我们都把一个图片信息转换成字符数组
只需要调用ImageIO中的write方法
设置好Image对象,输出格式Format 输出目标--output
把其中的输出目标output用我们需要的ByteArryOutputStream来实现就可以完成了
ImageIO默认的write方法
能支持各种类型的Format
但是当我们需要限制输出的文件大小的时候
ImageIO中实现的write方法就有些力不从心了
在我们的远程监控系统实施过程中
如果要用UDP组播来实现屏幕的传送
又必须把BufferedImage变为64KB一下的一个文件
所以
我们就必须要想办法把一个图片按质量压缩
并且用byte[]的形式来保存压缩好的数据
以便在网络中传输
昨天百度了又google
google了又百度
忙活了半天
还是没找到合适的相关方法
(再一次体现自己查资料能力的问题,下篇日志总结资料搜集的方法)
最后好不容易进了个英文网站
勉强看懂了作者的意思
现在把自己实现的代码及思路小结一下
首先,如前所述
ImageIO虽然能支持选定格式的输出
但是不能自己设置质量
上网查了有关图片格式相关信息后
得到
gif是目前无损压缩做的比较好的
jpeg能支持多种格式程度的压缩方式
压缩效果较好
昨天的测试代码已经表明了
一个截屏保存为GIF的时候
打包成字符数组需要大概2S,图片大小大概为100KB
ImageIO默认的Jpg格式 压缩大概0.5S 图片大小大概200KB
现在我们开始实现按给定压缩质量压缩文件成JPEG的代码
/** * * 自己设置压缩质量来把图片压缩成byte[] * @param image * 压缩源图片 * @param quality * 压缩质量,在0-1之间, * @return 返回的字节数组 */ private byte[] bufferedImageTobytes(Image image, float quality) { System.out.println(quality+"质量开始打包"+getCurrentTime()); //如果图片空,返回空 if (image == null) { return null; } // 重新设定图片的宽和高 BufferedImage bImage = new BufferedImage(image.getWidth(null), image .getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics bg = bImage.getGraphics(); bg.drawImage(image, 0, 0, null); bg.dispose(); // 得到指定Format图片的writer Iterator<ImageWriter> iter = ImageIO .getImageWritersByFormatName("jpeg");// 得到迭代器 ImageWriter writer = (ImageWriter) iter.next(); // 得到writer // 得到指定writer的输出参数设置(ImageWriteParam ) ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩 iwp.setCompressionQuality(quality); // 设置压缩质量参数 iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED ); ColorModel colorModel = ColorModel.getRGBdefault(); // 指定压缩时使用的色彩模式 iwp.setDestinationType( new javax.imageio.ImageTypeSpecifier( colorModel, colorModel.createCompatibleSampleModel(16, 16)) ); // 开始打包图片,写入byte[] ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 取得内存输出流 IIOImage iIamge = new IIOImage(bImage, null, null); try { //此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput //通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream)); writer.write(null, iIamge, iwp); } catch (IOException e) { System.out.println("write errro"); e.printStackTrace(); } System.out.println(quality+"质量完成打包-----"+getCurrentTime()+"------size------"+byteArrayOutputStream.toByteArray().length); return byteArrayOutputStream.toByteArray(); }
代码挺容易看懂的,难点主要在
//通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
为了从byteArrayOutputStream到ImageOutputStream画了我将近2个小时。。
代码出来了
现在我们开始用测试结果来展示各种新式图片的压缩时间、压缩后大小
压缩后图片内容
测试代码如下
package cn.mzd.newIM.test; import java.awt.AWTException; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; public class ImageSizeTest { /** * @param args * @throws AWTException */ public void getImageSize() throws AWTException { java.awt.Robot rb = new java.awt.Robot(); Dimension d = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); Rectangle rt = new Rectangle(0, 0, (int) d.getWidth(), (int) d .getHeight()); for (int i = 0; i < 1000; i++) { BufferedImage image = rb.createScreenCapture(rt); bufferedImageTobytes(image,"gif"); bufferedImageTobytes(image,"jpeg"); bufferedImageTobytes(image,(float) 0.3); } } /** * 用Format对应格式中ImageIO默认参数把IMAGE打包成BYTE[] * @param image * @return */ private byte[] bufferedImageTobytes(BufferedImage image,String format) { System.out.println(format+"格式开始打包"+getCurrentTime()); BufferedImage bImage = new BufferedImage(image.getWidth(null), image .getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics bg = bImage.getGraphics(); bg.drawImage(image, 0, 0, null); bg.dispose(); ByteArrayOutputStream out = new ByteArrayOutputStream(); try { ImageIO.write(bImage, format, out); } catch (IOException e) { e.printStackTrace(); } System.out.println(format+"格式完成打包-----"+getCurrentTime()+"----lenth------"+out.toByteArray().length); return out.toByteArray(); } /** * * 自己设置压缩质量来把图片压缩成byte[] * @param image * 压缩源图片 * @param quality * 压缩质量,在0-1之间, * @return 返回的字节数组 */ private byte[] bufferedImageTobytes(Image image, float quality) { System.out.println("jpeg"+quality+"质量开始打包"+getCurrentTime()); //如果图片空,返回空 if (image == null) { return null; } // 重新设定图片的宽和高 BufferedImage bImage = new BufferedImage(image.getWidth(null), image .getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics bg = bImage.getGraphics(); bg.drawImage(image, 0, 0, null); bg.dispose(); // 得到指定Format图片的writer Iterator<ImageWriter> iter = ImageIO .getImageWritersByFormatName("jpeg");// 得到迭代器 ImageWriter writer = (ImageWriter) iter.next(); // 得到writer // 得到指定writer的输出参数设置(ImageWriteParam ) ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩 iwp.setCompressionQuality(quality); // 设置压缩质量参数 iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED ); ColorModel colorModel = ColorModel.getRGBdefault(); // 指定压缩时使用的色彩模式 iwp.setDestinationType( new javax.imageio.ImageTypeSpecifier( colorModel, colorModel.createCompatibleSampleModel(16, 16)) ); // 开始打包图片,写入byte[] ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 取得内存输出流 IIOImage iIamge = new IIOImage(bImage, null, null); try { //此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput //通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream)); writer.write(null, iIamge, iwp); } catch (IOException e) { System.out.println("write errro"); e.printStackTrace(); } System.out.println("jpeg"+quality+"质量完成打包-----"+getCurrentTime()+"----lenth----"+byteArrayOutputStream.toByteArray().length); return byteArrayOutputStream.toByteArray(); } /** * 自己定义格式,得到当前系统时间 * @return */ private String getCurrentTime() { Calendar c = new GregorianCalendar(); int hour = c.get(Calendar.HOUR_OF_DAY); int min = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); int millsecond = c.get(Calendar.MILLISECOND); String time = hour + "点" + min + "分" + second + "秒" + millsecond; return time; } public static void main(String args[]) throws Exception { ImageSizeTest test = new ImageSizeTest(); test.getImageSize(); } }
gif格式开始打包22点44分2秒776 gif格式完成打包-----22点44分4秒219----lenth------88597 jpeg格式开始打包22点44分4秒220 jpeg格式完成打包-----22点44分4秒579----lenth------193017 jpeg0.03质量开始打包22点44分4秒581 jpeg0.03质量完成打包-----22点44分4秒860----lenth----55348 gif格式开始打包22点44分5秒19 gif格式完成打包-----22点44分6秒941----lenth------93604 jpeg格式开始打包22点44分6秒941 jpeg格式完成打包-----22点44分7秒451----lenth------210974 jpeg0.03质量开始打包22点44分7秒453 jpeg0.03质量完成打包-----22点44分7秒722----lenth----58728 gif格式开始打包22点44分7秒906 gif格式完成打包-----22点44分9秒234----lenth------120938 jpeg格式开始打包22点44分9秒234 jpeg格式完成打包-----22点44分9秒545----lenth------214277 jpeg0.03质量开始打包22点44分9秒546 jpeg0.03质量完成打包-----22点44分9秒801----lenth----57217 gif格式开始打包22点44分9秒927 gif格式完成打包-----22点44分11秒395----lenth------133633 jpeg格式开始打包22点44分11秒397 jpeg格式完成打包-----22点44分11秒884----lenth------262952 jpeg0.03质量开始打包22点44分11秒885 jpeg0.03质量完成打包-----22点44分12秒286----lenth----65639 gif格式开始打包22点44分12秒458 gif格式完成打包-----22点44分14秒321----lenth------135386 jpeg格式开始打包22点44分14秒322 jpeg格式完成打包-----22点44分14秒823----lenth------262394 jpeg0.03质量开始打包22点44分14秒824 jpeg0.03质量完成打包-----22点44分15秒233----lenth----65774 gif格式开始打包22点44分15秒432 gif格式完成打包-----22点44分17秒297----lenth------137548 jpeg格式开始打包22点44分17秒299 jpeg格式完成打包-----22点44分17秒786----lenth------272242 jpeg0.03质量开始打包22点44分17秒787 jpeg0.03质量完成打包-----22点44分18秒192----lenth----67039 gif格式开始打包22点44分18秒367 gif格式完成打包-----22点44分20秒201----lenth------138447 jpeg格式开始打包22点44分20秒201 jpeg格式完成打包-----22点44分20秒732----lenth------272076 jpeg0.03质量开始打包22点44分20秒733 jpeg0.03质量完成打包-----22点44分21秒134----lenth----66780 gif格式开始打包22点44分21秒277 gif格式完成打包-----22点44分22秒453----lenth------98671 jpeg格式开始打包22点44分22秒453 jpeg格式完成打包-----22点44分22秒762----lenth------227669 jpeg0.03质量开始打包22点44分22秒764 jpeg0.03质量完成打包-----22点44分23秒28----lenth----61676
jpeg压缩只有当质量为0.03时,才能达到满足效果的小于64KB
而0.03是什么概念呢?
压缩质量是从0-1的一个数,0表示最小
而0。03………………………………………………
图片几乎看不清楚。。。。
应该是不符合我们的传输要求的
所以,本次试验
还是以失败告终
从本次试验中
学到的东西
1.其实API没那么难看懂 其实英文网站可以读懂
2.教会了我查资料应该怎么下手,如何确定自己需要的到底是什么
3.读了很多API 也算是个成长吧。。
恩
还有
明白了图片格式,储存,压缩大概是怎么回事