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"));
}
可以看到压缩 png 不仅没有让图片变小,反而反向压缩了,从原来的 47k 压缩到了 80k
具体可以看看这个 issuse github.com/coobird/thu…
2. 解决方案
网上找了下解决方案,大概有两个
- 使用pdf渲染的开源软件OpenViewerFX, 这个里面包含类似 tinypng 压缩算法的图片压缩
- 使用 java-png-compress-util 大神做好的使用 libimagequant 依赖库,使用java JNI调用实现对PNG图片进行压缩
考虑到不同环境差异,决定还是依赖 OpenViewerFX 来做 png 的图片压缩
3. 测试 OpenViewerFX
先试试原来的 expert22.png
public static void main(String[] args) throws Exception {
File file = new File("E:\\壁纸\\expert22.png");
PngCompressor.compress(file, file);
}
em..., 好吧好像没有变化,可能是图片已经够小的原因。不过没有像 Thumbnails 反向压缩了,那换一张图片试试
嗯,可以看到还是有效果的,直接压缩了 100多K
4. 代码实现
- 引入依赖
<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 类了,具体版本变化没仔细去研究了
- 图片压缩具体实现
/**
* 图片压缩
* @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);
}
}
需要注意的是
- png 使用 Thumbnails 做处理的话,需要使用 BufferedImage.TYPE_INT_ARGB 模式,不然有的 png 图片处理完之后背景会是黑色的
- 对于 git 这种动态图片做压缩的话会丢失动态效果。
5. 结语
咳咳,这篇简单的文章就到这里就结束了,代码的话特别简单。只是调用了下第三方包做了下处理。
只是找寻合适的 png 第三方压缩包和测试方面,比较消耗时间。这篇文章就是踩下坑,节省下大家找寻第三方包的时间吧