我们都把一个图片信息转换成字符数组
只需要调用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 也算是个成长吧。。
恩
还有
明白了图片格式,储存,压缩大概是怎么回事