Java使用Thumbnails实现图片指定大小压缩

Java使用Thumbnails实现图片指定大小压缩

项目中有个要求,对上传服务器的图片大小进行判断,大于50k的图片要进行压缩处理,让其小于50k后在上传。针对图片压缩,一般有以下两种方法:1)java api的ImageIO实现图片压缩,但效果不好,图片压缩后出现变红现象,看了网上的博客普遍都说bug比较多,会有OOM内存溢出的现象。2)该方法使用的是谷歌的Thumbnails插件来实现图片压缩。本文主要介绍的是使用插件实现图片压缩。

实现:

Thumbnails.of("源文件路径") 
			        .scale(1f) //0-1 float 压缩大小
			        .outputQuality(0.7f) //0-1 压缩质量
			        .toFile("新文件路径");

需要引入的依赖:

<!--图片压缩-->
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.8</version>
        </dependency>

使用Thumbnails插件实现图片压缩方法有以下两种实现方式:

第一种方式,实现思路:

按照一定的比例压缩图片,递归压缩图片,如果压缩后的图片还不满足要求,则继续进行压缩,直到压缩后的图片大小满足要求。
代码实现:
public class ThumbnailUtil {
    /**
     * 根据指定大小和指定经度压缩图片
     *
     * @param srcPath     源图片地址
     * @param desPath     目标图片地址
     * @param desFileSize 指定图片大小,单位kb
     * @param accuracy    精度,递归压缩的比率,建议小于0.9
     * @return
     */
    public static String compressPictureForScale(String srcPath, String desPath, long desFileSize, double accuracy) {
        if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(desPath)) {
            return null;
        }
        if (!new File(srcPath).exists()) {
            return null;
        }
        try {
            File srcFile = new File(srcPath);
            long srcFileSize = srcFile.length();
            System.out.println("源图片: " + srcPath + ", 大小: " + srcFileSize / 1024 + "kb");
            //1.先转换成jpg
            Thumbnails.of(srcPath).scale(1f).toFile(desPath);
            //递归压缩,直到目标文件大小小于desFileSize
            compressPicCycle(desPath, desFileSize, accuracy);

            File desFile = new File(desPath);
            System.out.println("目标图片: " + desPath + ", 大小: " + desFile.length() / 1024 + "kb");
            System.out.println("图片压缩完成!");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return desPath;
    }

    private static void compressPicCycle(String desPath, long desFileSize, double accuracy) throws IOException {
        File srcFileJPG = new File(desPath);
        long srcFileSizeJPG = srcFileJPG.length();
        //2.判断大小,如果小于50kb,不用压缩,如果大于等于50kb,需要压缩
        if (srcFileSizeJPG <= desFileSize * 1024) {
            return;
        }
        //计算宽高
        BufferedImage bim = ImageIO.read(srcFileJPG);
        int srcWidth = bim.getWidth();
        int srcHeight = bim.getHeight();
        int destWidth = new BigDecimal(srcWidth).multiply(new BigDecimal(accuracy)).intValue();
        int destHeight = new BigDecimal(srcHeight).multiply(new BigDecimal(accuracy)).intValue();
        Thumbnails.of(desPath).size(destWidth,destHeight).outputQuality(accuracy).toFile(desPath);
        compressPicCycle(desPath,desFileSize,accuracy);
    }

    public static void main(String[] args) {
        String srcPath = "C:\\Users\\hemanman6\\Desktop\\微信图片_20210802151348.png";
        String desPath = "C:\\Users\\hemanman6\\Desktop\\2.jpg";
        ThumbnailUtil.compressPictureForScale(srcPath,desPath,50,0.8);
    }
}

结果显示:

在这里插入图片描述
注意

png转jpg图片占存大小变小,jgp转png图片占存大小变大

为了更贴近公司的业务代码,对上述代码进行改进,去除了一些多余的IO过程,把递归改成了循环,并且把文件操作改为了流和字节数组的操作。

第二种,使用循环方式、流、字节数组实现

代码实现如下:
public class ThumbnailUtis1 {
    private static Logger logger = LoggerFactory.getLogger(ThumbnailUtis1.class);

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小,单位kb
     * @param imageId     影像编号
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPictureForScale(byte[] imageBytes, long desFileSize, String imageId) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream).scale(accuracy).outputQuality(accuracy).toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("【图片压缩】imageId={} | 图片原大小={}kb | 压缩后大小={}kb", imageId, srcSize / 1024,
                    imageBytes.length / 1024);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }

        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }

    public static void main(String[] args) throws IOException {
        //将文件内容读入字节数组。文件始终处于关闭状态。
        byte[] bytes = FileUtils.readFileToByteArray(new File("C:\\Users\\hemanman6\\Desktop\\微信图片_20210802151348.jpg"));
        long l = System.currentTimeMillis();
        bytes = ThumbnailUtis1.compressPictureForScale(bytes,30,"x");
        System.out.println(System.currentTimeMillis()-1);
        //将字节数组写入到文件
        FileUtils.writeByteArrayToFile(new File("C:\\Users\\hemanman6\\Desktop\\333.jpg"),bytes);
    }
}

其中,FileUtils类需要引入如下依赖:

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
结果显示:

在这里插入图片描述
在这里插入图片描述

  • 8
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值