当前位置: 首页 > news >正文

不损失清晰度情况对图片进行压缩的工具类(可通过地址也可以通过文件调用)

一 、效果

原图和效果图对比

 二、工具类代码

2.1导包

 <dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.16</version>
</dependency>
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.5</version>
</dependency>

注意点:工具类里面有一个地方需要返回MultipartFile类,如果需要这个方法那么就还需要导包,如果不需要,可以直接删除工具类的downloadAndCompressToMultpartFile这个方法

<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.20</version>
</dependency>

2.2 工具类


import net.coobird.thumbnailator.Thumbnails;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.util.StringUtils;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;public class ImageCompressorUtil {/*** 下载并压缩图片(保持高清晰度)*/public static void downloadAndCompress(String imageUrl, String savePath) throws Exception {long startTime = System.currentTimeMillis();try  {InputStream inputStream = getImageInputStream(imageUrl);// 使用Thumbnailator进行高质量压缩Thumbnails.of(inputStream).scale(1.0) // 保持原始尺寸.outputQuality(0.75) // 质量参数(0.0-1.0,值越高质量越好).toFile(savePath);long originalSize = getRemoteFileSize(imageUrl);long compressedSize = new File(savePath).length();System.out.println("\n处理完成:" + savePath);System.out.println("原图大小:" + formatSize(originalSize));System.out.println("压缩后大小:" + formatSize(compressedSize));System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "ms");} catch (Exception e) {System.err.println("处理失败:" + e.getMessage());throw e;}}/*** 通过地址压缩图片* @param imageUrl* @param quality 建议0.7* @return* @throws Exception*/public static MultipartFile downloadAndCompressToMultpartFile(String imageUrl, double quality) throws Exception {try  {InputStream inputStream = getImageInputStream(imageUrl);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();// 压缩图片Thumbnails.of(inputStream).scale(1.0).outputQuality(quality).toOutputStream(outputStream);// 提取文件名和内容类型String originalFilename = extractFileName(imageUrl);String contentType = detectContentType(originalFilename);if(StringUtils.isEmpty(contentType)){return null;}// 使用Spring的MockMultipartFile创建实例return new MockMultipartFile("file",                 // 表单字段名originalFilename,       // 原始文件名contentType,            // 内容类型outputStream.toByteArray()  // 文件内容);} catch (Exception e) {System.err.println("处理失败:" + e.getMessage());throw e;}}/*** 从URL提取文件名*/private static String extractFileName(String url) {if (url == null){return null;}int lastSlash = url.lastIndexOf('/');String fileName = lastSlash > 0 ? url.substring(lastSlash + 1) : url;// 处理查询参数(如果有)int queryIndex = fileName.indexOf('?');if (queryIndex > 0) {fileName = fileName.substring(0, queryIndex);}// 如果没有扩展名,默认为jpgif (!fileName.contains(".")) {fileName += ".jpg";}return fileName;}/*** 检测文件内容类型*/private static String detectContentType(String fileName) {if (fileName == null) {return null;}String lowerCaseName = fileName.toLowerCase();if (lowerCaseName.endsWith(".png")) return "image/png";if (lowerCaseName.endsWith(".gif")) return "image/gif";if (lowerCaseName.endsWith(".webp")) return "image/webp";if (lowerCaseName.endsWith(".bmp")) return "image/bmp";return "image/jpeg";}/*** 获取图片输入流(处理网络连接)*/private static InputStream getImageInputStream(String imageUrl) throws IOException {URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(5000);connection.setReadTimeout(10000);connection.setRequestProperty("User-Agent", "Mozilla/5.0");if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {throw new IOException("图片下载失败,响应码:" + connection.getResponseCode());}return connection.getInputStream();}public static File compressMultipartFile(MultipartFile file, double quality, String outputPath) throws Exception {if (file == null || file.isEmpty()) {throw new IllegalArgumentException("上传的文件为空");}long startTime = System.currentTimeMillis();File outputFile = new File(outputPath);try {InputStream inputStream = file.getInputStream();// 使用Thumbnailator进行高质量压缩Thumbnails.of(inputStream).scale(1.0).outputQuality(quality).toFile(outputFile);long originalSize = file.getSize();long compressedSize = outputFile.length();System.out.println("\n处理完成:" + outputPath);System.out.println("原图大小:" + formatSize(originalSize));System.out.println("压缩后大小:" + formatSize(compressedSize));System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "ms");return outputFile;} catch (Exception e) {System.err.println("压缩失败:" + e.getMessage());// 清理可能生成的不完整文件if (outputFile.exists()) {outputFile.delete();}throw e;}}public static InputStream compressToStream(MultipartFile file, double quality) throws Exception {if (file == null || file.isEmpty()) {throw new IllegalArgumentException("上传的文件为空");}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {InputStream inputStream = file.getInputStream();// 压缩到输出流Thumbnails.of(inputStream).scale(1.0).outputQuality(quality).toOutputStream(outputStream);// 转换为ByteArrayInputStream以便返回return new ByteArrayInputStream(outputStream.toByteArray());} catch (Exception e) {System.err.println("压缩失败:" + e.getMessage());throw e;}}/*** 获取远程文件大小*/private static long getRemoteFileSize(String imageUrl) {try {URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("HEAD");return connection.getContentLength();} catch (Exception e) {return -1;}}/*** 格式化文件大小(B/KB/MB)*/private static String formatSize(long bytes) {if (bytes < 0) {return "未知";}if (bytes < 1024){return bytes + "B";}if(bytes < 1024 * 1024){return String.format("%.2fKB", bytes / 1024.0);}return String.format("%.2fMB", bytes / (1024.0 * 1024));}/*** 调整压缩质量参数(0.0-1.0)* 较高的值(如0.8-0.9)保持更好的质量* 较低的值(如0.6-0.7)实现更高的压缩率*/public static void setCompressionQuality(double quality) {// 验证参数范围if (quality < 0.0 || quality > 1.0) {throw new IllegalArgumentException("质量参数必须在0.0-1.0之间");}// 这里可以添加全局质量参数的存储逻辑}/*** 测试方法*/public static void main(String[] args) throws Exception {// 测试JPG图片压缩String jpgUrl = "https://51fangtao.oss-cn-shenzhen.aliyuncs.com/mall/upload/1687858554984u9acttxm0uuupk6v6ddo.jpg";String jpgSavePath = "D:/compressed_jpg.jpg";downloadAndCompress(jpgUrl, jpgSavePath);// 测试PNG图片压缩(转换为JPG以获得更好的压缩率)String pngUrl = "https://ftimageupload.oss-cn-shenzhen.aliyuncs.com/17029036937294.png";String pngSavePath = "D:/compressed_png.jpg"; // 保存为JPGdownloadAndCompress(pngUrl, pngSavePath);}
}
http://www.dtcms.com/a/315050.html

相关文章:

  • 基于实时音视频技术的远程控制传输SDK的功能设计
  • 基于特征融合的医学图像分类算法
  • #C语言——刷题攻略:牛客编程入门训练(四):运算(二)
  • 【基于超表面实现电磁感应透明(EIT)的复现与讲解】
  • Spring P1 | 创建你的第一个Spring MVC项目(IDEA图文详解版,社区版专业版都有~)
  • [Shell编程] 零基础入门 Shell 编程:从概念到第一个脚本
  • 基于TurboID的邻近标记质谱(PL-MS)实验指南:从质粒构建到质谱鉴定
  • 【OS】操作系统概述
  • 互联网医院整体项目套表整理过程文档全流程分析
  • Stanford CS336 assignment1 | Byte-Pair Encoding (BPE) Tokenizer
  • 飞算JavaAI:颠覆传统开发的智能利器
  • Effective C++ 条款22: 将成员变量声明为private
  • Pixel 4D 3.4.4.0 | 支持丰富的壁纸资源,高清画质,高度的个性化设置能力,智能推荐功能
  • Ubuntu 下 MySQL 离线部署教学(含手动步骤与一键脚本)
  • 力扣面试150题--加一
  • ZCC1004E-120V 3A 零功耗使能异步降压电源芯片
  • 人工智能之数学基础:条件概率及其应用
  • JS中的Set和WeakSet联系与区别
  • 数据结构---配置网络步骤、单向链表额外应用
  • 【Linux】Linux 操作系统 - 33 , 线程(二) 线程互斥和同步 , 带你对线程使用深刻理解 !
  • 《Python 实用项目与工具制作指南》· 2.2 变量
  • JVM调优工具详解
  • 把“距离过近”的节点(或端点)合并成一个,避免重复。机器学习 python
  • web:ts元组
  • 【RH124知识点问答题】第8章 监控和管理 Linux 进程
  • Bean的生命周期和循环依赖问题的解决
  • 防火墙认证用户部署
  • 开发规范(一)移动端
  • 多线程(一)
  • 【C#】操作Execl和Word文件-1