`
java_mzd
  • 浏览: 580641 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

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

阅读更多

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

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

 

 

还有

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

 

分享到:
评论

相关推荐

    Java范例开发大全 (源程序)

     实例92 字母大小写转换 120  实例93 去除多余的空白 120  实例94 原始数组类型的String形式 121  实例95 Java合法标识符 122  实例96 显示一周各星期的名称 123  实例97 构造空心方框 124  实例98 这...

    java范例开发大全(pdf&源码)

    实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一周各星期的名称 123 实例97 构造空心方框 124 实例98 这一天是星期几 125 实例...

    java范例开发大全源代码

     实例92 字母大小写转换 120  实例93 去除多余的空白 120  实例94 原始数组类型的String形式 121  实例95 Java合法标识符 122  实例96 显示一周各星期的名称 123  实例97 构造空心方框 124  实例...

    java范例开发大全

    实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一周各星期的名称 123 实例97 构造空心方框 124 实例98 这一天是星期几 125 实例...

    Java范例开发大全(全书源程序)

    实例92 字母大小写转换 120 实例93 去除多余的空白 120 实例94 原始数组类型的String形式 121 实例95 Java合法标识符 122 实例96 显示一周各星期的名称 123 实例97 构造空心方框 124 实例98 这一天是星期几 ...

    1345个易语言模块

    公历转换为农历.ec 六六自用 模块.ec 六十四卦相.ec 关于窗口.ec 关于菜单的一些修改操作.ec 关机管理.ec 关联.ec 关联 数据库和新表格.ec 关联文件.ec 关联程序.ec 关闭托盘图标.ec 关闭窗口或进程.ec 内存专用模块...

    1350多个精品易语言模块

    公历转换为农历.ec 六六自用 模块.ec 六十四卦相.ec 关于窗口.ec 关于菜单的一些修改操作.ec 关机管理.ec 关联.ec 关联 数据库和新表格.ec 关联文件.ec 关联程序.ec 关闭托盘图标.ec 关闭窗口或进程.ec 内存专用模块...

Global site tag (gtag.js) - Google Analytics