Java 保质压缩图片
Java 保质压缩图片
一、需求背景
📅 2025.03.25 最近接到一个图片保存的需求。心想这不就是调用 API
,上传到云存储平台上去吗。难点不过是云存储平台 API
的配置和使用。
但现实狠狠给了我一巴掌,实际情况是:需要将图片保存到数据库中去。
项目组长给了我一个提示:图片转为 Base64编码,既可以后端存到数据库中去,也可以前端取出数据,直接显示 Base64编码的图片。
嗯,不错,Hutool也有现成的 Base64工具类。实际操作后发现,图片一大(1M)以上,数据库就超级慢,但现在手机图片都动辄 3M,那数据库不早晚得崩溃。
数据库慢的原因有以下两个:
- Base64编码后,数据会增大 30%;
- 图片太大。
因此,使用 Base64编码还不是最优解,以及图片还需要保质压缩(图片体积变小,但是画质要好,不能压缩后啥也看不到了)。
通过百度和 DeepSeek,了解到数据库可以存放二进制数据,然后只需要编写图片压缩代码并转为 byte[]即可。
二、功能实现
环境:SpringBoot2.7
、Java8
引入的依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.36</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-imaging</artifactId>
<version>1.0.0-alpha5</version>
</dependency>
具体代码:
package com.rnny.myapi.utils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.imaging.Imaging;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Date;
@Slf4j
public class ImageUtility {
/**
* 根据图片网络地址来下载图片,保存到默认的本地磁盘,并返回图片的byte[]
*
* @param imageSourceUrl 图片的网络地址
* @return 图片 base64 编码数据,不存在或报错则返回byte[0]
*/
public static byte[] downloadImageUseHutool(String imageSourceUrl) {
return downloadImageUseHutool(imageSourceUrl, null);
}
/**
* 根据图片网络地址来下载图片,保存到指定的本地磁盘,并返回图片的byte[]
*
* @param imageSourceUrl 图片的网络地址
* @param localDiskPath 图片的本地磁盘路径
* @return 图片 base64 编码数据,不存在或报错则返回byte[0]
*/
public static byte[] downloadImageUseHutool(String imageSourceUrl, String localDiskPath) {
if (StrUtil.isEmpty(imageSourceUrl)) {
return null;
}
if (StrUtil.isEmpty(localDiskPath)) {
localDiskPath = "D:/images/" + DateUtil.formatDate(new Date()) + "/" + System.currentTimeMillis() + ".jpg";
}
// try-catch捕获图片下载地址无效异常
try {
// 1、下载网络图片,保存到本地并返回图片file
File file = HttpUtil.downloadFileFromUrl(imageSourceUrl, localDiskPath);
return resizeImage(file);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
// 路径日志,正式环境删除即可
log.info("图片网络地址:{}", imageSourceUrl);
log.info("图片的本地磁盘路径:{}", localDiskPath);
}
return new byte[0];
}
/**
* 自动压缩图片,并返回图片的byte[]
*
* @param inputImageFile 图片文件
* @return 图片压缩后的byte[],如果不存在或报错则返回byte[0]
*/
public static byte[] resizeImage(File inputImageFile) {
try {
// 1. 读取原始图片
BufferedImage originalImage = Imaging.getBufferedImage(inputImageFile);
// 2. 计算等比缩放后的高度(压缩图片)
double ratio = 0.9;
if (inputImageFile.length() > 4194304) {
// 大于4M
ratio = 0.5;
} else if (inputImageFile.length() > 3145728) {
// 大于3M
ratio = 0.6;
} else if (inputImageFile.length() > 1048576) {
// 大于2M
ratio = 0.7;
} else if (inputImageFile.length() > 102400) {
// 大于100K
ratio = 0.8;
}
int targetWidth = (int) (originalImage.getWidth() * ratio);
int targetHeight = (int) (originalImage.getHeight() * ratio);
// 3. 创建目标尺寸的RGB图像(去除alpha通道)
BufferedImage resizedImage = new BufferedImage(
targetWidth,
targetHeight,
BufferedImage.TYPE_INT_RGB);
// 4. 高质量缩放绘制
Graphics2D g = resizedImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(originalImage,
0, 0, targetWidth, targetHeight,
0, 0, originalImage.getWidth(), originalImage.getHeight(),
null);
g.dispose();
// 5. 输出为JPEG字节数组
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(resizedImage, "jpg", baos);
return baos.toByteArray();
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return new byte[0];
}
// 测试功能是否可以使用,正式环境删除即可。
public static void main(String[] args) {
String imageSourceUrl = "https://pic.rmb.bdstatic.com/bjh/618296445392de1b74e60c5065d5edf0.jpeg@h_1280";
ImageUtility.downloadImageUseHutool(imageSourceUrl);
}
}