现在做的网站需要保存用户上传的图片,同时需要进行压缩和图片切割等特殊效果的处理。
一开始我们用的是JMagick+ ImageMagick处理用户上传的图片,但是存在一个非常严重的问题,Tomcat在跑了大概10天左右后会crash掉,异常内容为:
- magick.MagickException: Unable to retrieve handle
从表象看,应该是没有释放ImageMagick的句柄导致的,查找API后发现程序中没有调用
- magick.MagickImage.destroyImages() Called by finalize to deallocate the image handle.
在程序加上本方法,情况有所改善,大概在40天左右后出现了一次tomcat进程crash。
似乎并没有从本质上找到问题的根本。。。
在JMagick的邮件列表中找到一份我认为有价值的邮件,http://sourceforge.net/mailarchive/message.php?msg_name=20cf28cd1002231148s33c99843q875f59906dd32b8b%40mail.gmail.com
里面讲到了JMagick作为应用服务的缺点,并建议可以使用IM4JAVA:
- The "JNI hazard" here is that if something you use (f.ex libtiff for reading
- TIFF files) has a memory bug then it can make your whole JVM crash. Thats of
- course frustrating and therefore its great to have im4java around, which
- starts IM as an external process, so JVM crashes are avoided.
- * *
- Coolest thing would be if JMagick and im4java could have the same API so it
- was easy to switch depending on luckyness. Ive asked the author of im4java
- to attemt to be as compatible as possible, but as im4java is very much
- different internally its limited how much can be done in that direction.
- If you don't like the risk, stick to im4java. If your want optimal
- performance give JMagick a try.
- And, its not JMagick that is buggy, its what it depends on (hereunder IM)
- that is not always (memory) bug free on long running processes.
- I also have never seen a mismatch between JMagick binary and ImageMagick
- binaries leading to crashes.
所以我把思路转向了IM4Java。
IM4Java的官网 http://im4java.sourceforge.net/index.html 。
在 Developer's Guide 中提到im4java支持ImageMagick和GraphicsMagick。GraphicsMagick是ImageMagick的一个分支,相对于ImageMagick而言,TA处理速度更快,消耗资源更少,并且大的图片处理网站,如 Flickr andEtsy 已经在使用TA了。
下载GraphicsMagick的Q8版本(还有Q16、Q32的,版本见的区别可以查看ImageMagick的官网,大致意思是每像素用多少bit来存储信息,16、32要比8消耗更多的内存^_^)。
下面这段话是在GraphicsMagick的邮件列表中找到的:
- > I've got question about IM Q16 & Q8. What's a difference between that two versions?
- I know, that Q16 version takes 2 times more memory than Q8.
- But is that so great precision in algorithm is needed in converting jpegs, gif or pngs
- (I need IM for converting that types of formats)
- & JPEG and GIF only have 8-bit versions, so there will almost certainly be no benefit to using Q16.
- It is possible to have 16-bit PNGs, but if you have to ask, you probably don't have to worry about it
安装GraphicsMagick和IM4Java非常简单,按照官网做就ok了,下面是一个简单的例子:
- /**
- * 先缩放,后居中切割图片
- * @param srcPath 源图路径
- * @param desPath 目标图保存路径
- * @param rectw 待切割在宽度
- * @param recth 待切割在高度
- * @throws IM4JavaException
- * @throws InterruptedException
- * @throws IOException
- */
- public static void cropImageCenter(String srcPath, String desPath, int rectw, int recth) throws IOException, InterruptedException, IM4JavaException
- {
- IMOperation op = new IMOperation();
- op.addImage();
- op.resize(rectw, recth, '^').gravity("center").extent(rectw, recth);
- op.addImage();
- ConvertCmd convert = new ConvertCmd(true);
- //convert.createScript("e:\\test\\myscript.sh",op);
- convert.run(op, srcPath, desPath);
- }
我的头像就是用这个方法压缩的,源图为:
原始尺寸为578*800,大小为68.8KB,处理后为180*180,大小为 6.15KB
在我的机器上使用LoadRunner进行了压力测试,并发10用户的情况下,每秒能处理11张左右的图片。
我的机器配置为:
Inter(R) Pentium(R) D CPU2.80GHz, 2.00GB 内存,迈拓 6V160E0 7200rpm
操作系统为 Windows server2003 Enterprise Edition Service Pack 2