ImageMagick 与 JMagick去除水印

ImageMagick 官网 http://www.imagemagick.org/script/index.php

JMagick 官网 http://www.jmagick.org/index.html (官网的源码svn:https://jmagick.svn.sourceforge.net/svnroot/jmagick)

1.  简介

    ImageMagick 是一个功能很强的图片处理程序。可应用在多种操作系统平台上。

Jmagick通过jni操作ImageMagick。

 

     Javashop支持通过ImageMagick生成图片缩略图,但需要系统中配置好 ImageMagick。

 

2.  安装环境要求

确认已经安装了zlib、freetype、libpng和jpeg-6b等lib的开发包,可以用rpm-aq查询,例如,你应该检查是否已经安装如下rpm包:

rpm –qa |grep libpng

rpm –qa |grep libpng-devel

rpm –qa |grep libjpeg

rpm –qa |grep gd-devel

 

如果你希望支持tiff格式,还应该检查

rpm –qa |grep libtiff

 

3.  安装ImageMagick包

tar xzvf ImageMagick- 6.4.0.tar.gz

 

./configure --prefix=/opt/ImageMagick --enable-share--enable-static

 

Make

 

make install

 

使用convert 看看是否可以转换文件

  测试:convert-geometry 600x200 star.jpg star_small.gif

4.  安装JMagick包

tar xzvf jmagick-6.4.0.tar.gz

 

./configure --prefix=/opt/JMagick--with-magick-home=/opt/ImageMagick

--enable-share --enable-static --with-java-home=/usr/java/jdk6

 

make all

make install

5.  配置环境变量。

vi /etc/profile

 

加入:

export PATH=$PATH:/opt/ImageMagick/bin

export LD_LIBRARY_PATH=:/opt/JMagick/lib:/opt/ImageMagick/lib

exportDYLD_LIBRARY_PATH=:/opt/JMagick/lib:/opt/ImageMagick/lib

export CLASSPATH=$CLASSPATH:/opt/JMagick/lib

 

 

如果要在Tomcat中运行,需要再运行时加入参数: -Djmagick.systemclassloader=no

 

或者在程序中写入:System.setProperty("jmagick.systemclassloader","no")。


=========================================================================

Jmagick的安装和使用

ImageMagick 是一个用来创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线, 多边形,椭圆,曲线,附加到图片伸展旋转。ImageMagick是免费软件:全部源码开放,可以自由使用,复制,修改,发布。支持大多数的操作系统。

1.对用户上传图片进行缩放 
    对于用户自己上传的图片不能简单的 用css限制大小,因为这样每次加载图片时候还是会加载整幅大图。占用多余的宽带,并且影响页面加载速度。应该根据实际显示需要进行缩放。比如我想要用户 相册里的图片大小不能超过500x300: 
用ImageMagick处理起来很简单
convert -resize "500x300>" input.jpg  output.jpg #如果图片比500x300小就保持原样,以防小图片被放大失真。

2.生成不同比例缩略图
    一般相册等应用,都会提供缩略图和预览图,这些缩略图同样不能简单的用css来限制大小,要为每个图片生成不同比例的预览图。

3.去除多余信息
    Exif信息是数码相机在拍摄过程中采集的一系列信息,这些信息放置在我们熟知的jpg文件的头部,也就是说Exif信息是镶嵌在JPEG图像文件格式内的一组拍摄参数,主要包括摄影时的光圈、快门、ISO、日期时间等各种与当时摄影条件相关的讯息,相机品牌型号,色彩编码,拍摄时录制的声音以及全球定位系统(GPS)等信息。简单的说,它就好像是傻瓜相机的日期打印功能一样,只不过Exif信息所记录的资讯更为详尽和完备。不过,具有Exif信息的 JPEG图像文件要比普通的JPEG文件略大一点。还有就是像PS这种软件处理过的图片会有“program comments”。如果不是专业的摄影类网站,这些信息是没有用的,可以去掉:
convert -strip input.jpg output.jpg

4.调节压缩比
    大多时候,我们的网站并不需要那么清晰的图片,适量调节JPG图片的压缩比会减少图片大小,肉眼并不会分辨出质量被压缩后的图片。通常75%是最佳比例。
convert -quality 75% input.jpg output.jpg

上面几个步骤可以一次搞定:
convert -resize "500x300" -strip -quality 75% input.jpg output.jpg

上面说的都是针对JPG格式的处理方式,下面说一下BMP,GIF,PNG等格式的处理。

对于BMP直接转成JPG就可以了。再按照上面的方式处理。

