图像按质量压缩、转换为字符数组小结

我们都把一个图片信息转换成字符数组

只需要调用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 也算是个成长吧。。

 

 

还有

明白了图片格式,储存,压缩大概是怎么回事

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值