Java环境下Imagemagick中文图片处理问题非完美解决方案

 

Java环境下Imagemagick中文图片处理问题非完美解决方案

在处理服务器与客户端交互时候,基于性能考虑(参考手机客户端网络加速技术方案实现思考 ), 对软件介绍中的图片采用缩略图进行展现,这样涉及了实际图片缩略图的动态处理问题,采用Java的Runtime.getRuntime().exec直 接来调用Imagemagick的命令来完成缩略图的动态生成。原本是一个很简单的问题,只不过由于在图片的目录路径及图片名称中存在中文,因此在处理时 候又出现了FileNotFoundException,记录一下非完美解决方案。

1、系统环境:

操作系统:Red Hat Enterprise Linux AS release 4 (Nahant Update 4)

操作系统用户环境变量(参考Linux环境下资源下载中文目录及中文文件名称问题 ):

export LC_ALL=zh_CN.GB18030

export LANG= zh_CN.GB18030

JVM、Tomcat、数据库等相关的字符集(参考Struts2中Datetimepicker控件的中文问题 ):UTF-8

2、需求场景

手机客户端对于图片的请求分为两大类:图片的下载请求、图片的预览请求。

图片的下载请求 :客户端请求下载实际的图片内容,此时候服务器端不需要对图片进行任何加工处理,只需要正确返回实际的图片内容。

图片的预览请求 :客户端并不需要下载完整的图片内容,只需要在客户端能够预览图片,因此在分辨率及图片质量上可以稍稍降低,以节省带宽资源。在手机客户端发起图片预览请求时候,服务器端响应的所有的图片都采用缩略图(降低图片大小)及低分辨率(降低图片质量)的方式返回。

备注:通过手机浏览器或手机客户端下载1M左右以上的资源时候,如果采用Struts2的Stream Result,存在服务器端无响应的现象,具体原因没有查明,有空看看Struts2代码再说,采用传统的response写流的方式实现没有此问题。

3、实现机制

采用Runtime.getRuntime().exec(“/usr/bin/convert  -sample 75%x75% /test.jpg /test_thumb.jpg”)来动态生成缩略图。

备注:

a、考虑到jmagick并不能完整支持Imagemagick所有命令集且使用上并不是很方便,因此没有采用jmagick,直接使用 Runtime.getRuntime().exec(“/usr/bin/convert  -sample 75%x75% /test.jpg /test_thumb.jpg”)的方案,使用方法具体可以参考在线主题制作技术实现方案

b、这里使用的imagemagick的命令只供测试使用,不一定是最佳的命令,具体查一下imagemagick的手册

c、由于Imagemagick生成图片相对较慢,因此并不需要每一次都生成缩略图,可以将缩略图存放在与原有图片相同的目录路径下,这样在客户端 发起图片预览请求时候,服务器端先查看一下请求图片的预览图是否存在,如果存在直接返回以前生成的预览图,如果不存在则动态生成后再返回。

4、问题

在使用Runtime.getRuntime().exec调用convert来动态生成缩略图时候,由于资源在Linux服务器上存放目录及文件 名称都存在中文(例如/products/material/img/101×80 /人物肖像101×8/测试.jpg),因此在调用时候会报FileNotFoundException错误。

5、方案测试

测试命令:

/usr/bin/convert -sample 75%x75%   /img/101×80/人物肖像101×8/测试.jpg  /img/101×80/人物肖像101×8/测试_thumb.jpg

试验1:

操作: 操作系统编码为zh_CN.GB18030,因此在shell命令行执行convert,如果传入的字符串参数为正常的zh_CN.GBK(比zh_CN.GB18030范围小)的编码,那么不会乱码。

结果: 在命令行执行,已验证。

试验2:

操作: JVM环境变量为UTF-8,Java内部本身也是采用UTF-8编码,Runtime.getRuntime().exec调用convert时候,如果将参数进行转码成zh_CN.GBK,则应该能够正常处理

private static final String CMD=”/usr/bin/convert “;
private static final String PRAM=” -sample 75%x75%  “;

