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 2021/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 2021/5/20 15:16*/
@Data
public 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 2021/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");ImageCompressUtil.compress(imageSource,fileOutputStream);}finally {IoUtil.close(fileInputStream);IoUtil.flush(fileOutputStream);IoUtil.close(fileOutputStream);}}
}
压缩前
压缩后
Java图片压缩工具类(递归压缩到指定大小范围)相关推荐
- java图片压缩工具类
java图片压缩工具类 PicCompressUtil.java import java.io.ByteArrayInputStream; import java.io.ByteArrayOutput ...
- java图片压缩工具类(指定压缩大小)
1:先导入依赖 <!--thumbnailator图片处理--><dependency><groupId>net.coobird</groupId>&l ...
- android图片压缩工具类
好久没写博客了,一方面是因为最近找了家实习单位,很累基本上下班后就没有打不起精神去学习,另一方面我自己觉得写博客确实有点耗时间,趁着周六周日想花点时间研究下fresco,picass,Glide等框架 ...
- 一个好用的android图片压缩工具类
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
- java图片的导出,并压缩
java图片的导出,并压缩 java 压缩包jar包使用的是commons-compress-1.6.jar /*** 导出图片* @param request* @param response*/@ ...
- JAVA图片裁剪工具类
JAVA图片裁剪工具类: <span style="font-size:14px;">package org.oms.avatar.util;import java.a ...
- java zip 压缩工具类
java zip 压缩工具类 目录结构 环境依赖 zip压缩工具类 遇到的问题 环境依赖 <!--这里作者使用的是 springboot 2.3.2.RELEASE 版本--> <d ...
- 整合的图片压缩工具类ImageTools
根据网上找的资料和自己用到的地方进行修改的图片压缩工具类,有什么不对的地方请见谅,源码如下: public final class ImageTools {/*** Transfer drawable ...
- python更改图片存储大小_python不改变图片尺寸压缩到指定大小
python不改变图片尺寸压缩到指定大小 import base64 import io import os from PIL import Image from PIL import ImageFi ...
最新文章
- SharePoint Online 创建和使用栏
- CF1446F-Line Distance【计算几何,树状数组,二分】
- Lighttpd 的安装配置(web服务器软件)
- RabbitMQ事务和Confirm发送方消息确认——深入解读
- MPLS 次末跳弹出配置_weblogic的安装与配置
- Android开源框架:Universal-Image-Loader解析(四)TaskProcess
- interface接口_Java程序设计--接口interface(笔记)
- 自动修改mysql5.7初始化密码
- GitLab oauth2.0 第三方登录 单点登录
- 关于Google Chrome浏览器离线安装包下载方法
- tomcat 官网下载
- alook浏览器哪个好 夸克浏览器_简单搜索、X浏览器、夸克浏览器、Via几款极简浏览器,到底哪个最好用?...
- 新华文娱数据发布年度白皮书 口碑成观影首要驱动力
- 移动端使用fiddler抓包步骤
- 某某客户的一次勒索病毒应急响应
- 假期错过的...条AI新闻都在这里了
- 和sar比起来,其他Linux命令都是猹---ing
- B-004 LC滤波器的基础知识
- 【文献管理软件Zotero】Zotfile插件及云同步的使用技巧
- 微信公众平台开发(PHP)(五) 天气预报功能开发
热门文章
- 50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 上
- “微信身份证”来了!安全吗?要是手机丢了咋办…
- 区域环评项目(Vue3 PC)实现验证码等功能 问题记录
- iOS点击短信中的链接跳转到App
- 稀疏数组——实现五子棋存盘和续上盘功能
- html图片居中自适应,解决img图片自适应居中问题
- pycharm配置sqlite
- csgo内置服务器文件夹,[服务器架设] CSGO 服务器架设新手全教程(WIN)(带图) | 视频迟些送上...
- 微信小程序 - 页面事件
- BZOJ1746 DP