Java工具类——实现gif图片缩放与剪切功能

比较实用, 能够处理gif动态图片

Java图片处理工具类:html

[java]  view plain  copy
  在CODE上查看代码片 派生到个人代码片
  1. package com.pinker.util;  
  2. import java.awt.Color;  
  3. import java.awt.Graphics;  
  4. import java.awt.Image;  
  5. import java.awt.image.BufferedImage;  
  6. import java.io.File;  
  7. import java.io.IOException;  
  8. import java.util.Arrays;  
  9. import java.util.Iterator;  
  10.   
  11. import javax.imageio.IIOImage;  
  12. import javax.imageio.ImageIO;  
  13. import javax.imageio.ImageReader;  
  14. import javax.imageio.ImageWriter;  
  15. import javax.imageio.stream.ImageInputStream;  
  16. import javax.imageio.stream.ImageOutputStream;  
  17.    
  18. /** 
  19.  * 图像裁剪以及压缩处理工具类 
  20.  * 
  21.  * 主要针对动态的GIF格式图片裁剪以后,只出现一帧动态效果的现象提供解决方案 
  22.  * 
  23.  * 提供依赖三方包解决方案(针对GIF格式数据特征一一解析,进行编码解码操做) 
  24.  * 提供基于JDK Image I/O 的解决方案(JDK探索失败) 
  25.  */  
  26. public class ImageUtil2 {  
  27.    
  28.     public enum IMAGE_FORMAT{  
  29.         BMP("bmp"),  
  30.         JPG("jpg"),  
  31.         WBMP("wbmp"),  
  32.         JPEG("jpeg"),  
  33.         PNG("png"),  
  34.         GIF("gif");  
  35.            
  36.         private String value;  
  37.         IMAGE_FORMAT(String value){  
  38.             this.value = value;  
  39.         }  
  40.         public String getValue() {  
  41.             return value;  
  42.         }  
  43.         public void setValue(String value) {  
  44.             this.value = value;  
  45.         }  
  46.     }  
  47.        
  48.        
  49.     /** 
  50.      * 获取图片格式 
  51.      * @param file   图片文件 
  52.      * @return    图片格式 
  53.      */  
  54.     public static String getImageFormatName(File file)throws IOException{  
  55.         String formatName = null;  
  56.            
  57.         ImageInputStream iis = ImageIO.createImageInputStream(file);  
  58.         Iterator<ImageReader> imageReader =  ImageIO.getImageReaders(iis);  
  59.         if(imageReader.hasNext()){  
  60.             ImageReader reader = imageReader.next();  
  61.             formatName = reader.getFormatName();  
  62.         }  
  63.    
  64.         return formatName;  
  65.     }  
  66.        
  67.     /*************************  基于三方包解决方案    *****************************/  
  68.     /** 
  69.      * 剪切图片 
  70.      * 
  71.      * @param source        待剪切图片路径 
  72.      * @param targetPath    裁剪后保存路径(默认为源路径) 
  73.      * @param x                起始横坐标 
  74.      * @param y                起始纵坐标 
  75.      * @param width            剪切宽度 
  76.      * @param height        剪切高度          
  77.      * 
  78.      * @returns            裁剪后保存路径(图片后缀根据图片自己类型生成)     
  79.      * @throws IOException 
  80.      */  
  81.     public static String cutImage(String sourcePath , String targetPath , int x , int y , int width , int height) throws IOException{  
  82.         File file = new File(sourcePath);  
  83.         if(!file.exists()) {  
  84.             throw new IOException("not found the image:" + sourcePath);  
  85.         }  
  86.         if(null == targetPath || targetPath.isEmpty()) targetPath = sourcePath;  
  87.            
  88.         String formatName = getImageFormatName(file);  
  89.         if(null == formatName) return targetPath;  
  90.         formatName = formatName.toLowerCase();  
  91.            
  92.         // 防止图片后缀与图片自己类型不一致的状况  
  93.         String pathPrefix = getPathWithoutSuffix(targetPath);  
  94.         targetPath = pathPrefix + formatName;  
  95.            
  96.         // GIF须要特殊处理  
  97.         if(IMAGE_FORMAT.GIF.getValue() == formatName){  
  98.             GifDecoder decoder = new GifDecoder();    
  99.             int status = decoder.read(sourcePath);    
  100.             if (status != GifDecoder.STATUS_OK) {    
  101.                 throw new IOException("read image " + sourcePath + " error!");    
  102.             }  
  103.    
  104.             AnimatedGifEncoder encoder = new AnimatedGifEncoder();  
  105.             encoder.start(targetPath);  
  106.             encoder.setRepeat(decoder.getLoopCount());    
  107.             for (int i = 0; i < decoder.getFrameCount(); i ++) {    
  108.                 encoder.setDelay(decoder.getDelay(i));    
  109.                 BufferedImage childImage = decoder.getFrame(i);  
  110.                 BufferedImage image = childImage.getSubimage(x, y, width, height);  
  111.                 encoder.addFrame(image);    
  112.             }    
  113.             encoder.finish();  
  114.         }else{  
  115.             BufferedImage image = ImageIO.read(file);  
  116.             image = image.getSubimage(x, y, width, height);  
  117.             ImageIO.write(image, formatName, new File(targetPath));  
  118.         }  
  119.         //普通图片  
  120.         BufferedImage image = ImageIO.read(file);  
  121.         image = image.getSubimage(x, y, width, height);  
  122.         ImageIO.write(image, formatName, new File(targetPath));  
  123.           
  124.         return targetPath;  
  125.     }  
  126.        
  127.     /** 
  128.      * 压缩图片 
  129.      * @param sourcePath       待压缩的图片路径 
  130.      * @param targetPath    压缩后图片路径(默认为初始路径) 
  131.      * @param width            压缩宽度 
  132.      * @param height        压缩高度 
  133.      * 
  134.      * @returns                   裁剪后保存路径(图片后缀根据图片自己类型生成)     
  135.      * @throws IOException 
  136.      */  
  137.     public static String zoom(String sourcePath , String targetPath, int width , int height) throws IOException{  
  138.         File file = new File(sourcePath);  
  139.         if(!file.exists()) {  
  140.             throw new IOException("not found the image :" + sourcePath);  
  141.         }  
  142.         if(null == targetPath || targetPath.isEmpty()) targetPath = sourcePath;  
  143.            
  144.         String formatName = getImageFormatName(file);  
  145.         if(null == formatName) return targetPath;  
  146.         formatName = formatName.toLowerCase();  
  147.            
  148.         // 防止图片后缀与图片自己类型不一致的状况  
  149.         String pathPrefix = getPathWithoutSuffix(targetPath);  
  150.         targetPath = pathPrefix + formatName;  
  151.            
  152.         // GIF须要特殊处理  
  153.         if(IMAGE_FORMAT.GIF.getValue() == formatName){  
  154.             GifDecoder decoder = new GifDecoder();    
  155.             int status = decoder.read(sourcePath);    
  156.             if (status != GifDecoder.STATUS_OK) {    
  157.                 throw new IOException("read image " + sourcePath + " error!");    
  158.             }  
  159.    
  160.             AnimatedGifEncoder encoder = new AnimatedGifEncoder();  
  161.             encoder.start(targetPath);  
  162.             encoder.setRepeat(decoder.getLoopCount());    
  163.             for (int i = 0; i < decoder.getFrameCount(); i ++) {    
  164.                 encoder.setDelay(decoder.getDelay(i));    
  165.                 BufferedImage image = zoom(decoder.getFrame(i), width , height);  
  166.                 encoder.addFrame(image);    
  167.             }    
  168.             encoder.finish();  
  169.         }else{  
  170.             BufferedImage image = ImageIO.read(file);  
  171.             BufferedImage zoomImage = zoom(image , width , height);  
  172.             ImageIO.write(zoomImage, formatName, new File(targetPath));  
  173.         }  
  174.         BufferedImage image = ImageIO.read(file);  
  175.         BufferedImage zoomImage = zoom(image , width , height);  
  176.         ImageIO.write(zoomImage, formatName, new File(targetPath));  
  177.            
  178.         return targetPath;  
  179.     }  
  180.        
  181.     /*********************** 基于JDK 解决方案     ********************************/  
  182.        
  183.     /** 
  184.      * 读取图片 
  185.      * @param file 图片文件 
  186.      * @return     图片数据 
  187.      * @throws IOException 
  188.      */  
  189.     public static BufferedImage[] readerImage(File file) throws IOException{  
  190.         BufferedImage sourceImage = ImageIO.read(file);  
  191.         BufferedImage[] images = null;  
  192.         ImageInputStream iis = ImageIO.createImageInputStream(file);  
  193.         Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(iis);  
  194.         if(imageReaders.hasNext()){  
  195.             ImageReader reader = imageReaders.next();  
  196.             reader.setInput(iis);  
  197.             int imageNumber = reader.getNumImages(true);  
  198.             images = new BufferedImage[imageNumber];  
  199.             for (int i = 0; i < imageNumber; i++) {  
  200.                 BufferedImage image = reader.read(i);  
  201.                 if(sourceImage.getWidth() > image.getWidth() || sourceImage.getHeight() > image.getHeight()){  
  202.                     image = zoom(image, sourceImage.getWidth(), sourceImage.getHeight());  
  203.                 }  
  204.                 images[i] = image;  
  205.             }  
  206.             reader.dispose();  
  207.             iis.close();  
  208.         }  
  209.         return images;  
  210.     }  
  211.        
  212.     /** 
  213.      * 根据要求处理图片 
  214.      * 
  215.      * @param images    图片数组 
  216.      * @param x            横向起始位置 
  217.      * @param y         纵向起始位置 
  218.      * @param width      宽度     
  219.      * @param height    宽度 
  220.      * @return            处理后的图片数组 
  221.      * @throws Exception 
  222.      */  
  223.     public static BufferedImage[] processImage(BufferedImage[] images , int x , int y , int width , int height) throws Exception{  
  224.         if(null == images){  
  225.             return images;  
  226.         }  
  227.         BufferedImage[] oldImages = images;  
  228.         images = new BufferedImage[images.length];  
  229.         for (int i = 0; i < oldImages.length; i++) {  
  230.             BufferedImage image = oldImages[i];  
  231.             images[i] = image.getSubimage(x, y, width, height);  
  232.         }  
  233.         return images;  
  234.     }  
  235.        
  236.     /** 
  237.      * 写入处理后的图片到file 
  238.      * 
  239.      * 图片后缀根据图片格式生成 
  240.      * 
  241.      * @param images        处理后的图片数据 
  242.      * @param formatName     图片格式 
  243.      * @param file            写入文件对象 
  244.      * @throws Exception 
  245.      */  
  246.     public static void writerImage(BufferedImage[] images ,  String formatName , File file) throws Exception{  
  247.         Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName(formatName);  
  248.         if(imageWriters.hasNext()){  
  249.             ImageWriter writer = imageWriters.next();  
  250.             String fileName = file.getName();  
  251.             int index = fileName.lastIndexOf(".");  
  252.             if(index > 0){  
  253.                 fileName = fileName.substring(0, index + 1) + formatName;  
  254.             }  
  255.             String pathPrefix = getFilePrefixPath(file.getPath());  
  256.             File outFile = new File(pathPrefix + fileName);  
  257.             ImageOutputStream ios = ImageIO.createImageOutputStream(outFile);  
  258.             writer.setOutput(ios);  
  259.                
  260.             if(writer.canWriteSequence()){  
  261.                 writer.prepareWriteSequence(null);  
  262.                 for (int i = 0; i < images.length; i++) {  
  263.                     BufferedImage childImage = images[i];  
  264.                     IIOImage image = new IIOImage(childImage, null , null);  
  265.                     writer.writeToSequence(image, null);  
  266.                 }  
  267.                 writer.endWriteSequence();  
  268.             }else{  
  269.                 for (int i = 0; i < images.length; i++) {  
  270.                     writer.write(images[i]);  
  271.                 }  
  272.             }  
  273.                
  274.             writer.dispose();  
  275.             ios.close();  
  276.         }  
  277.     }  
  278.        
  279.     /** 
  280.      * 剪切格式图片 
  281.      * 
  282.      * 基于JDK Image I/O解决方案 
  283.      * 
  284.      * @param sourceFile        待剪切图片文件对象 
  285.      * @param destFile                  裁剪后保存文件对象 
  286.      * @param x                    剪切横向起始位置 
  287.      * @param y                 剪切纵向起始位置 
  288.      * @param width              剪切宽度     
  289.      * @param height            剪切宽度 
  290.      * @throws Exception 
  291.      */  
  292.     public static void cutImage(File sourceFile , File destFile, int x , int y , int width , int height) throws Exception{  
  293.         // 读取图片信息  
  294.         BufferedImage[] images = readerImage(sourceFile);  
  295.         // 处理图片  
  296.         images = processImage(images, x, y, width, height);  
  297.         // 获取文件后缀  
  298.         String formatName = getImageFormatName(sourceFile);  
  299.         destFile = new File(getPathWithoutSuffix(destFile.getPath()) + formatName);  
  300.    
  301.         // 写入处理后的图片到文件  
  302.         writerImage(images, formatName , destFile);  
  303.     }  
  304.        
  305.        
  306.        
  307.     /** 
  308.      * 获取系统支持的图片格式 
  309.      */  
  310.     public static void getOSSupportsStandardImageFormat(){  
  311.         String[] readerFormatName = ImageIO.getReaderFormatNames();  
  312.         String[] readerSuffixName = ImageIO.getReaderFileSuffixes();  
  313.         String[] readerMIMEType = ImageIO.getReaderMIMETypes();  
  314.         System.out.println("========================= OS supports reader ========================");  
  315.         System.out.println("OS supports reader format name :  " + Arrays.asList(readerFormatName));  
  316.         System.out.println("OS supports reader suffix name :  " + Arrays.asList(readerSuffixName));  
  317.         System.out.println("OS supports reader MIME type :  " + Arrays.asList(readerMIMEType));  
  318.            
  319.         String[] writerFormatName = ImageIO.getWriterFormatNames();  
  320.         String[] writerSuffixName = ImageIO.getWriterFileSuffixes();  
  321.         String[] writerMIMEType = ImageIO.getWriterMIMETypes();  
  322.            
  323.         System.out.println("========================= OS supports writer ========================");  
  324.         System.out.println("OS supports writer format name :  " + Arrays.asList(writerFormatName));  
  325.         System.out.println("OS supports writer suffix name :  " + Arrays.asList(writerSuffixName));  
  326.         System.out.println("OS supports writer MIME type :  " + Arrays.asList(writerMIMEType));  
  327.     }  
  328.        
  329.     /** 
  330.      * 压缩图片 
  331.      * @param sourceImage    待压缩图片 
  332.      * @param width          压缩图片高度 
  333.      * @param heigt          压缩图片宽度 
  334.      */  
  335.     private static BufferedImage zoom(BufferedImage sourceImage , int width , int height){  
  336.         BufferedImage zoomImage = new BufferedImage(width, height, sourceImage.getType());  
  337.         Image image = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);  
  338.         Graphics gc = zoomImage.getGraphics();  
  339.         gc.setColor(Color.WHITE);  
  340.         gc.drawImage( image , 00null);  
  341.         return zoomImage;  
  342.     }  
  343.        
  344.     /** 
  345.      * 获取某个文件的前缀路径 
  346.      * 
  347.      * 不包含文件名的路径 
  348.      * 
  349.      * @param file   当前文件对象 
  350.      * @return 
  351.      * @throws IOException 
  352.      */  
  353.     public static String getFilePrefixPath(File file) throws IOException{  
  354.         String path = null;  
  355.         if(!file.exists()) {  
  356.             throw new IOException("not found the file !" );  
  357.         }  
  358.         String fileName = file.getName();  
  359.         path = file.getPath().replace(fileName, "");  
  360.         return path;  
  361.     }  
  362.        
  363.     /** 
  364.      * 获取某个文件的前缀路径 
  365.      * 
  366.      * 不包含文件名的路径 
  367.      * 
  368.      * @param path   当前文件路径 
  369.      * @return       不包含文件名的路径 
  370.      * @throws Exception 
  371.      */  
  372.     public static String getFilePrefixPath(String path) throws Exception{  
  373.         if(null == path || path.isEmpty()) throw new Exception("文件路径为空!");  
  374.         int index = path.lastIndexOf(File.separator);  
  375.         if(index > 0){  
  376.             path = path.substring(0, index + 1);  
  377.         }  
  378.         return path;  
  379.     }  
  380.        
  381.     /** 
  382.      * 获取不包含后缀的文件路径 
  383.      * 
  384.      * @param src 
  385.      * @return 
  386.      */  
  387.     public static String getPathWithoutSuffix(String src){  
  388.         String path = src;  
  389.         int index = path.lastIndexOf(".");  
  390.         if(index > 0){  
  391.             path = path.substring(0, index + 1);  
  392.         }  
  393.         return path;  
  394.     }  
  395.        
  396.     /** 
  397.      * 获取文件名 
  398.      * @param filePath        文件路径 
  399.      * @return                文件名 
  400.      * @throws IOException 
  401.      */  
  402.     public static String getFileName(String filePath) throws IOException{  
  403.         File file = new File(filePath);  
  404.         if(!file.exists()) {  
  405.             throw new IOException("not found the file !" );  
  406.         }  
  407.         return file.getName();  
  408.     }  
  409.        
  410.     /** 
  411.      * @param args 
  412.      * @throws Exception 
  413.      */  
  414.     public static void main(String[] args) throws Exception {  
  415.         // 获取系统支持的图片格式  
  416.         //ImageCutterUtil.getOSSupportsStandardImageFormat();  
  417.            
  418.         try {  
  419.             // 起始坐标,剪切大小  
  420.             int x = 100;  
  421.             int y = 75;  
  422.             int width = 100;  
  423.             int height = 100;  
  424.             // 参考图像大小  
  425.             int clientWidth = 300;  
  426.             int clientHeight = 250;  
  427.                
  428.                
  429.             File file = new File("C:\\1.jpg");  
  430.             BufferedImage image = ImageIO.read(file);  
  431.             double destWidth = image.getWidth();  
  432.             double destHeight = image.getHeight();  
  433.                
  434.             if(destWidth < width || destHeight < height)  
  435.                 throw new Exception("源图大小小于截取图片大小!");  
  436.                
  437.             double widthRatio = destWidth / clientWidth;  
  438.             double heightRatio = destHeight / clientHeight;  
  439.                
  440.             x = Double.valueOf(x * widthRatio).intValue();  
  441.             y = Double.valueOf(y * heightRatio).intValue();  
  442.             width = Double.valueOf(width * widthRatio).intValue();  
  443.             height = Double.valueOf(height * heightRatio).intValue();  
  444.                
  445.             System.out.println("裁剪大小  x:" + x + ",y:" + y + ",width:" + width + ",height:" + height);  
  446.    
  447.             /************************ 基于三方包解决方案 *************************/  
  448.             String formatName = getImageFormatName(file);  
  449.             String pathSuffix = "." + formatName;  
  450.             String pathPrefix = getFilePrefixPath(file);  
  451.             String targetPath = pathPrefix  + System.currentTimeMillis() + pathSuffix;  
  452.             targetPath = ImageUtil2.cutImage(file.getPath(), targetPath, x , y , width, height);  
  453.                
  454.             String bigTargetPath = pathPrefix  + System.currentTimeMillis() + pathSuffix;  
  455.             ImageUtil2.zoom(targetPath, bigTargetPath, 100100);  
  456.                
  457.             String smallTargetPath = pathPrefix  + System.currentTimeMillis() + pathSuffix;  
  458.             ImageUtil2.zoom(targetPath, smallTargetPath, 5050);  
  459.                
  460.             /************************ 基于JDK Image I/O 解决方案(JDK探索失败) *************************/  
  461. //              File destFile = new File(targetPath);  
  462. //              ImageCutterUtil.cutImage(file, destFile, x, y, width, height);  
  463.         } catch (IOException e) {  
  464.             e.printStackTrace();  
  465.         }  
  466.     }  
  467. }  

转自【http://www.open-open.com/lib/view/open1394859355853.html】