Im4java 操作 ImageMagick 处理图片

Stella981
• 阅读 791

背景

之前用的是JMagick,各种限制各种坑,直到使用了Im4java,真是相当的好用啊。

项目描述

ImageMagic的安装可参考:图片处理软件 ImageMagick 的安装和使用

Im4java是ImageMagick的第二个java接口。它不是JMagick的替代品,而是作为补充。

JMagick是ImageMagick C-API之上的瘦JNI层。相比之下,im4java只为ImageMagick命令生成命令行,并将生成的命令行传递给选定的IM命令(使用java.lang.ProcessBuilder.start() - 方法)。

im4java的缺点:您仅限于IM命令的功能。使用JMagick,您可以访问IM的低级接口,所以您可以非常详细地控制图像处理。图像处理会有更好的表现。

im4java的优点:IM命令行的界面非常稳定,因此你的java程序(和im4java-library)可以在很多版本的IM上运行。im4java还提供了更好的OO接口(IM命令行的“语言”,其后缀操作符号很容易转换为OO符号)。最重要的是:你可以在任何地方使用im4java,而JMagick在某些地方会因为JNI的危险性而无法使用 (例如java应用程序服务器)。

注意事项

我用的ImageMagick版本是ImageMagick-7.0.8-12-Q16-x64-dll.exe,安装完后发现安装目录里只有个 magick.exe 命令。程序里直接使用convert,composite,identify的时候都会报错,提示文件找不到。新版本使用这些命令必须先写上 magick 命令才行,比如这样 magick convert xxxx。原因可能是ImageMagick版本更新了,但是Im4java版本没更新(Im4java版本是1.4.0),导致出现不兼容的情况,解决办法很简单,直接把 magick.exe 复制三份,重命名为其他三个命令就可以了,实测可用。

Im4java 操作 ImageMagick 处理图片

Im4java 操作 ImageMagick 处理图片

Im4java 操作 ImageMagick 处理图片

Im4java 操作 ImageMagick 处理图片

项目代码

Im4java的当前最新版本是1.4.0,支持Maven配置

新建Maven项目,在pom中添加

<dependency>
    <groupId>org.im4java</groupId>
    <artifactId>im4java</artifactId>
    <version>1.4.0</version>
</dependency>

