Java图片处理/压缩
图片压缩分为无损,有损压缩处理。
- 首先考虑用开源的或商业的jar包。
1.thumbnailator-0.4.2-all.jar
2.图片压缩:magickimage
Java图片处理/压缩:ImageMagick for java 使用Jmagick压缩高质量图片(包括Jmagick的应用)
ImageMagick for java 使用Jmagick压缩高质量图片j
在做pdf文档转成jpg的时候,发现了Jmagick的创建高质量的图片的一个java类库,自己以前使用另外的一个类库,感觉这个更好点,就试着用了下,感觉不错
1.使用的windows下的jmagick-win-6.3.9-Q16.zip 地址是:http://downloads.jmagick.org/6.3.9/
2.doc对应的api地址:http://downloads.jmagick.org/jmagick-doc/
3.安装ImageMagick,官方网站:http://www.imagemagick.org/
我使用的是:ImageMagick-6.4.6-4-Q16-windows-dll.exe :点击下载
4. 安装ImageMagick-6.4.6-4-Q16-windows-dll.exe,将 安装目录下(按自己所安装的目录找) 下的所有dll文件 copy 到系统盘下的 “C:\WINDOWS\system32\”文件夹里
5. 配置环境变量
再环境变量path里添加新的值 “C:\Program Files\ImageMagick-6.4.6-4-Q16“使用IDE可以不用配置
6.解压jmagick-win-6.3.9-Q16.zip
将 jmagick.dll 复制到系统盘下的 “C:\WINDOWS\system32\”文件夹里 和 复制到jdk的bin(例“D:\jdk6\bin”)文件里各一份
将 jmagick.jar 复制到Tomcat下的lib文件夹里 和 所使用项目的WEB-INF下lib文件里 各一份
7.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 )
8.还要注意如果部署到web应用,你在使用的class里面需要
System.setProperty(“jmagick.systemclassloader”,”no”);
要不然会报出UnsatisfiedLinkError: no JMagick in java.library.path.
实例测试code:
package com.utils; import magick.ImageInfo; import magick.MagickApiException; import magick.MagickException; import magick.MagickImage; public class Treamspdf { public static void main(String[] args) { resetsize("E:/mylearn/workspace/TTPDF/src/com/utils/http_imgload.jpg","new.jpg"); } public static void resetsize(String picFrom,String picTo){ try{ ImageInfo info=new ImageInfo(picFrom); MagickImage image=new MagickImage(new ImageInfo(picFrom)); MagickImage scaled=image.scaleImage(120, 97); scaled.setFileName(picTo); scaled.writeImage(info); }catch(MagickApiException ex){ ex.printStackTrace(); } catch(MagickException ex) { ex.printStackTrace(); } } }
常用的水印,切图,压缩等简单程序工具类,继续下面
package com.utils; import java.awt.Dimension; import java.awt.Rectangle; import java.text.SimpleDateFormat; import java.util.Date; 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 Aa { static{ //不能漏掉这个,不然jmagick.jar的路径找不到 System.setProperty("jmagick.systemclassloader","no"); } /** * 压缩图片 * @param filePath 源文件路径 * @param toPath 缩略图路径 */ public static void createThumbnail(String filePath, String toPath) throws MagickException{ ImageInfo info = null; MagickImage image = null; Dimension imageDim = null; MagickImage scaled = null; try{ info = new ImageInfo(filePath); image = new MagickImage(info); imageDim = image.getDimension(); int wideth = imageDim.width; int height = imageDim.height; if (wideth > height) { height = 660 * height / wideth; wideth = 660; } scaled = image.scaleImage(wideth, height);//小图片文件的大小. scaled.setFileName(toPath); scaled.writeImage(info); }finally{ if(scaled != null){ scaled.destroyImages(); } } } /** * 水印(图片logo) * @param filePath 源文件路径 * @param toImg 修改图路径 * @param logoPath logo图路径 * @throws MagickException */ public static void initLogoImg(String filePath, String toImg, String logoPath) throws MagickException { 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; if (width > 660) { height = 660 * height / width; width = 660; } sImage = fImage.scaleImage(width, height); fLogo = new MagickImage(new ImageInfo(logoPath)); logoDim = fLogo.getDimension(); int lw = width / 8; int lh = logoDim.height * lw / logoDim.width; sLogo = fLogo.scaleImage(lw, lh); sImage.compositeImage(CompositeOperator.AtopCompositeOp, sLogo, width-(lw + lh/10), height-(lh + lh/10)); sImage.setFileName(toImg); sImage.writeImage(info); } finally { if(sImage != null){ sImage.destroyImages(); } } } /** * 水印(文字) * @param filePath 源文件路径 * @param toImg 修改图路径 * @param text 名字(文字内容自己随意) * @throws MagickException */ public static void initTextToImg(String filePath, String toImg, String text) throws MagickException{ 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 wideth = imageDim.width; int height = imageDim.height; if (wideth > 660) { height = 660 * height / wideth; wideth = 660; } 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 + 300; MagickImage scaled = aImage.scaleImage(wideth, height); if(wideth > tl && height > 5){ DrawInfo aInfo = new DrawInfo(info); aInfo.setFill(PixelPacket.queryColorDatabase("white")); aInfo.setUnderColor(new PixelPacket(0,0,0,100)); aInfo.setPointsize(12); //解决中文乱码问题,自己可以去随意定义个自己喜欢字体,我在这用的微软雅黑 String fontPath = "C:/WINDOWS/Fonts/MSYH.TTF"; // String fontPath = "/usr/maindata/MSYH.TTF"; aInfo.setFont(fontPath); aInfo.setTextAntialias(true); aInfo.setOpacity(0); aInfo.setText(" " + text + "于 " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + " 上传于XXXX网,版权归作者所有!"); aInfo.setGeometry("+" + (wideth-tl) + "+" + (height-5)); scaled.annotateImage(aInfo); } scaled.setFileName(toImg); scaled.writeImage(info); scaled.destroyImages(); } /** * 切图 * @param imgPath 源图路径 * @param toPath 修改图路径 * @param w * @param h * @param x * @param y * @throws MagickException */ 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(); } } } }
- 其次自己写java代码:
package org.uup.web; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; /** * 图像压缩工具 * @author lhj * */ public class ImageSizer { /** * 压缩图片方法 * * @param oldFile 将要压缩的图片 * @param width 不能超过的最大压缩宽 * @param height 不能超过的最大压缩长 * @param quality 压缩清晰度 <b>建议为1.0</b> * @param smallIcon 压缩图片后,添加的扩展名 * @return * @throws IOException */ public static void imageZip(File oldFile, File destFile, String format, int maxWidth, int maxHeight, float quality) throws IOException { FileOutputStream out = null; try { // 文件不存在时 if (!oldFile.exists()) return; /** 对服务器上的临时文件进行处理 */ Image srcFile = ImageIO.read(oldFile); int new_w = 0, new_h = 0; // 获取图片的实际大小 高度 int h = (int) srcFile.getHeight(null); // 获取图片的实际大小 宽度 int w = (int) srcFile.getWidth(null); // 为等比缩放计算输出的图片宽度及高度 if ((((double) w) > (double) maxWidth) || (((double) h) > (double) maxHeight)) { // 为等比缩放计算输出的图片宽度及高度 double rateW = ((double) srcFile.getWidth(null)) / (double) maxWidth * 1.0; double rateH = ((double) srcFile.getHeight(null)) / (double) maxHeight * 1.0; // 根据缩放比率大的进行缩放控制 //double rate = rateW > rateH ? rateW : rateH; double rate; char zipType; if(rateW > rateH){ rate = rateW; zipType = 'W'; } else { rate = rateH; zipType = 'H'; } new_w = (int) (((double) srcFile.getWidth(null)) / rate); new_h = (int) (((double) srcFile.getHeight(null)) / rate); double rate2 = 0; if(zipType == 'W' && new_h > maxHeight){ rate = (double) new_h / (double) maxHeight * 1.0; } else if(zipType == 'H' && new_w > maxWidth){ rate = (double) new_w / (double) maxWidth * 1.0; } if(rate2 != 0){ new_w = (int) (((double) new_w) / rate); new_h = (int) (((double) new_h) / rate); System.out.println("2次修改宽高。"); } } else { new_w = w; new_h = h; } if ( new_w < 1 ) throw new IllegalArgumentException( "image width " + new_w + " is out of range" ); if ( new_h < 1 ) throw new IllegalArgumentException( "image height " + new_h + " is out of range" ); /** 宽,高设定 */ BufferedImage tag = new BufferedImage(new_w, new_h, BufferedImage.TYPE_INT_RGB); tag.getGraphics().drawImage(srcFile, 0, 0, new_w, new_h, null); out = new FileOutputStream(destFile); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(tag); /** 压缩质量 */ jep.setQuality(quality, true); encoder.encode(tag, jep); out.close(); srcFile.flush(); } finally{ if(out != null)out.close(); } } public static final MediaTracker tracker = new MediaTracker(new Component() { private static final long serialVersionUID = 1234162663955668507L;} ); /**方法二
* @param originalFile 原图像 * @param resizedFile 压缩后的图像 * @param width 图像宽 * @param format 图片格式 jpg, png, gif(非动画) * @throws IOException */ public static void resize(File originalFile, File resizedFile, int width, String format) throws IOException { FileInputStream fis = null; ByteArrayOutputStream byteStream = null; try{ if(format!=null && "gif".equals(format.toLowerCase())){ resize(originalFile, resizedFile, width, 1); return; } fis = new FileInputStream(originalFile); byteStream = new ByteArrayOutputStream(); int readLength = -1; int bufferSize = 1024; byte bytes[] = new byte[bufferSize]; while ((readLength = fis.read(bytes, 0, bufferSize)) != -1) { byteStream.write(bytes, 0, readLength); } byte[] in = byteStream.toByteArray(); fis.close(); byteStream.close(); Image inputImage = Toolkit.getDefaultToolkit().createImage( in ); waitForImage( inputImage ); int imageWidth = inputImage.getWidth( null ); if ( imageWidth < 1 ) throw new IllegalArgumentException( "image width " + imageWidth + " is out of range" ); int imageHeight = inputImage.getHeight( null ); if ( imageHeight < 1 ) throw new IllegalArgumentException( "image height " + imageHeight + " is out of range" ); // Create output image. int height = -1; double scaleW = (double) imageWidth / (double) width; double scaleY = (double) imageHeight / (double) height; if (scaleW >= 0 && scaleY >=0) { if (scaleW > scaleY) { height = -1; } else { width = -1; } } Image outputImage = inputImage.getScaledInstance( width, height, java.awt.Image.SCALE_DEFAULT); checkImage( outputImage ); encode(new FileOutputStream(resizedFile), outputImage, format); }finally{ try { if(byteStream != null) { byteStream.close(); } if(fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** Checks the given image for valid width and height. */ private static void checkImage( Image image ) { waitForImage( image ); int imageWidth = image.getWidth( null ); if ( imageWidth < 1 ) throw new IllegalArgumentException( "image width " + imageWidth + " is out of range" ); int imageHeight = image.getHeight( null ); if ( imageHeight < 1 ) throw new IllegalArgumentException( "image height " + imageHeight + " is out of range" ); } /** Waits for given image to load. Use before querying image height/width/colors. */ private static void waitForImage( Image image ) { try { tracker.addImage( image, 0 ); tracker.waitForID( 0 ); tracker.removeImage(image, 0); } catch( InterruptedException e ) { e.printStackTrace(); } } /** Encodes the given image at the given quality to the output stream. */ private static void encode( OutputStream outputStream, Image outputImage, String format ) throws java.io.IOException { try { int outputWidth = outputImage.getWidth( null ); if ( outputWidth < 1 ) throw new IllegalArgumentException( "output image width " + outputWidth + " is out of range" ); int outputHeight = outputImage.getHeight( null ); if ( outputHeight < 1 ) throw new IllegalArgumentException( "output image height " + outputHeight + " is out of range" ); // Get a buffered image from the image. BufferedImage bi = new BufferedImage( outputWidth, outputHeight, BufferedImage.TYPE_INT_RGB ); Graphics2D biContext = bi.createGraphics(); biContext.drawImage( outputImage, 0, 0, null ); ImageIO.write(bi, format, outputStream); outputStream.flush(); }finally{ if(outputStream != null) { outputStream.close(); } } } /** * 缩放gif图片 * @param originalFile 原图片 * @param resizedFile 缩放后的图片 * @param newWidth 宽度 * @param quality 缩放比例 (等比例) * @throws IOException */ private static void resize(File originalFile, File resizedFile, int newWidth, float quality) throws IOException { if (quality < 0 || quality > 1) { throw new IllegalArgumentException("Quality has to be between 0 and 1"); } ImageIcon ii = new ImageIcon(originalFile.getCanonicalPath()); Image i = ii.getImage(); Image resizedImage = null; int iWidth = i.getWidth(null); int iHeight = i.getHeight(null); if (iWidth > iHeight) { resizedImage = i.getScaledInstance(newWidth, (newWidth * iHeight) / iWidth, Image.SCALE_SMOOTH); } else { resizedImage = i.getScaledInstance((newWidth * iWidth) / iHeight, newWidth, Image.SCALE_SMOOTH); } // This code ensures that all the pixels in the image are loaded. Image temp = new ImageIcon(resizedImage).getImage(); // Create the buffered image. BufferedImage bufferedImage = new BufferedImage(temp.getWidth(null), temp.getHeight(null), BufferedImage.TYPE_INT_RGB); // Copy image to buffered image. Graphics g = bufferedImage.createGraphics(); // Clear background and paint the image. g.setColor(Color.white); g.fillRect(0, 0, temp.getWidth(null), temp.getHeight(null)); g.drawImage(temp, 0, 0, null); g.dispose(); // Soften. float softenFactor = 0.05f; float[] softenArray = {0, softenFactor, 0, softenFactor, 1-(softenFactor*4), softenFactor, 0, softenFactor, 0}; Kernel kernel = new Kernel(3, 3, softenArray); ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); bufferedImage = cOp.filter(bufferedImage, null); // Write the jpeg to a file. FileOutputStream out = new FileOutputStream(resizedFile); // Encodes image as a JPEG data stream JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bufferedImage); param.setQuality(quality, true); encoder.setJPEGEncodeParam(param); encoder.encode(bufferedImage); } /** * 图片缩放(图片等比例缩放为指定大小,空白部分以白色填充) * * @param srcBufferedImage 源图片 * @param destFile缩放后的图片文件 * @param destHeight * @param destWidth */ public static void zoom(BufferedImage srcBufferedImage, File destFile, String format, int destHeight, int destWidth) { try { int imgWidth = destWidth; int imgHeight = destHeight; int srcWidth = srcBufferedImage.getWidth(); int srcHeight = srcBufferedImage.getHeight(); double scaleW = destWidth * 1.0 / srcWidth; double scaleH = destHeight * 1.0 / srcHeight; if (scaleW >= scaleH) { double imgWidth1 = scaleH * srcWidth; double imgHeight1 = scaleH * srcHeight; imgWidth = (int)imgWidth1; imgHeight = (int)imgHeight1; } else { double imgWidth1 = scaleW * srcWidth; double imgHeight1 = scaleW * srcHeight; imgWidth = (int)imgWidth1; imgHeight = (int)imgHeight1; } BufferedImage destBufferedImage = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = destBufferedImage.createGraphics(); graphics2D.setBackground(Color.WHITE); graphics2D.clearRect(0, 0, destWidth, destHeight); graphics2D.drawImage(srcBufferedImage.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), (destWidth / 2) - (imgWidth / 2), (destHeight / 2) - (imgHeight / 2), null); graphics2D.dispose(); ImageIO.write(destBufferedImage, format, destFile); } catch (IOException e) { e.printStackTrace(); } } }