而GIF和PNG貌似有些特殊。GIF的一些特性(动画效果,透明等)是 JPG没有的,可以根据实际情况选择转或不转,如果转换成jpg,取第一帧只需要这样:
convert -format jpg input.gif input.jpg

PNG也可以通过减少PNG图片color数量的办法达到压缩的目的。但是这种办法压缩出来的图像可以明显看出来失真,而且呈锯齿状。

对于真实世界的PNG图片(通常指照片),一般先转换成JPG,再通过上面的办法来压缩。

但是要注意一点,透明或半透明的PNG图片在转换成JPG时透明部分会变成黑色。。。建议做用户头像时候不要转成JPG。。很难看~~~
本人头像就是深受毒害。。

关于图片扩展名

发现大部分网站喜欢把用户上传的图片(头像,相册等)都统一转成特定格式(一般都是 jpg)。这样做的潜在弊端就是在用像ImageMagick这样的软件处理的时候会根据扩展名做隐式格式转换。
个人觉得在保存图片的时候不加扩展名处理起来更灵活一些。  现在介绍使用Jmagick的使用,可以生成质量很好的缩略图,当然还有其 他很多图像处理的方法。

   首先jmagick(http://www.yeo.id.au/jmagick/)是ImageMagick(http: //www.imagemagick.org/)的java 应用的接口。所以要先安装ImageMagick应用程序,你的java应用才能使用,在主页上你可以轻松找到下载的链接。

   1。下载jmagick,imagemagick

   2.安装ImageMagick,网站上有安装方法(windows,unnix),我只在win上做了安装,安装以后把安装目录下所有的dll文件 copy到windows/system32/目录下。

   3。下载的jmagick包含jmagick.jar,jmagick.dll文件,jmagick.dll需要copy到 windows/system32/目录下。

   4。web应用如果部署到tomcat下,那么最好在catalina.bat文件中改变如下设置

set JAVA_OPTS=%JAVA_OPTS% -Xms256M -Xmx768M -XX:MaxPermSize=128M -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="${catalina.base}\conf\logging.properties"

   避免heap溢出的问题,参数看你自己的机器而定。( -Xms256M -Xmx768M -XX:MaxPermSize=128M )

   5。还要注意如果部署到web应用,你在使用的class里面需要

      System.setProperty("jmagick.systemclassloader","no");

     要不然会报出UnsatisfiedLinkError: no JMagick in java.library.path.

     实例如下:


public void resize(int w, int h) throws IOException {

        try {
                // Resize
          System.setProperty("jmagick.systemclassloader","no");
                ImageInfo info = new ImageInfo(sourceFileName);
                MagickImage image = new MagickImage(info);
                MagickImage scaled = image.scaleImage(w, h);//小图片文件的大小.
                scaled.setFileName(destFile);
                scaled.writeImage(info);

              }  catch(MagickApiException ex) {
                      System.out.println(ex);

              }  catch(MagickException ex) {
                      System.out.println(ex);
              }
    }



一些基本使用方法的代码,具体大家可以参考官方给的源码,那里比较详细:


 
 
  1. package org.wsr.util;
  2. import java.awt.Dimension;
  3. import java.awt.Point;
  4. import java.awt.Rectangle;
  5. import java.io.File;
  6. import magick.CompositeOperator;
  7. import magick.CompressionType;
  8. import magick.DrawInfo;
  9. import magick.ImageInfo;
  10. import magick.MagickException;
  11. import magick.MagickImage;
  12. import magick.PixelPacket;
  13. import magick.PreviewType;
  14. public class JMagicjWrapper {
  15. public static void main(String[] args) throws MagickException{
  16. //test for function imageResize
  17. // JMagicjWrapper.imageResize("pics.jpg", "reSize20x30.png", 20, 30);
  18. // JMagicjWrapper.imageResize("pics.jpg", "reSize250x200.jpeg", 250, 200);
  19. // JMagicjWrapper.imageResize("pics.jpg", "reSize50x50.jpg", 50, 50);
  20. // JMagicjWrapper.imageResize("pics.jpg", "reSize120x120.bmp", 120, 120);
  21. // JMagicjWrapper.imageResize("pics.jpg", "reSize.tif", 20, 30);//not create file
  22. //
  23. //test for function createWaterPrintByImg
  24. JMagicjWrapper.createWaterPrintByImg( "f://1.jpg", "f://4.jpg", "f://watermark.gif", new Point( 0, 0));
  25. //JMagicjWrapper.imageResize("wpl.gif", "logo250x200.gif", 250, 200);
  26. //Because file "wpl.gif" may not be release, the later function cause a error, can not open file handle.
  27. //JMagicjWrapper.createWaterPrintByImg("pics.jpg", "wpl.gif", "logoFull.jpg", new Point(1680,1050));//not create file
  28. //JMagicjWrapper.createWaterPrintByImg("pics.jpg", "wpl.gif", "logoExt.jpg", new Point(2000,1000));//not create file
  29. //test for function createWaterPrintByText
  30. //This function can not handle Chinese Character, I'll continue to takle the issue
  31. //JMagicjWrapper.createWaterPrintByText("pics1.jpg", "wpt.gif", "For Test", new Point(300,300), 100);
  32. }
  33. private static final String[] Type = {
  34. ".JPG",
  35. ".JPEG",
  36. ".BMP",
  37. ".GIF",
  38. ".PNG"
  39. };
  40. public static boolean checkType(String path){
  41. for ( int i = 0; i < Type.length; i++) {
  42. if (path.toUpperCase().endsWith(Type[i])) {
  43. return true;
  44. } else {
  45. continue;
  46. }
  47. }
  48. return false;
  49. }
  50. /**改变图片大小
  51. * @param filePath 原图片位置
  52. * toPath 新图片位置
  53. * width 新图片的宽度
  54. * height 新图片的高度
  55. * @return
  56. * @throw
  57. * @author sulliy@sina.com 2010-8-11
  58. */
  59. public static void imageResize(String filePath, String toPath, int width, int height)
  60. throws MagickException {
  61. ImageInfo info = null;
  62. MagickImage image = null;
  63. Dimension imageDim = null;
  64. MagickImage scaled = null;
  65. if (!checkType(filePath) || !checkType(toPath)) {
  66. return;
  67. }
  68. try {
  69. info = new ImageInfo();
  70. image = new MagickImage(info);
  71. imageDim = image.getDimension();
  72. if (width <= 0 || height <= 0) {
  73. height = 120;
  74. width = 120;
  75. }
  76. scaled = image.scaleImage(width, height);
  77. scaled.setFileName(toPath);
  78. scaled.writeImage(info);
  79. } finally {
  80. if (scaled != null) {
  81. scaled.destroyImages();
  82. }
  83. }
  84. }
  85. /**创建图片水印
  86. * @param filePath 源文件路径
  87. * toImg 生成文件位置
  88. * logoPath logo路径
  89. * pos logo在源图片中的相对位置,以像素点为单位
  90. * @return
  91. * @throw MagickException
  92. * @author sulliy@sina.com 2010-8-11
  93. */
  94. public static void createWaterPrintByImg(String filePath, String toImg,
  95. String logoPath, Point pos) throws MagickException {
  96. if (!checkType(filePath) || !checkType(toImg) || !checkType(logoPath)) {
  97. return;
  98. }
  99. ImageInfo info = new ImageInfo();
  100. MagickImage fImage = null;
  101. MagickImage sImage = null;
  102. MagickImage fLogo = null;
  103. MagickImage sLogo = null;
  104. Dimension imageDim = null;
  105. Dimension logoDim = null;
  106. try {
  107. //原来图片
  108. fImage = new MagickImage( new ImageInfo(filePath));
  109. imageDim = fImage.getDimension();
  110. int width = imageDim.width;
  111. int height = imageDim.height;
  112. sImage = fImage.scaleImage(width, height);
  113. fLogo = new MagickImage( new ImageInfo(logoPath));
  114. logoDim = fLogo.getDimension();
  115. int lw = logoDim.width;
  116. int lh = logoDim.height;
  117. sLogo = fLogo.scaleImage(lw, lh);
  118. //开始打水印,从左上角开始;如果到右边界则重新开始一行的打印(x=0,y=y+h)
  119. int startX = 0;
  120. int startY = 0;
  121. do {
  122. sImage.compositeImage(CompositeOperator.AtopCompositeOp, sLogo,
  123. startX, startY);
  124. startX += (logoDim.width + 60);
  125. if (startX >= width){
  126. startY += logoDim.height * 2;
  127. startX = 0;
  128. }
  129. } while(startY <= height);
  130. sImage.setFileName(toImg);
  131. sImage.writeImage(info);
  132. } finally {
  133. if (fImage != null) {
  134. fImage.destroyImages();
  135. }
  136. if (sImage != null) {
  137. sImage.destroyImages();
  138. }
  139. if (fLogo != null) {
  140. fLogo.destroyImages();
  141. }
  142. if (sLogo != null) {
  143. sLogo.destroyImages();
  144. }
  145. }
  146. }
  147. /**创建文字水印
  148. * @param filePath 源文件路径
  149. * toImg 生成文件位置
  150. * text 水印文本
  151. * pos logo在源图片中的相对位置,以像素点为单位
  152. * pointSize 用于设置点阵大小
  153. * @return
  154. * @throw MagickException
  155. * @author sulliy@sina.com 2010-8-11
  156. */
  157. public static void createWaterPrintByText(String filePath, String toImg, String text
  158. , Point pos, int pointSize)
  159. throws MagickException {
  160. if (!checkType(filePath) || !checkType(toImg)) {
  161. return;
  162. }
  163. if ( null == text || "".equals(text)) {
  164. text = "sulliy@sina.com";
  165. }
  166. ImageInfo info = new ImageInfo(filePath);
  167. if (filePath.toUpperCase().endsWith( "JPG")
  168. || filePath.toUpperCase().endsWith( "JPEG")) {
  169. info.setCompression(CompressionType.JPEGCompression); // 压缩类别为JPEG格式
  170. info.setPreviewType(PreviewType.JPEGPreview); // 预览格式为JPEG格式
  171. info.setQuality( 95);
  172. }
  173. MagickImage aImage = new MagickImage(info);
  174. Dimension imageDim = aImage.getDimension();
  175. int width = imageDim.width;
  176. int height = imageDim.height;
  177. if (width <= ( int)pos.getX() || height <= ( int)pos.getY()) {
  178. pos.setLocation( 0, 0);
  179. }
  180. int a = 0;
  181. int b = 0;
  182. String[] as = text.split( "");
  183. for (String string : as) {
  184. if (string.matches( "[/u4E00-/u9FA5]")) {
  185. a++;
  186. }
  187. if (string.matches( "[a-zA-Z0-9]")) {
  188. b++;
  189. }
  190. }
  191. int tl = a * 12 + b * 6 ; //字符长度
  192. MagickImage scaled = aImage.scaleImage(width, height);
  193. if (width > tl && height > 5) {
  194. DrawInfo aInfo = new DrawInfo(info);
  195. aInfo.setFill(PixelPacket.queryColorDatabase( "white"));
  196. aInfo.setUnderColor( new PixelPacket( 65535, 65535, 65535, 65535)); //设置为透明颜色
  197. aInfo.setPointsize(pointSize);
  198. // 解决中文乱码问题,自己可以去随意定义个自己喜欢字体,我在这用的微软雅黑
  199. String fontPath = "C:/WINDOWS/Fonts/MSIMHEI.TTF";
  200. // String fontPath = "/usr/maindata/MSYH.TTF";
  201. aInfo.setFont(fontPath);
  202. aInfo.setTextAntialias( true);
  203. aInfo.setOpacity( 0); //透明度
  204. aInfo.setText(text);
  205. aInfo.setGeometry( "+" + (( int)pos.getX() + "+" + ( int)pos.getY()));
  206. scaled.annotateImage(aInfo);
  207. }
  208. scaled.setFileName(toImg);
  209. scaled.writeImage(info);
  210. scaled.destroyImages();
  211. }
  212. /**切取图片
  213. * @param imgPath 原图路径
  214. * toPath 生成文件位置
  215. * w 左上位置横坐标
  216. * h 左上位置竖坐标
  217. * x 右下位置横坐标
  218. * y 右下位置竖坐标
  219. * @return
  220. * @throw MagickException
  221. * @author sulliy@sina.com 2010-8-11
  222. */
  223. public static void cutImg(String imgPath, String toPath, int w, int h,
  224. int x, int y) throws MagickException {
  225. ImageInfo infoS = null;
  226. MagickImage image = null;
  227. MagickImage cropped = null;
  228. Rectangle rect = null;
  229. try {
  230. infoS = new ImageInfo(imgPath);
  231. image = new MagickImage(infoS);
  232. rect = new Rectangle(x, y, w, h);
  233. cropped = image.cropImage(rect);
  234. cropped.setFileName(toPath);
  235. cropped.writeImage(infoS);
  236. } finally {
  237. if (cropped != null) {
  238. cropped.destroyImages();
  239. }
  240. }
  241. }
  242. /**删除图片文件
  243. * @param src 图片位置
  244. * @return
  245. * @throw
  246. * @author sulliy@sina.com 2010-8-11
  247. */
  248. public static boolean removeFile(String src) throws SecurityException{
  249. try {
  250. if (!checkType(src)) {
  251. return false;
  252. }
  253. File file = new File(src);
  254. return file.delete();
  255. } catch (Exception e) {
  256. e.printStackTrace();
  257. return false;
  258. }
  259. }
  260. }



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值