Java图片压缩

最近发现网站传的图片很多都是直接使用相机照的,很多图片都非常大,这样占用空间,而且用户加载也会变慢,所以搞了一下压缩图片的方法,但是网上很多都只有JPG的压缩方式,PNG的很少。这里也记录一下。

我们用PS把PNG转为网络图片我们一般会讲PNG24转为PNG8,这里也是我的思路。下面贴上代码:

public static final String PNG_EXTENSION = "png";
public static final String JPG_EXTENSION = "jpg";
 
public static boolean compress(String filePath) {
    File file = StringUtils.isEmpty(filePath) ? null : new File(filePath);
    if(!file.exists() || !file.isFile()) {
        return false;
    }
    Graphics2D graphics2D = null;
    ImageWriter imageWriter = null;
    ImageWriteParam imageWriteParams = null;
    FileOutputStream fileOutputStream = null;
    try {
        String extension = Tools.getFileExt(filePath);
        imageWriter = ImageIO.getImageWritersByFormatName(extension).next();
        if(PNG_EXTENSION.equals(extension.toLowerCase())) {
            BufferedImage srcBufferedImage = ImageIO.read(file);
            int width = srcBufferedImage.getWidth();
            int height = srcBufferedImage.getHeight();
            BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_555_RGB);
            graphics2D = newBufferedImage.createGraphics();
            graphics2D.setBackground(BACKGROUND_COLOR);
            graphics2D.clearRect(0, 0, width, height);
            graphics2D.drawImage(srcBufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
            imageWriter = ImageIO.getImageWritersByFormatName(extension).next();
            fileOutputStream = new FileOutputStream(filePath);
            imageWriter.setOutput(ImageIO.createImageOutputStream(fileOutputStream));
            imageWriter.write(new IIOImage(newBufferedImage, null, null));
            fileOutputStream.flush();
        } else if(JPG_EXTENSION.equals(extension.toLowerCase())) {
            BufferedImage srcBufferedImage = ImageIO.read(new File(filePath));
            imageWriteParams = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(null);
            imageWriteParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            imageWriteParams.setCompressionQuality(0.8F);
            imageWriteParams.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
            ColorModel colorModel = ImageIO.read(new File(filePath)).getColorModel();
            imageWriteParams.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
            fileOutputStream = new FileOutputStream(file);
            imageWriter.setOutput(ImageIO.createImageOutputStream(fileOutputStream));
            imageWriter.write(null, new IIOImage(srcBufferedImage, null, null), imageWriteParams);
            fileOutputStream.flush();
        }
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    } finally {
        if(imageWriter != null)
            imageWriter.abort();
        IOUtils.closeQuietly(fileOutputStream);
    }
    return true;
}

下面是PNG的几种模式的对比TYPE_USHORT_555_RGBTYPE_INT_RGB(这个相当于PNG24),TYPE_BYTE_INDEXED(相当于PNG8)}。

原始图片:411KB

Java图片压缩

TYPE_BYTE_INDEXED处理后:139KB

Java图片压缩

TYPE_USHORT_555_RGB处理后:218KB

Java图片压缩

TYPE_INT_RGB处理后:532KB

Java图片压缩

PS处理后:127KB

Java图片压缩

仔细看原始图片和TYPE_INT_RGB是最好的,其次是TYPE_USHORT_555_RGB,然后是PS,最后是TYPE_BYTE_INDEXED。(仔细看丝袜部分,能看出来)考虑到大小和质量所以使用TYPE_USHORT_555_RGB

参考文章:
http://fandayrockworld.iteye.com/blog/628551
http://blog.csdn.net/monitor1394/article/details/6087583

注:这里主要处理PNG和JPG的图片,其他图片很少也不处理。还有就是一般都是RGB的颜色,有的PS的CMYK模式的会出问题。
还有就是Tools.getFileExt(filePath);这个是获取图片真实的格式,有的图片是PNG的格式但是却把后缀写成了JPG,这里防止这样的问题出现,具体问题参考文章:http://www.acgist.com/article/134.html