300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Java图片压缩工具类(递归压缩到指定大小范围)

Java图片压缩工具类(递归压缩到指定大小范围)

时间:2024-05-01 11:27:49

相关推荐

Java图片压缩工具类(递归压缩到指定大小范围)

Java图片压缩工具

工具类使用场景

公司做人脸识别项目时候需要上传学生、家长、教师、访客的正面照图片,但是人脸识别机器有限制只接收200KB-1M的图片,所以必须做图片压缩到指定范围大少。APP上传使用产品的评价附件图片,手机直接拍照上传的图片过大,直接存储导致文件服务器存储容量递减,所以要压缩到指定范围大少。

注意事项

最大递归压缩深度默认为20,一般情况下JVM支持1000~2000的栈,所以请勿设置过大的递归深度,否则会抛出:stackoverflowerror.质量比与尺寸比默认均为0.85去压缩,压缩出来的图片少于期待范围时候,会自动递增质量比与尺寸比去压缩。图片压缩比较耗时和性能,能异步的话建议异步处理来消峰。本机压缩6M图片到600KB时候耗时3秒。

依赖关系

<dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.14</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.29</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency>

核心代码

1.压缩类

import lombok.AccessLevel;import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;import net.coobird.thumbnailator.Thumbnails;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.OutputStream;/*** @author huangrusheng* @version 1.0* @date /5/20 15:27*/@Slf4j@AllArgsConstructor(access = AccessLevel.PRIVATE)public final class ImageCompressUtil {/*** @param imageSource 图片源* @param outputStream 压缩后的图片输出地* @return* @throws IOException*/public static boolean compress(ImageSource imageSource, OutputStream outputStream) throws IOException{boolean result = compress(imageSource);if(result){outputStream.write(imageSource.getSource());}return result;}public static boolean compress(ImageSource imageSource) throws IOException {if(imageSource.getNumberOfCompressions() == 0){imageSource.setStartTime(System.currentTimeMillis());imageSource.setOriginalSource(imageSource.getSource());}if( imageSource.getSource().length>=imageSource.getMinCompressToByteSize()&& imageSource.getSource().length <= imageSource.getMaxCompressToByteSize()) {log.info("成功完成图片压缩,总耗时:{}秒 , 压缩次数:{} , 压缩前大少:{} KB ,压缩后大少:{}KB.",(System.currentTimeMillis() - imageSource.getStartTime()) / 1000, imageSource.getNumberOfCompressions(),imageSource.getByteSizeBeforeCompress() / 1024, imageSource.getSource().length / 1024);return true;}if(imageSource.getNumberOfCompressions() > imageSource.getRecursionDepth()){log.warn("图片过大,导致递归压缩次数超出:{},请尝试上传其他较小的图片.",imageSource.getNumberOfCompressions());return false;}//如果压缩小于期待值减少,增加下质量与尺寸比例if(imageSource.getSource().length < imageSource.getMinCompressToByteSize()){log.warn("压缩过度重新压缩,总耗时:{}秒 , 压缩次数:{} , 压缩前大少:{} KB ,压缩后大少:{}KB.",(System.currentTimeMillis()-imageSource.getStartTime())/1000 ,imageSource.getNumberOfCompressions(),imageSource.getByteSizeBeforeCompress()/1024, imageSource.getSource().length/1024 );imageSource.setScale(imageSource.getScale() + imageSource.getIncrementCompressQuality());imageSource.setQuality(imageSource.getQuality() + imageSource.getIncrementCompressQuality());imageSource.setSource(imageSource.getOriginalSource());}ByteArrayOutputStream byteArrayOutputStream =new ByteArrayOutputStream(imageSource.getMaxCompressToByteSize());Thumbnails.of(new ByteArrayInputStream(imageSource.getSource())).scale(imageSource.getScale()).outputQuality(imageSource.getQuality()).outputFormat(imageSource.getImageFormat()).toOutputStream(byteArrayOutputStream);imageSource.setSource(byteArrayOutputStream.toByteArray());imageSource.increaseNumberOfCompressions();return compress(imageSource);}}

2.压缩参数POJO类

import lombok.Data;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;/*** @author huangrusheng* @version 1.0* @date /5/20 15:16*/@Datapublic class ImageSource {/*** 需压缩的图片,转为字节*/private byte[] source;/*** 记录压缩前的图片,转为字节*/private byte[] originalSource;/*** 当前图片压缩的次数*/private int numberOfCompressions = 0;private long startTime ;/*** 未执行压缩前,图片的字节大少*/private int byteSizeBeforeCompress ;/*** 压缩质量*/private double quality = 0.85;/*** 压缩尺寸比例*/private double scale = 0.85;private double incrementCompressQuality = 0.05;/*** 需压缩到最大容许的字节数,默认为1M*/private int maxCompressToByteSize = 1024*1024*1;/*** 需压缩到最小容许的字节数,默认为200KB*/private long minCompressToByteSize = 1024*200;/*** 压缩后的图片格式,默认JPG*/private String imageFormat = "jpg";/*** 最大递归压缩深度*/private int recursionDepth = 20;public ImageSource(byte[] source){this.initSource(source);}public ImageSource(InputStream inputStream) throws IOException {this(inputStream,null);}public ImageSource(InputStream inputStream,Long inputByteSize ) throws IOException{ByteArrayOutputStream byteArrayOutputStream= new ByteArrayOutputStream(inputByteSize == null ? 2 * 1024 * 1024 : inputByteSize.intValue());int n ;byte [] buffer = new byte[1024 * 100];while ( -1 != ( n = inputStream.read(buffer))){byteArrayOutputStream.write(buffer,0,n);}this.initSource(byteArrayOutputStream.toByteArray());}private void initSource(byte[] source){this.source = source;this.byteSizeBeforeCompress = this.source.length;}public void increaseNumberOfCompressions(){this.numberOfCompressions = this.numberOfCompressions + 1;}}

单元测试用例

import cn.hutool.core.io.IoUtil;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.JUnit4;import java.io.FileInputStream;import java.io.FileOutputStream;/*** @author huangrusheng* @version 1.0* @date /5/20 16:05*/@RunWith(JUnit4.class)public class ImageCompressTest {@Testpublic void testCompress() throws Exception{FileInputStream fileInputStream = null ;FileOutputStream fileOutputStream = null;try {fileInputStream = new FileInputStream("D:\\image_source.jpg");fileOutputStream = new FileOutputStream("D:\\image_compress.jpg");ImageSource imageSource = new ImageSource(fileInputStream);imageSource.setMinCompressToByteSize(300*1024);imageSource.setMaxCompressToByteSize(800*1024);imageSource.setImageFormat("jpg");press(imageSource,fileOutputStream);}finally {IoUtil.close(fileInputStream);IoUtil.flush(fileOutputStream);IoUtil.close(fileOutputStream);}}}

压缩前

压缩后

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。