ImageMagick 与 JMagick

靳举
2023-12-01

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);
              }
    }



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

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;  
        }  
    }
    
}  



 类似资料: