java图片处理解决方案 _PHP_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > PHP > java图片处理解决方案

java图片处理解决方案

 2011/11/4 8:11:46  zkl_1987  http://zkl-1987.iteye.com  我要评论(0)
  • 摘要:项目需要调整图片服务器的解决方案,这次调整使用fastdfs存储小文件,也就是图片,因为现在还没有fastdfs的.net版的客服端,所以理所当然把处理图片放到了java这块,使用java来处理图片并且上传到fastdfs上。之前还真没用java整过图片,因为一般没这个需求,现在的需求是要根据前台传过来的尺寸进行图片的缩略,自适应缩放,留白,加水印操作。一开始我使用jdk自带的一套图片处理库来处理图片,也就是sun的JPEGCodec,测试发现它会把所有的图片全部转换成jpeg格式
  • 标签:解决方案 解决 图片 Java 理解
项目需要调整图片服务器的解决方案,这次调整使用fastdfs存储小文件,也就是图片,因为现在还没有fastdfs的.net版的客服端,所以理所当然把处理图片放到了java这块,使用java来处理图片并且上传到fastdfs上。

之前还真没用java整过图片,因为一般没这个需求,现在的需求是要根据前台传过来的尺寸进行图片的缩略,自适应缩放,留白,加水印操作。

一开始我使用jdk自带的一套图片处理库来处理图片,也就是sun的JPEGCodec,测试发现它会把所有的图片全部转换成jpeg格式,也就是说把bmp,gif,png这种格式的图片全部转换成了jpeg格式,而且对于gif动画图片缩放就只能对第一帧缩放,所以对于gif这种的的缩放完之后就“不动了”。

之后使用Graphics2D+ImageIO的方式,先判断图片的格式,然后缩放的时候强制的把图片格式作为参数传给ImageIO来处理,
ImageIO.write(image, pic_type, out);


但是对于gif动画图片缩放也只对第一帧缩放,所以对于gif这种的的缩放完之后也是“不动了”。
最后在网上发现了一个架包 --gif4j ,它可以对gif动画图片进行缩放但是对于加水印和留白操作就无能为力了。

最后在做压力测试时发现,使用这种方式(java的jdk+gif4j),特别是对于大图的操作,大图我这边测试的是6~7M的图片,发现非常非常耗cpu和内存,当然程序已经优化过的前提下测试,图片都以流的方式进行操作。但是这种cpu和内存的消耗简直是开玩笑了,要是需要处理的图片一多,每秒过百的请求服务器就得卡死,而且这种方式处理的图片质量不是特别高。


在这种方案放弃之后,发现了ImageMagick。
ImageMagick (TM) 是一个免费的创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附加到图片伸展旋转。ImageMagick的大多数功能的使用都来源于命令行工具。它还支持以下程序语言: Perl, C, C++, Python, PHP, Ruby, Java;现成的ImageMagick接口(PerlMagick, Magick++, PythonMagick, MagickWand for PHP, RubyMagick, and JMagick)是可利用的。


利用Java 的JNI(java本地调用),依赖操作系统提供的功能, 操作批量、大图片,这种方式效率比较高。
然后当然是开搞,ImageMagick 在windows和linux下的配置稍有不同,详细情况可以参考:http://www.imagemagick.org/script/index.php


下面贴出使用JMagick调用Imagemagick进行缩略的代码。


public void resize1(String src, String dsec, int width, int height,
			int quality) {
		ImageInfo info = null;
		MagickImage image = null;
		Dimension imageDim = null;
		MagickImage scaled = null;
		try {
			info = new ImageInfo(src);
			info.setQuality(quality);
			image = new MagickImage(info);
			imageDim = image.getDimension();

			int srcW = imageDim.width;
			int srcH = imageDim.height;
			
			int[] i = PicUtil.getWandH(srcW, srcH, width, height, 1);

			scaled = image.scaleImage(i[0], i[1]);
			scaled.setFileName(dsec);
			scaled.writeImage(info);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (scaled != null) {
				scaled.destroyImages();
			}
			if (image != null) {
				image.destroyImages();
			}
		}
	}



这里注意,使用完之后要释放资源。

if (scaled != null) {
				scaled.destroyImages();
			}
			if (image != null) {
				image.destroyImages();
			}


否则会很伤,你懂的。



加水印代码:
	public void addWater(String src, String src_biao, String dsrc,
			int position, int quality) {
		ImageInfo info = null;
		ImageInfo logo_info = null;
		MagickImage image = null;
		MagickImage logo_image = null;
		Dimension imageDim = null;
		Dimension logo_imageDim = null;
		// MagickImage compositeimage = null;
		try {
			info = new ImageInfo(src);
			info.setQuality(quality);
			image = new MagickImage(info);
			imageDim = image.getDimension();
			logo_info = new ImageInfo(src_biao);
			logo_image = new MagickImage(logo_info);
			logo_imageDim = logo_image.getDimension();

			int[] ii = WaterPosition.position(position, imageDim.width,
					logo_imageDim.width, imageDim.height, logo_imageDim.height);
			image.compositeImage(CompositeOperator.AtopCompositeOp, logo_image,
					ii[0], ii[1]);
			image.setFileName(dsrc);
			image.writeImage(info);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (logo_image != null) {
				logo_image.destroyImages();
			}
			if (image != null) {
				image.destroyImages();
			}
		}
	}




代码都整完之后,进行压力测试,问题出来了,java调用JNI的方式存在内存隐患,至于原因,可以网上查查。现在的情况就是如果可以10天半个月重启下服务,那没问题,但是如果长时间的跑着服务,它会把内存耗尽,然后死掉。

很郁闷,是吧,我也很郁闷。但我想做就做个NB点的吧,然后发现了GraphicsMagick+im4java这种方式。
具体的不介绍了,网上资料很少,例子代码更少,我在这里贴几段,仅供参考。



缩放代码:
	public void resize1(String src, String dsec, int o_width, int o_heigh,
			int width, int height, double quality) {
		int[] i = PicUtil.getWandH(o_width, o_heigh, width, height, 1);
		ConvertCmd cmd = new ConvertCmd(true);
		IMOperation op = new IMOperation();
		op.addImage(src);
		op.scale(i[0], i[1]);
		op.quality(quality);
		op.addImage(dsec);
		try {
			cmd.run(op);
		} catch (Exception e) {
			log.error(e,e);
		}
	}





加水印:

	public void addWater(String src, String src_biao, String dsrc,
			int position, double quality) {
		CompositeCmd cmd = new CompositeCmd(true);
		IMOperation op = new IMOperation();
		op.gravity(WaterPosition.positionMagick(position));
		op.quality(quality);
		op.addImage();
		op.addImage();
		op.addImage();
		try {
			cmd.run(op, src_biao, src, dsrc);
		} catch (Exception e) {
			log.error(e,e);
		}
	}


我大功告成了!
发表评论
用户名: 匿名