工具类

  1 package imagemagick;
  2 
  3 import java.awt.Image;
  4 import java.awt.image.BufferedImage;
  5 import java.io.File;
  6 import java.util.ArrayList;
  7 import java.util.HashMap;
  8 import java.util.Map;
  9 
 10 import javax.imageio.ImageIO;
 11 
 12 import org.im4java.core.CompositeCmd;
 13 import org.im4java.core.ConvertCmd;
 14 import org.im4java.core.IMOperation;
 15 import org.im4java.core.IdentifyCmd;
 16 import org.im4java.core.ImageCommand;
 17 import org.im4java.process.ArrayListOutputConsumer;
 18 
 19 public class Im4JavaUtils {
 20     
 21     private static final String IMAGE_MAGICK_PATH = "D:\\ImageMagick-7.0.8-Q16";
 22     
 23     enum CommandType{
 24         
 25         convert("转换处理"),composite("图片合成"),identify("图片信息"),;
 26         private String name;
 27         
 28         CommandType(String name) {
 29             this.name = name;
 30         }
 31 
 32         public String getName() {
 33             return name;
 34         }
 35 
 36         public void setName(String name) {
 37             this.name = name;
 38         }
 39         
 40     }
 41     
 42     private static ImageCommand getImageCommand(CommandType command) {
 43         ImageCommand cmd = null;
 44         switch (command) {
 45         case convert:
 46             cmd = new ConvertCmd();
 47             break;
 48         case composite:
 49             cmd = new CompositeCmd();
 50             break;
 51         case identify:
 52             cmd = new IdentifyCmd();
 53             break;
 54         }
 55         if (cmd != null) {
 56             cmd.setSearchPath(IMAGE_MAGICK_PATH);
 57         }
 58         return cmd;
 59     }
 60 
 61     /**
 62      * 旋转图片
 63      * @param srcImagePath 原图片地址
 64      * @param newImagePath 新图片地址
 65      * @param degree 旋转角度
 66      * @return
 67      */
 68     public static boolean roateImage(String srcImagePath, String newImagePath, Double degree){
 69         try {
 70             IMOperation op = new IMOperation();
 71             op.addImage(srcImagePath);
 72             op.rotate(degree);
 73             op.addImage(newImagePath);
 74             ImageCommand convert = getImageCommand(CommandType.convert);
 75             convert.run(op);
 76             System.out.println("旋转图片成功");
 77         } catch (Exception e) {
 78             e.printStackTrace();
 79             return false;
 80         }
 81         return true;
 82     }
 83     
 84     /**
 85      * 裁剪图片
 86      * @param srcImagePath 原图片地址
 87      * @param newImagePath 新图片地址
 88      * @param width 裁剪后的宽度
 89      * @param height 裁剪后的高度
 90      * @param x 起始横坐标
 91      * @param y 起始纵坐标
 92      * @return
 93      */
 94     public static boolean cutImage(String srcImagePath, String newImagePath, Integer width, Integer height, Integer x, Integer y) {
 95         try {
 96             IMOperation op = new IMOperation();
 97             op.addImage(srcImagePath);
 98             op.crop(width, height, x, y);
 99             op.addImage(newImagePath);
100             ImageCommand convert = getImageCommand(CommandType.convert);
101             convert.run(op);
102             System.out.println("裁剪图片成功");
103         } catch (Exception e) {
104             e.printStackTrace();
105             return false;
106         }
107         return true;
108     }
109     
110     /**
111      * 缩放图片
112      * @param srcImagePath 原图片地址
113      * @param newImagePath 新图片地址
114      * @param width 缩放后的宽度
115      * @param height 缩放后的高度
116      * 高度和宽度需符合图片比例,不符合的情况下,以其中最小值为准。
117      * @return
118      */
119     public static boolean zoomImage(String srcImagePath, String newImagePath, Integer width, Integer height) {
120         try {
121             IMOperation op = new IMOperation();
122             op.addImage(srcImagePath);
123             op.resize(width, height);
124             op.addImage(newImagePath);
125             ImageCommand convert = getImageCommand(CommandType.convert);
126             convert.run(op);
127             System.out.println("缩放图片成功");
128         } catch (Exception e) {
129             e.printStackTrace();
130             return false;
131         }
132         return true;
133     }
134     
135     /**
136      * 压缩图片
137      * @param srcImagePath 原图片地址
138      * @param newImagePath 新图片地址
139      * @param quality 压缩比例
140      * 图片压缩比,有效值范围是0.0-100.0,数值越大,缩略图越清晰。
141      * @return
142      */
143     public static boolean compressImage(String srcImagePath, String newImagePath, Double quality) {
144         try {
145             IMOperation op = new IMOperation();
146             op.addImage(srcImagePath);
147             op.quality(quality);
148             op.addImage(newImagePath);
149             ImageCommand convert = getImageCommand(CommandType.convert);
150             convert.run(op);
151             System.out.println("压缩图片成功");
152         } catch (Exception e) {
153             e.printStackTrace();
154             return false;
155         }
156         return true;
157     }
158     
159     /**
160      * 文字水印
161      * @param srcImagePath 原图片地址
162      * @param newImagePath 新图片地址
163      * @param content 水印文字,不支持汉字
164      * @return
165      */
166     public static boolean textImage(String srcImagePath, String newImagePath, String content) {
167         try {
168             IMOperation op = new IMOperation();
169             op.addImage(srcImagePath);
170             //右下角
171             op.font("ArialBold").gravity("southeast").pointsize(60).fill("#F2F2F2").draw("text 10,10 " + content);
172             op.addImage(newImagePath);
173             ImageCommand convert = getImageCommand(CommandType.convert);
174             convert.run(op);
175             System.out.println("添加文字水印成功");
176         } catch (Exception e) {
177             e.printStackTrace();
178             return false;
179         }
180         return true;
181     }
182     
183     /**
184      * 图片水印
185      * @param srcImagePath 原图片地址
186      * @param newImagePath 新图片地址
187      * @param appendImagePath 水印图片地址
188      * @param dissolve 水印透明度,0-100
189      * @return
190      */
191     public static boolean compositeImage(String srcImagePath, String newImagePath, String appendImagePath, Integer dissolve) {
192         try {
193             //原图片信息
194             BufferedImage bufferedImage = ImageIO.read(new File(srcImagePath));
195             int w = bufferedImage.getWidth();
196             int h = bufferedImage.getHeight();
197             //水印图片信息
198             Image image = ImageIO.read(new File(appendImagePath));
199             int w1 = image.getWidth(null);
200             int h1 = image.getHeight(null);
201             
202             IMOperation op = new IMOperation();
203             op.geometry(w1, h1, w-w1-10, h-h1-10);
204             op.dissolve(dissolve);
205             op.addImage(appendImagePath);
206             op.addImage(srcImagePath);
207             op.addImage(newImagePath);
208             ImageCommand composite = getImageCommand(CommandType.composite);
209             composite.run(op);
210             System.out.println("添加图片水印成功");
211         } catch (Exception e) {
212             e.printStackTrace();
213             return false;
214         }
215         return true;
216     }
217     
218     /**
219      * 获取图片信息
220      * @param imagePath 图片地址
221      * @return
222      */
223     public static Map<String, String> getImageInfo(String imagePath) {
224         Map<String, String> imageInfo = new HashMap<>();
225         try {
226             IMOperation op = new IMOperation();
227             op.format("%w,%h,%d/%f,%Q,%b,%e");
228             op.addImage();
229             ImageCommand identifyCmd = getImageCommand(CommandType.identify);//注意这里,用的是identify
230             ArrayListOutputConsumer output = new ArrayListOutputConsumer();  
231             identifyCmd.setOutputConsumer(output);  
232             identifyCmd.run(op, imagePath);  
233             ArrayList<String> cmdOutput = output.getOutput();  
234             String[] result = cmdOutput.get(0).split(",");
235             if (result.length == 6) {
236                 imageInfo.put("宽度", result[0]);
237                 imageInfo.put("高度", result[1]);
238                 imageInfo.put("路径", result[2]);
239                 imageInfo.put("质量", result[3]);
240                 imageInfo.put("大小", result[4]);
241                 imageInfo.put("格式", result[5]);
242             }
243         } catch (Exception e) {
244             e.printStackTrace();
245         }
246         return imageInfo;
247     }
248     
249 }

