JAVA 图片压缩踩坑记

1,842 阅读3分钟

JAVA 图片压缩踩坑记

最近公司需要重新梳理一下文件上传相关的工作,然后对用户上传的图片相关的东西做一下压缩吧,节省下带宽。

然后的话,发现很多图片处理都是只压缩 JPG 格式的,没有对 PNG 图片压缩做处理,但是看网上又有比较多的PNG在线压缩网站,不过 JAVA 好像 对 PNG 压缩实现好像不是特别多。

想找找看有没有一个类似于 tinypng 可以在 JAVA 中压缩 PNG 的通用图片压缩。

所以找了下解决方案,在这里做个记录

1. Thumbnails 的坑

首先我直接引用了 Google 的 Thumbnails来做,官网上宣称压缩 jpg png 格式都可以,然后我随便找了几张图片试了下,发现并不行,最主要的问题是会把 png 格式的图片越压缩越大。

public static void main(String[] args) throws Exception {  
    Thumbnails.Builder builder = Thumbnails.of(new File("E:\\壁纸\\expert.png"))  
    .outputQuality(0.6f);  
    builder.scale(1);  
    builder.imageType(BufferedImage.TYPE_INT_ARGB);  
    builder.toFile(new File("E:\\壁纸\\expert22.png"));  
}

image.png

image.png

可以看到压缩 png 不仅没有让图片变小,反而反向压缩了,从原来的 47k 压缩到了 80k

具体可以看看这个 issuse github.com/coobird/thu…

2. 解决方案

网上找了下解决方案,大概有两个

  1. 使用pdf渲染的开源软件OpenViewerFX, 这个里面包含类似 tinypng 压缩算法的图片压缩
  2. 使用 java-png-compress-util 大神做好的使用 libimagequant 依赖库,使用java JNI调用实现对PNG图片进行压缩

考虑到不同环境差异,决定还是依赖 OpenViewerFX 来做 png 的图片压缩

参考 java png 图片压缩

3. 测试 OpenViewerFX

先试试原来的 expert22.png

public static void main(String[] args) throws Exception {  
    File file = new File("E:\\壁纸\\expert22.png");  
    PngCompressor.compress(file, file);  
}

image.png

em..., 好吧好像没有变化,可能是图片已经够小的原因。不过没有像 Thumbnails 反向压缩了,那换一张图片试试

image.png

image.png

嗯,可以看到还是有效果的,直接压缩了 100多K

4. 代码实现

  1. 引入依赖

<dependency>  
    <groupId>net.coobird</groupId>  
    <artifactId>thumbnailator</artifactId>  
    <version>0.4.20</version>  
</dependency>  
  
<!-- https://mvnrepository.com/artifact/org.jpedal/OpenViewerFX -->  
<dependency>  
    <groupId>org.jpedal</groupId>  
    <artifactId>OpenViewerFX</artifactId>  
    <version>6.6.14</version>  
</dependency>

需要注意 OpenViewerFX 的版本,高版本的 OpenViewerFX 已经没有 PngCompressor 类了,具体版本变化没仔细去研究了

  1. 图片压缩具体实现
/**  
* 图片压缩  
* @param file 图片地址  
* @param extension 后缀名  
*/
public void compressFile(File file, String extension) {  
    try {  
        if (!extension.matches("jpg|jpeg|png|gif|bmp")) {  
            return;  
        }  
        BufferedImage bufferedImage = ImageIO.read(file);  
        int width = bufferedImage.getWidth();  
        int height = bufferedImage.getHeight();  
        Thumbnails.Builder builder = Thumbnails.of(file)  
        .outputQuality(0.6f);  
        // 如果图片大于 1k 则重置为 1k 图片
        if (width > 1920 || height > 1080) {  
            builder.size(GlobalFile.LIMIT_WIDTH, GlobalFile.LIMIT_HEIGHT);  
        } else {  
            builder.scale(1);  
        }
        // 如果是 png 则使用 TYPE_INT_ARGB 模式
        if (extension != null && extension.equals("png")) {  
            builder.imageType(BufferedImage.TYPE_INT_ARGB);  
        }  
        builder.toFile(file);
        // 如果图片是 png 则使用 OpenViewerFX 中的 PngCompressor 进行压缩
        if (extension != null && extension.equals("png")) {  
            PngCompressor.compress(file, file);  
        }  
    } catch (Exception e) {  
        log.error("压缩图片失败", e);  
    }  
}

需要注意的是

  1. png 使用 Thumbnails 做处理的话,需要使用 BufferedImage.TYPE_INT_ARGB 模式,不然有的 png 图片处理完之后背景会是黑色的
  2. 对于 git 这种动态图片做压缩的话会丢失动态效果。

5. 结语

咳咳,这篇简单的文章就到这里就结束了,代码的话特别简单。只是调用了下第三方包做了下处理。

只是找寻合适的 png 第三方压缩包和测试方面,比较消耗时间。这篇文章就是踩下坑,节省下大家找寻第三方包的时间吧