java图片处了解决方案
java图片处理解决方案
项目需要调整图片服务器的解决方案,这次调整使用fastdfs存储小文件,也就是图片,因为现在还没有fastdfs的.net版的客服端,所以理所当然把处理图片放到了java这块,使用java来处理图片并且上传到fastdfs上。
之前还真没用java整过图片,因为一般没这个需求,现在的需求是要根据前台传过来的尺寸进行图片的缩略,自适应缩放,留白,加水印操作。
一开始我使用jdk自带的一套图片处理库来处理图片,也就是sun的JPEGCodec,测试发现它会把所有的图片全部转换成jpeg格式,也就是说把bmp,gif,png这种格式的图片全部转换成了jpeg格式,而且对于gif动画图片缩放就只能对第一帧缩放,所以对于gif这种的的缩放完之后就“不动了”。
之后使用Graphics2D+ImageIO的方式,先判断图片的格式,然后缩放的时候强制的把图片格式作为参数传给ImageIO来处理,
但是对于gif动画图片缩放也只对第一帧缩放,所以对于gif这种的的缩放完之后也是“不动了”。
最后在网上发现了一个架包 --gif4j ,它可以对gif动画图片进行缩放但是对于加水印和留白操作就无能为力了。
最后在做压力测试时发现,使用这种方式(java的jdk+gif4j),特别是对于大图的操作,大图我这边测试的是6~7M的图片,发现非常非常耗cpu和内存,当然程序已经优化过的前提下测试,图片都以流的方式进行操作。但是这种cpu和内存的消耗简直是开玩笑了,要是需要处理的图片一多,每秒过百的请求服务器就得卡死,而且这种方式处理的图片质量不是特别高。
在这种方案放弃之后,发现了ImageMagick。
利用Java 的JNI(java本地调用),依赖操作系统提供的功能, 操作批量、大图片,这种方式效率比较高。
然后当然是开搞,ImageMagick 在windows和linux下的配置稍有不同,详细情况可以参考:http://www.imagemagick.org/script/index.php
下面贴出使用JMagick调用Imagemagick进行缩略的代码。
这里注意,使用完之后要释放资源。
否则会很伤,你懂的。
加水印代码:
代码都整完之后,进行压力测试,问题出来了,java调用JNI的方式存在内存隐患,至于原因,可以网上查查。现在的情况就是如果可以10天半个月重启下服务,那没问题,但是如果长时间的跑着服务,它会把内存耗尽,然后死掉。
很郁闷,是吧,我也很郁闷。但我想做就做个NB点的吧,然后发现了GraphicsMagick+im4java这种方式。
具体的不介绍了,网上资料很少,例子代码更少,我在这里贴几段,仅供参考。
缩放代码:
加水印:
我大功告成了!
项目需要调整图片服务器的解决方案,这次调整使用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); } }
我大功告成了!
1 楼
andylo25
2011-06-08
“具体的不介绍了,网上资料很少,例子代码更少”
不知道这个是什么意思?
是因为资料少,物以稀为贵,表示你很NB,所以不介绍呢?还是写错了?
不知道这个是什么意思?
是因为资料少,物以稀为贵,表示你很NB,所以不介绍呢?还是写错了?