测试代码

 1 package imagemagick;
 2 
 3 import java.util.Map;
 4 
 5 public class Im4JavaTest {
 6     
 7     //源图片目录
 8     public static final String SRC_IMAGE_PATH = "C:\\Users\\Administrator\\Desktop\\test\\";
 9     //新图片目录
10     public static final String NEW_IMAGE_PATH = "C:\\Users\\Administrator\\Desktop\\new\\";
11     //水印图片地址
12     public static final String APPEND_IMAGE_PATH = "C:\\Users\\Administrator\\Desktop\\test\\logo.jpg";
13     
14     public static void main(String[] args) {
15         
16         Im4JavaUtils.roateImage(SRC_IMAGE_PATH + "1.jpg", NEW_IMAGE_PATH + "1.jpg", 90.0);
17         
18         Im4JavaUtils.cutImage(SRC_IMAGE_PATH + "2.jpg", NEW_IMAGE_PATH + "2.jpg", 100, 100, 100, 100);
19         
20         Im4JavaUtils.zoomImage(SRC_IMAGE_PATH + "3.jpg", NEW_IMAGE_PATH + "3.jpg", 400, 270);
21         
22         Im4JavaUtils.compressImage(SRC_IMAGE_PATH + "4.jpg", NEW_IMAGE_PATH + "4.jpg", 50.0);
23         
24         Im4JavaUtils.textImage(SRC_IMAGE_PATH + "5.jpg", NEW_IMAGE_PATH + "5.jpg", "TEST");
25         
26         Im4JavaUtils.compositeImage(SRC_IMAGE_PATH + "6.jpg", NEW_IMAGE_PATH + "6.jpg", APPEND_IMAGE_PATH, 50);
27         
28         System.out.println("======获取图片信息=====");
29         Map<String, String> imageInfo = Im4JavaUtils.getImageInfo(SRC_IMAGE_PATH + "6.jpg");
30         for (String key : imageInfo.keySet()) {
31             System.out.println(key + " : " + imageInfo.get(key));
32         }
33         System.out.println("======获取图片信息=====");
34 
35     }
36 
37 }

运行结果

原图片文件夹

Im4java 操作 ImageMagick 处理图片

新图片文件夹,测试结果

Im4java 操作 ImageMagick 处理图片

Im4java 操作 ImageMagick 处理图片

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这