做网站往往需要处理各种各样的图片,对于jdk自带的一套图片处理库,他的特点是稳定简单,但是对图片处理来说,性能确实很不咋的!
于是我转向了以C++处理为核心的java处理包—— JMagick+ ImageMagick 。jmagick是一个开源的API,利用JNI(Java Native Interface)技术实现了对ImageMagickAPI 的Java访问接口,因此也将比纯Java实现的图片操作函数在速度上要快。实地测试后发现,速度果然提高了不少,但是质量却大大下降了,在大量测试数据 下,每生成100张图片约会有5张图片生成出现错误,还会出现down机的情况。对于一个商业应用来说,这个是绝对不可以接受的,于是对jmagick的 研究暂放一段时间。
经过韩boss指导,我转向了 GraphicsMagick+im4java 的研究,输入关键词google一下,很容易就可以找到
http://javantsky.iteye.com/blog/747807
,这篇博客,文章介绍GraphicsMagick+im4java 性能高,运行稳定!
于是我开始了对GraphicsMagick+im4java实际研究:
个人感觉im4java就是graphicsmagick的外面包装了一层“纸”,一个java转换的命令行输出工具,其api也基本没有参考价值(有些 与实际不符的地方),GraphicsMagick+im4java的核心在于GraphicsMagick。
作为一个缩放+切割功能的实现,可以使用
- gm convert input.jpg -thumbnail 100x100^ -gravity center -extent 100x100 output.jpg
gm convert input.jpg -thumbnail 100x100^ -gravity center -extent 100x100 output.jpg
这条命令,经过测试发现,thumbnail命令的效率还不如原有java实现的效率,可能用它来实现这么简单的功能是高射炮打蚊子了,关于GraphicsMagick各项参数的使用的文章,网上实在是少之又少,于是只能靠自己了!
我找到了所有和缩放有关的命令,经过一一验证,最终选择了sample命令。相比最初的纯java实现,内存节省了约70%,CPU效率提高了约80%, 耗费时间约节省了72%,下面为我找到的所有缩放有关的GraphicsMagick命令的测试数据:
Graphics+im4java性能对比:
记录一(其中内存和CPU为观测数据):
原有java实现:
图片大小:2.5M(2592x1944)
内存:1185M(共)
CPU:170%(共)(按双核)
耗时:162,875ms/200张(线程池10)
输出图片大小:36.1K
thumbnail命令实现:
- gm convert input.jpg -thumbnail 600x600^ -gravity center -extent 600x600 output.jpg
gm convert input.jpg -thumbnail 600x600^ -gravity center -extent 600x600 output.jpg
图片大小:2.5M(2592x1944)
内存:150M/线程
CPU:9%/线程
耗时:193,423ms/200张(线程池10)
输出图片大小:78.5K
geometry命令实现:
- gm convert input.jpg -geometry 600x600^ -gravity center -extent 600x600 output.jpg
gm convert input.jpg -geometry 600x600^ -gravity center -extent 600x600 output.jpg
图片大小:2.5M(2592x1944)
内存:50M/线程
CPU:9%/线程
耗时:94,518ms/200张(线程池10)
输出图片大小:101.8K
resize命令实现:
- gm convert input.jpg -resize 600x600^ -gravity center -extent 600x600 output.jpg
gm convert input.jpg -resize 600x600^ -gravity center -extent 600x600 output.jpg
图片大小:2.5M(2592x1944)
内存:55M/线程
CPU:13%/线程
耗时:97,342ms/200张(线程池10)
输出图片大小:101.8K
sample命令实现:
- gm convert input.jpg -sample 600x600^ -gravity center -extent 600x600 output.jpg
gm convert input.jpg -sample 600x600^ -gravity center -extent 600x600 output.jpg
图片大小:2.5M(2592x1944)
内存:35M/线程
CPU:9%/线程
耗时:46,541ms/200张(线程池10)
输出图片大小:117.3K
sample(quality:50)
- gm convert input.jpg -sample 600x600^ -gravity center -extent 600x600 -quality 50 output.jpg
gm convert input.jpg -sample 600x600^ -gravity center -extent 600x600 -quality 50 output.jpg
图片大小:2.5M(2592x1944)
内存:40M/线程
CPU:16%/线程
耗时:68,839ms/200张(线程池10)
输出图片大小:47.2
scale命令实现:
- gm convert input.jpg -scale 600x600^ -gravity center -extent 600x600 output.jpg
gm convert input.jpg -scale 600x600^ -gravity center -extent 600x600 output.jpg
图片大小:2.5M(2592x1944)
内存:42M/线程
CPU:8%/线程
耗时:68,778ms/200张(线程池10)
输出图片大小:99.2K
在sample命令下,可以通过修改quality参数的值,来修改输出图片质量,改变输出图片大小。以下为我的测试数据:
记录二:
sample对比(无quality设置):
图片大小:2.5M(2592x1944)
内存:32(\)M/线程
CPU:9%/线程
耗时:46,659ms/200张(线程池10)
输出图片大小:117.3K
sample(quality:50)
图片大小:2.5M(2592x1944)
内存:28M/线程
CPU:9%/线程
耗时:40,549ms/200张(线程池10)
输出图片大小:48.8
sample(quality:60)
图片大小:2.5M(2592x1944)
内存:35M(\)/线程
CPU:8%(\)/线程
耗时:45,647ms/200张(线程池10)
输出图片大小:53.3
sample(quality:75)
图片大小:2.5M(2592x1944)
内存:30M(\)/线程
CPU:9%(\)/线程
耗时:45,719ms/200张(线程池10)
输出图片大小:65.6
sample(quality:85)
图片大小:2.5M(2592x1944)
内存:32M(\)/线程
CPU:8%(\)/线程
耗时:46,510ms/200张(线程池10)
输出图片大小:84.5
sample(quality:95)
图片大小:2.5M(2592x1944)
内存:34M(\)/线程
CPU:8%(\)/线程
耗时:47,650ms/200张(线程池10)
输出图片大小:156.0
sample(quality:100)
图片大小:2.5M(2592x1944)
内存:34M(\)/线程
CPU:11%(\)/线程
耗时:50,469ms/200张(线程池10)
输出图片大小:298.1
- ConvertCmd cvcmd = new ConvertCmd();
- Operation op = new Operation();
- op.addImage();
- op.addRawArgs( "-sample" , "600x600^" );
- op.addRawArgs( "-gravity" , "center" );
- op.addRawArgs( "-extent" , "600x600" );
- op.addRawArgs( "-quality" , "100" );
- op.addImage();
- cvcmd.run(op, srcImg, desImg);
ConvertCmd cvcmd = new ConvertCmd(); Operation op = new Operation(); op.addImage(); op.addRawArgs("-sample", "600x600^"); op.addRawArgs("-gravity", "center"); op.addRawArgs("-extent", "600x600"); op.addRawArgs("-quality", "100"); op.addImage(); cvcmd.run(op, srcImg, desImg);
这是我从文小猫童鞋那里找到的一张她自制的美食图片,源图像文件像素为1944x2592,处理后为600x600;
由于个人能力有限,欢迎大家指出不足,提出更好的解决方案!
im4java官方网站:
http://im4java.sourceforge.net/index.html
im4java的api:
http://im4java.sourceforge.net/api/
graphicsmagick的官方网站:
http://www.graphicsmagick.org/index.html
graphicsmagick的命令行参数解析:
http://www.graphicsmagick.org/utilities.html