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图片(通常指照片),一般先转换成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);
}
}
一些基本使用方法的代码,具体大家可以参考官方给的源码,那里比较详细:
-
package org.wsr.util;
-
-
import java.awt.Dimension;
-
import java.awt.Point;
-
import java.awt.Rectangle;
-
import java.io.File;
-
-
import magick.CompositeOperator;
-
import magick.CompressionType;
-
import magick.DrawInfo;
-
import magick.ImageInfo;
-
import magick.MagickException;
-
import magick.MagickImage;
-
import magick.PixelPacket;
-
import magick.PreviewType;
-
-
public
class JMagicjWrapper {
-
-
public static void main(String[] args) throws MagickException{
-
-
//test for function imageResize
-
-
// JMagicjWrapper.imageResize("pics.jpg", "reSize20x30.png", 20, 30);
-
// JMagicjWrapper.imageResize("pics.jpg", "reSize250x200.jpeg", 250, 200);
-
// JMagicjWrapper.imageResize("pics.jpg", "reSize50x50.jpg", 50, 50);
-
// JMagicjWrapper.imageResize("pics.jpg", "reSize120x120.bmp", 120, 120);
-
// JMagicjWrapper.imageResize("pics.jpg", "reSize.tif", 20, 30);//not create file
-
//
-
-
//test for function createWaterPrintByImg
-
JMagicjWrapper.createWaterPrintByImg(
"f://1.jpg",
"f://4.jpg",
"f://watermark.gif",
new Point(
0,
0));
-
//JMagicjWrapper.imageResize("wpl.gif", "logo250x200.gif", 250, 200);
-
//Because file "wpl.gif" may not be release, the later function cause a error, can not open file handle.
-
//JMagicjWrapper.createWaterPrintByImg("pics.jpg", "wpl.gif", "logoFull.jpg", new Point(1680,1050));//not create file
-
//JMagicjWrapper.createWaterPrintByImg("pics.jpg", "wpl.gif", "logoExt.jpg", new Point(2000,1000));//not create file
-
-
//test for function createWaterPrintByText
-
//This function can not handle Chinese Character, I'll continue to takle the issue
-
//JMagicjWrapper.createWaterPrintByText("pics1.jpg", "wpt.gif", "For Test", new Point(300,300), 100);
-
}
-
-
private
static
final String[] Type = {
-
".JPG",
-
".JPEG",
-
".BMP",
-
".GIF",
-
".PNG"
-
};
-
-
public static boolean checkType(String path){
-
for (
int i =
0; i < Type.length; i++) {
-
if (path.toUpperCase().endsWith(Type[i])) {
-
return
true;
-
}
else {
-
continue;
-
}
-
}
-
return
false;
-
}
-
-
/**改变图片大小
-
* @param filePath 原图片位置
-
* toPath 新图片位置
-
* width 新图片的宽度
-
* height 新图片的高度
-
* @return
-
* @throw
-
* @author sulliy@sina.com 2010-8-11
-
*/
-
public static void imageResize(String filePath, String toPath, int width, int height)
-
throws MagickException {
-
ImageInfo info =
null;
-
MagickImage image =
null;
-
Dimension imageDim =
null;
-
MagickImage scaled =
null;
-
-
if (!checkType(filePath) || !checkType(toPath)) {
-
return;
-
}
-
-
try {
-
info =
new ImageInfo();
-
image =
new MagickImage(info);
-
imageDim = image.getDimension();
-
if (width <=
0 || height <=
0) {
-
height =
120;
-
width =
120;
-
}
-
scaled = image.scaleImage(width, height);
-
scaled.setFileName(toPath);
-
scaled.writeImage(info);
-
}
finally {
-
if (scaled !=
null) {
-
scaled.destroyImages();
-
}
-
}
-
}
-
-
/**创建图片水印
-
* @param filePath 源文件路径
-
* toImg 生成文件位置
-
* logoPath logo路径
-
* pos logo在源图片中的相对位置,以像素点为单位
-
* @return
-
* @throw MagickException
-
* @author sulliy@sina.com 2010-8-11
-
*/
-
public static void createWaterPrintByImg(String filePath, String toImg,
-
String logoPath, Point pos)
throws MagickException {
-
if (!checkType(filePath) || !checkType(toImg) || !checkType(logoPath)) {
-
return;
-
}
-
-
ImageInfo info =
new ImageInfo();
-
MagickImage fImage =
null;
-
MagickImage sImage =
null;
-
MagickImage fLogo =
null;
-
MagickImage sLogo =
null;
-
Dimension imageDim =
null;
-
Dimension logoDim =
null;
-
try {
-
//原来图片
-
fImage =
new MagickImage(
new ImageInfo(filePath));
-
imageDim = fImage.getDimension();
-
int width = imageDim.width;
-
int height = imageDim.height;
-
sImage = fImage.scaleImage(width, height);
-
-
fLogo =
new MagickImage(
new ImageInfo(logoPath));
-
logoDim = fLogo.getDimension();
-
int lw = logoDim.width;
-
int lh = logoDim.height;
-
sLogo = fLogo.scaleImage(lw, lh);
-
-
//开始打水印,从左上角开始;如果到右边界则重新开始一行的打印(x=0,y=y+h)
-
int startX =
0;
-
int startY =
0;
-
do {
-
sImage.compositeImage(CompositeOperator.AtopCompositeOp, sLogo,
-
startX, startY);
-
startX += (logoDim.width +
60);
-
if (startX >= width){
-
startY += logoDim.height *
2;
-
startX =
0;
-
}
-
}
while(startY <= height);
-
-
sImage.setFileName(toImg);
-
sImage.writeImage(info);
-
}
finally {
-
if (fImage !=
null) {
-
fImage.destroyImages();
-
}
-
if (sImage !=
null) {
-
sImage.destroyImages();
-
}
-
if (fLogo !=
null) {
-
fLogo.destroyImages();
-
}
-
if (sLogo !=
null) {
-
sLogo.destroyImages();
-
}
-
}
-
}
-
-
/**创建文字水印
-
* @param filePath 源文件路径
-
* toImg 生成文件位置
-
* text 水印文本
-
* pos logo在源图片中的相对位置,以像素点为单位
-
* pointSize 用于设置点阵大小
-
* @return
-
* @throw MagickException
-
* @author sulliy@sina.com 2010-8-11
-
*/
-
public static void createWaterPrintByText(String filePath, String toImg, String text
-
, Point pos, int pointSize)
-
throws MagickException {
-
if (!checkType(filePath) || !checkType(toImg)) {
-
return;
-
}
-
-
if (
null == text ||
"".equals(text)) {
-
text =
"sulliy@sina.com";
-
}
-
-
ImageInfo info =
new ImageInfo(filePath);
-
if (filePath.toUpperCase().endsWith(
"JPG")
-
|| filePath.toUpperCase().endsWith(
"JPEG")) {
-
info.setCompression(CompressionType.JPEGCompression);
// 压缩类别为JPEG格式
-
info.setPreviewType(PreviewType.JPEGPreview);
// 预览格式为JPEG格式
-
info.setQuality(
95);
-
}
-
MagickImage aImage =
new MagickImage(info);
-
Dimension imageDim = aImage.getDimension();
-
int width = imageDim.width;
-
int height = imageDim.height;
-
-
if (width <= (
int)pos.getX() || height <= (
int)pos.getY()) {
-
pos.setLocation(
0,
0);
-
}
-
-
int a =
0;
-
int b =
0;
-
String[] as = text.split(
"");
-
for (String string : as) {
-
if (string.matches(
"[/u4E00-/u9FA5]")) {
-
a++;
-
}
-
if (string.matches(
"[a-zA-Z0-9]")) {
-
b++;
-
}
-
}
-
int tl = a *
12 + b *
6 ;
//字符长度
-
MagickImage scaled = aImage.scaleImage(width, height);
-
if (width > tl && height >
5) {
-
DrawInfo aInfo =
new DrawInfo(info);
-
aInfo.setFill(PixelPacket.queryColorDatabase(
"white"));
-
aInfo.setUnderColor(
new PixelPacket(
65535,
65535,
65535,
65535));
//设置为透明颜色
-
aInfo.setPointsize(pointSize);
-
// 解决中文乱码问题,自己可以去随意定义个自己喜欢字体,我在这用的微软雅黑
-
String fontPath =
"C:/WINDOWS/Fonts/MSIMHEI.TTF";
-
// String fontPath = "/usr/maindata/MSYH.TTF";
-
aInfo.setFont(fontPath);
-
aInfo.setTextAntialias(
true);
-
aInfo.setOpacity(
0);
//透明度
-
aInfo.setText(text);
-
aInfo.setGeometry(
"+" + ((
int)pos.getX() +
"+" + (
int)pos.getY()));
-
scaled.annotateImage(aInfo);
-
}
-
scaled.setFileName(toImg);
-
scaled.writeImage(info);
-
scaled.destroyImages();
-
}
-
-
/**切取图片
-
* @param imgPath 原图路径
-
* toPath 生成文件位置
-
* w 左上位置横坐标
-
* h 左上位置竖坐标
-
* x 右下位置横坐标
-
* y 右下位置竖坐标
-
* @return
-
* @throw MagickException
-
* @author sulliy@sina.com 2010-8-11
-
*/
-
public static void cutImg(String imgPath, String toPath, int w, int h,
-
int x,
int y)
throws MagickException {
-
ImageInfo infoS =
null;
-
MagickImage image =
null;
-
MagickImage cropped =
null;
-
Rectangle rect =
null;
-
try {
-
infoS =
new ImageInfo(imgPath);
-
image =
new MagickImage(infoS);
-
rect =
new Rectangle(x, y, w, h);
-
cropped = image.cropImage(rect);
-
cropped.setFileName(toPath);
-
cropped.writeImage(infoS);
-
-
}
finally {
-
if (cropped !=
null) {
-
cropped.destroyImages();
-
}
-
}
-
}
-
-
/**删除图片文件
-
* @param src 图片位置
-
* @return
-
* @throw
-
* @author sulliy@sina.com 2010-8-11
-
*/
-
public static boolean removeFile(String src) throws SecurityException{
-
try {
-
if (!checkType(src)) {
-
return
false;
-
}
-
-
File file =
new File(src);
-
return file.delete();
-
}
catch (Exception e) {
-
e.printStackTrace();
-
return
false;
-
}
-
}
-
-
}