JAVA实现gif图片缩放与剪切功能

  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. }  
  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