JMagic 操作 ImageMagick 处理图片
项目描述
imagemagick是功能强大的图片处理库,以稳定及高效率著称,众多语言对该库进行封装处理。比如php、java。由于我们是java项目,直接使用java通过JNI技术调用ImageMagick是不行的。因为ImageMagick开发时没有使用java JNI生成的头文件。可以使用JMagick解决,JMagick是由c语言开发的,开发时使用了java JNI生成的头文件,所以java可以通过JNI技术调用JMagick。JMagick再调用ImageMagick。这里我们处理图片使用的是JMagick暴露的java接口。
下载和安装
Windows安装使用Jmagick及imagemagick步骤如下:
1、访问jmagick网站下载: http://downloads.jmagick.org
2、目前JMagick只有32位的,所以只能选择32位的ImageMagick,并且版本支持很低,目前只到ImageMagick-6.3.9-0,只能使用32位的JDK,64位进程不能够调用32位的dll,想在64位的系统上用jmagick不仅要将jdk换成32位,而且jmagick.dll也得放到SysWOW64下面,不能放到System32中。
3、下载两个文件:红框的两个或者绿框的两个。
关于Q8,Q16,Q32的说明:(建议使用8,现在数码相机照的相片,每一种颜色就是8位深,3种颜色就是24位,所以选8)
支持的参数有3种,分别是 8,16,32。默认值是16。
Q8表示: 8-bits per pixel quantum
Q16表示:16-bits per pixel quantum
Q32表示:32-bits per pixel quantum
使用16-bit per pixel quantums在处理图片时比8-bit慢15%至50%,并须要更多的内存。
处理一张1024x768像素的图片8-bit要使用3.6M内存,16-bit要使用7.2M内存。计算方法是: (5 * Quantum Depth * Rows * Columns) / 8
大多数电脑显示使用8-bit per pixel quantums。使用16-bit per pixel quantums在处理图片时比8-bit慢15%至50%,并须要更多的内存。比如处理一张1024x768像素的图片8-bit要使用3M内存,16-bit要使用8M内存。8-bit可表示0-255种值,16-bit可表示0-65535种值。默认值是8-bit。
另外Windows下有动态版(dll),有静态版(static),这里使用了动态版。
4、下载时注意版本问题。不要到imagemagick官方网站下载imagemagick,这样会导致下载的imagemagick版本和jmagick版本不对应,导致调用出现异常。比如出现memor allocate not enough 的异常。
这是我下载出来的文件(我公司电脑系统是WIN7-32位,安装的也是32位的JDK):
5、双击下载的ImageMagick-6.3.9-0-Q8-windows-dll.exe文件安装即可,一直点击下一步就可以。这里如果勾选了红框标注的选项,环境变量会自动配好的。
在命令行使用
到这里就可以在DOS命令窗口中使用了,具体使用命令可以参考这篇博客:http://www.charry.org/docs/linux/ImageMagick/ImageMagick.html,下面截图演示对桌面图片的处理:
在Java中使用
1、将ImageMagick安装目录下的所有的.dll文件复制到 C:/ windows/System32的目录下(这一步有可能省略,等待验证)
2、解压jmagick-win-6.3.9-Q8.zip , 将jmagick.dll放到 C:/windows/System32 目录下。这里是为了能在Java中使用jmagick的类进行操作ImageMagick,如果不复制的话,会报UnsatisfiedLinkError: no JMagick in java.library.path.异常。
3、将jmagick.jar加入到eclipse下相关项目的build path中的libraries 中即完成了相应的安装。接下来就可以在java项目中使用了。
4、Java中通过jmagick操作ImageMagick,示例代码:
1 package com.demo.test; 2 3 import java.awt.Dimension; 4 import java.awt.Rectangle; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 8 9 import magick.CompositeOperator; 10 import magick.CompressionType; 11 import magick.DrawInfo; 12 import magick.ImageInfo; 13 import magick.MagickException; 14 import magick.MagickImage; 15 import magick.PixelPacket; 16 import magick.PreviewType; 17 18 public class ImageTools { 19 20 static{ 21 //不能漏掉这个,不然jmagick.jar的路径找不到 22 //System.setProperty("jmagick.systemclassloader","no"); 23 } 24 25 /** 26 * 压缩图片 27 * @param filePath 源文件路径 28 * @param toPath 缩略图路径 29 */ 30 public static void createThumbnail(String filePath, String toPath) throws MagickException{ 31 ImageInfo info = null; 32 MagickImage image = null; 33 Dimension imageDim = null; 34 MagickImage scaled = null; 35 try{ 36 info = new ImageInfo(filePath); 37 image = new MagickImage(info); 38 imageDim = image.getDimension(); 39 int wideth = imageDim.width; 40 int height = imageDim.height; 41 if (wideth > height) { 42 height = 660 * height / wideth; 43 wideth = 660; 44 } 45 scaled = image.scaleImage(wideth, height);//小图片文件的大小. 46 scaled.setFileName(toPath); 47 scaled.writeImage(info); 48 }finally{ 49 if(scaled != null){ 50 scaled.destroyImages(); 51 } 52 } 53 } 54 55 /** 56 * 水印(图片logo) 57 * @param filePath 源文件路径 58 * @param toImg 修改图路径 59 * @param logoPath logo图路径 60 * @throws MagickException 61 */ 62 public static void initLogoImg(String filePath, String toImg, String logoPath) throws MagickException { 63 ImageInfo info = new ImageInfo(); 64 MagickImage fImage = null; 65 MagickImage sImage = null; 66 MagickImage fLogo = null; 67 MagickImage sLogo = null; 68 Dimension imageDim = null; 69 Dimension logoDim = null; 70 try { 71 fImage = new MagickImage(new ImageInfo(filePath)); 72 imageDim = fImage.getDimension(); 73 int width = imageDim.width; 74 int height = imageDim.height; 75 if (width > 660) { 76 height = 660 * height / width; 77 width = 660; 78 } 79 sImage = fImage.scaleImage(width, height); 80 81 fLogo = new MagickImage(new ImageInfo(logoPath)); 82 logoDim = fLogo.getDimension(); 83 int lw = width / 8; 84 int lh = logoDim.height * lw / logoDim.width; 85 sLogo = fLogo.scaleImage(lw, lh); 86 87 sImage.compositeImage(CompositeOperator.AtopCompositeOp, sLogo, width-(lw + lh/10), height-(lh + lh/10)); 88 sImage.setFileName(toImg); 89 sImage.writeImage(info); 90 } finally { 91 if(sImage != null){ 92 sImage.destroyImages(); 93 } 94 } 95 } 96 97 /** 98 * 水印(文字) 99 * @param filePath 源文件路径 100 * @param toImg 修改图路径 101 * @param text 名字(文字内容自己随意) 102 * @throws MagickException 103 */ 104 public static void initTextToImg(String filePath, String toImg, String text) throws MagickException{ 105 ImageInfo info = new ImageInfo(filePath); 106 if (filePath.toUpperCase().endsWith("JPG") || filePath.toUpperCase().endsWith("JPEG")) { 107 info.setCompression(CompressionType.JPEGCompression); //压缩类别为JPEG格式 108 info.setPreviewType(PreviewType.JPEGPreview); //预览格式为JPEG格式 109 info.setQuality(95); 110 } 111 MagickImage aImage = new MagickImage(info); 112 Dimension imageDim = aImage.getDimension(); 113 int wideth = imageDim.width; 114 int height = imageDim.height; 115 if (wideth > 660) { 116 height = 660 * height / wideth; 117 wideth = 660; 118 } 119 int a = 0; 120 int b = 0; 121 String[] as = text.split(""); 122 for (String string : as) { 123 if(string.matches("[\u4E00-\u9FA5]")){ 124 a++; 125 } 126 if(string.matches("[a-zA-Z0-9]")){ 127 b++; 128 } 129 } 130 int tl = a*12 + b*6 + 300; 131 MagickImage scaled = aImage.scaleImage(wideth, height); 132 if(wideth > tl && height > 5){ 133 DrawInfo aInfo = new DrawInfo(info); 134 aInfo.setFill(PixelPacket.queryColorDatabase("white")); 135 aInfo.setUnderColor(new PixelPacket(0,0,0,100)); 136 aInfo.setPointsize(12); 137 //解决中文乱码问题,自己可以去随意定义个自己喜欢字体,我在这用的微软雅黑 138 String fontPath = "C:/WINDOWS/Fonts/MSYH.TTF"; 139 //String fontPath = "/usr/maindata/MSYH.TTF"; 140 aInfo.setFont(fontPath); 141 aInfo.setTextAntialias(true); 142 aInfo.setOpacity(0); 143 aInfo.setText(" " + text + "于 " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + " 上传于我的相册网,版权归作者所有!"); 144 aInfo.setGeometry("+" + (wideth-tl) + "+" + (height-5)); 145 scaled.annotateImage(aInfo); 146 } 147 scaled.setFileName(toImg); 148 scaled.writeImage(info); 149 scaled.destroyImages(); 150 } 151 152 /** 153 * 切图 154 * @param imgPath 源图路径 155 * @param toPath 修改图路径 156 * @param w 157 * @param h 158 * @param x 159 * @param y 160 * @throws MagickException 161 */ 162 public static void cutImg(String imgPath, String toPath, int w, int h, int x, int y) throws MagickException { 163 ImageInfo infoS = null; 164 MagickImage image = null; 165 MagickImage cropped = null; 166 Rectangle rect = null; 167 try { 168 infoS = new ImageInfo(imgPath); 169 image = new MagickImage(infoS); 170 rect = new Rectangle(x, y, w, h); 171 cropped = image.cropImage(rect); 172 cropped.setFileName(toPath); 173 cropped.writeImage(infoS); 174 175 } finally { 176 if (cropped != null) { 177 cropped.destroyImages(); 178 } 179 } 180 } 181 182 /** 183 * 测试 184 * @param args 185 */ 186 public static void main(String[] args) { 187 try { 188 cutImg("C:\\Users\\Administrator\\Desktop\\test\\new3.jpg", "C:\\Users\\Administrator\\Desktop\\test\\new5.jpg", 100, 100, 300, 150); 189 } catch (MagickException e) { 190 e.printStackTrace(); 191 } 192 } 193 }