Java图片压缩

写在前面

压缩原理,基于工具thumbnailator,其底层也是基于JDK提供的BufferedImage及Graphics2D,不一样的仅仅是它自己的一套算法来根据压缩比例来重新计算图片的长合宽,重新绘制图片。

依赖

<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.20</version>
</dependency>

工具类

/**
 * 图片压缩(此方法优化了算法,极大降低压缩时间成本,推荐使用)
 * <p>
 * 默认压缩目标大小允许的误差范围:0.1
 * <p>
 * 默认压缩时的图片格式:png
 *
 * @param img          - 待压缩图片
 * @param compressSize - 压缩目标大小(单位:kb)
 * @return image compress bytes
 */
public static byte[] compress(byte[] img, double compressSize) throws IOException {
    return compress(img, compressSize, "png");
}

/**
 * 图片压缩(此方法优化了算法,极大降低压缩时间成本,推荐使用)
 * <p>
 * 默认压缩目标大小允许的误差范围:0.1
 *
 * @param img          - 待压缩图片
 * @param compressSize - 压缩目标大小(单位:kb)
 * @param suffix       - 原文件后缀(必传)
 * @return image compress bytes
 */
public static byte[] compress(byte[] img, double compressSize, String suffix) throws IOException {
    return compress(img, compressSize, 0.1D, suffix);
}

/**
 * 图片压缩(此方法优化了算法,极大降低压缩时间成本,推荐使用)
 *
 * @param img          - 待压缩图片
 * @param compressSize - 压缩目标大小(单位:kb)
 * @param errorsFactor - 允许与目标值的误差范围因子:范围(0, 1)
 * @param suffix       - 原文件后缀(必传)
 * @return image compress bytes
 */
public static byte[] compress(byte[] img, double compressSize, double errorsFactor, String suffix) throws IOException {
    if ((img.length / 1024D) <= compressSize) {
        return img;
    }
    Asserts.isNotEmpty(suffix, "必须指定压缩文件后缀名,如png、jpg等");
    Asserts.isTrue(errorsFactor > 0 && errorsFactor < 1, "允许与目标值的误差范围因子需在(0,1)之间,且不包含头尾");
    ByteArrayOutputStream cache = new ByteArrayOutputStream();
    ByteArrayInputStream src = new ByteArrayInputStream(img);
    double min = 0, max = 1;
    double scale = (min + max) / 2.0D;
    final double targetSize = compressSize * 1024D;
    final double minPermitSize = targetSize * (1 - errorsFactor);
    final double maxPermitSize = targetSize * (1 + errorsFactor);
    Set<Double> prevent = new HashSet<>();// 用于标识无法压缩到目标范围类的图片大小,防止死循环
    while (true) {
        Thumbnails.of(src).scale(scale).outputFormat(suffix).toOutputStream(cache);
        double actualSize = cache.size();
        if (!prevent.add(actualSize)) {// 防止死循环
            log.info("压缩轮询次数:{}, 压缩率: {}", prevent.size() + 1, scale);
            break;
        }
        if (actualSize >= minPermitSize && actualSize <= maxPermitSize) {
            log.info("压缩轮询次数:{}, 压缩率: {}", prevent.size(), scale);
            break;
        }
        if (actualSize >= targetSize) {// 实际压缩率小了
            max = scale;
        } else {
            min = scale;
        }
        scale = (min + max) / 2.0D;
        cache.reset();// 清空当前已读取缓存
        src = new ByteArrayInputStream(img);// 重新加载下一次要读取的资源
    }
    return cache.toByteArray();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流沙QS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值