inputPath=new String(inputPath.getBytes(“UTF-8″),”GBK”);
outPutPath=new String(outPutPath.getBytes(“UTF-8″),”GBK”);
Process pc=Runtime.getRuntime().exec(CMD+PRAM+inputPath+” “+outPutPath);

结果: 以上代码不行,将getBytes的编码换成GBK、ISO8859-1,输出编码换成UTF-8、ISO8859-1等也一样

试验3:

操作: 将JVM环境变量修改为GBK

结果: 似乎也不行

试验4:

操作: 在java代码中,将中文路径/img/101×80/人物肖像101×8/测试.jpg  /img/101×80/人物肖像101×8/测试_thumb.jpg写入普通文本文件/home/client.aouu.com/img /img2.txt,然后在命令行调用convert来生成

Java代码(示例,不规范):

FileWriter os = new FileWriter(“/home/client.aouu.com/img/img1.txt”);
String imgPath=inputPath+” “+outPutPath;
os.write(imgPath);
os.close();
Process pc=Runtime.getRuntime().exec(“/home/client.aouu.com/img/img.sh”);
pc.waitFor();

img.sh:

#!/bin/sh

cat /home/client.aouu.com/img/img1.txt |xargs /usr/bin/convert  -sample 75%x75%

结果: 不行,报告-bash: ./img.sh: cannot execute binary file

试验5:

操作: 与试验4操作相同

img.sh:

#!/bin/sh

iconv -f UTF-8 -t GBK -c /home/client.aouu.com/img/img1.txt -o /home/client.aouu.com/img/img2.txt
cat /home/client.aouu.com/img/img2.txt |xargs /usr/bin/convert  -sample 75%x75%

结果: OK

结果分析:

尽管在java代码中将中文路径、中文文件名称的编码转码成GBK,但java内部本身是UTF-8编码,因此JVM通过 Runtime.getRuntime().exec传给/usr/bin/convert的参数实际上仍然为UTF-8编码(?是什么编码,尚待验 证),并不是GBK编码,因此convert获取输入参数后无法在操作系统找到对应的文件。

通过FileWriter写入文件的字符集也为UTF-8,通过iconv强制将UTF-8编码转化为GBK,这样convert能够正常处理。

具体的原因及机理尚待进一步考察验证,现在尚无好的办法,姑且凑合使用此种方案再说。


站内标签: convert , 环境变量 , iconv , imagemagick , java , linux , 中文目录 , 中文文件名 , 中文乱码


ImageMagick 是一款强大的图像处理软件,通过它我们可以实现多张图片的合并。在 Java 中,我们可以通过调用 ImageMagick 的命令行工具来实现图片合并。 首先,我们需要确保系统中已经安装了 ImageMagick。可以在终端中输入 `magick -version` 命令来检查是否已经安装成功。 接下来,我们可以使用 Java 的 `Runtime` 类来执行 ImageMagick 的命令行工具。首先,我们需要构建一个字符串数组,其中包含我们要执行的命令。例如,如果我们想要合并两张图片A.jpg和B.jpg,那么我们可以构建如下的命令数组: ```java String[] command = {"magick", "convert", "A.jpg", "B.jpg", "+append", "output.jpg"}; ``` 这个命令数组中,`magick` 是 ImageMagick 的命令行工具,`convert` 是 ImageMagick 的功能之一,`A.jpg` 和 `B.jpg` 是要合并的两张图片的文件名,`+append` 是合并图片的参数,`output.jpg` 是合并后的图片的输出文件名。 接下来,我们可以使用 `Runtime` 类的 `exec` 方法来执行命令: ```java Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command); ``` 执行完毕后,我们可以通过 `process.waitFor()` 方法等待命令执行完成。 最后,我们可以通过 `ImageIO` 类将合并后的图片输出到本地文件中: ```java BufferedImage mergedImage = ImageIO.read(new File("output.jpg")); ImageIO.write(mergedImage, "jpg", new File("merged.jpg")); ``` 以上就是使用 ImageMagickJava 中合并图片的过程。需要注意的是,使用 ImageMagick 进行图片合并的同时也可以对图片进行其他处理,例如裁剪、缩放、旋转等。具体的命令和参数可以根据需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值