From 63a9d2f8f9c5fed9092b62d5ba81e79545ff59f1 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Thu, 27 Nov 2025 11:00:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=9B=BE=E7=89=87=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/utils/file/ImageCompressUtil.java | 95 +++++++++++++++++-- .../converter/IgnoreFailedImageConverter.java | 8 +- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/utils/file/ImageCompressUtil.java b/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/utils/file/ImageCompressUtil.java index be56b97b..e156d646 100644 --- a/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/utils/file/ImageCompressUtil.java +++ b/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/utils/file/ImageCompressUtil.java @@ -72,13 +72,13 @@ public class ImageCompressUtil { } // 先尝试质量压缩 - byte[] compressedData = compressImageQuality(originalImage, formatName, 0.8f); + byte[] compressedData = compressImageQuality(originalImage, formatName, 0.7f); // 如果质量压缩后仍大于目标大小,则进行尺寸压缩 if (compressedData.length > maxSize) { // 计算缩放比例 double scale = Math.sqrt((double) maxSize / compressedData.length); - scale = Math.max(scale, 0.5); // 最小缩放到原来的一半 + scale = Math.max(scale, 0.2); // 最小缩放到原来的20% // 尺寸压缩 compressedData = compressImageByScale(originalImage, scale, formatName); @@ -86,20 +86,36 @@ public class ImageCompressUtil { // 如果压缩后还是太大,继续压缩 int attempts = 0; - while (compressedData.length > maxSize && attempts < 5) { + while (compressedData.length > maxSize && attempts < 15) { // 增加尝试次数到15次 // 优先降低质量 - float quality = Math.max(0.1f, 0.8f - attempts * 0.1f); + float quality = Math.max(0.01f, 0.7f - attempts * 0.1f); // 最低质量降至0.01 compressedData = compressImageQuality(originalImage, formatName, quality); // 如果质量压缩不够,再缩小尺寸 if (compressedData.length > maxSize) { - double scale = 0.9 - attempts * 0.1; // 逐步缩小尺寸 - scale = Math.max(scale, 0.5); + double scale = 0.8 - attempts * 0.15; // 更积极地缩小尺寸 + scale = Math.max(scale, 0.1); // 最小缩放到原来的10% compressedData = compressImageByScale(originalImage, scale, formatName); } attempts++; } + // 如果经过多次尝试仍然大于目标大小,则强制压缩到目标大小以下 + if (compressedData.length > maxSize) { + // 强制尺寸压缩到目标大小 + double finalScale = Math.sqrt((double) maxSize / compressedData.length) * 0.8; // 留一些余量 + finalScale = Math.max(finalScale, 0.05); // 至少保留5%的尺寸 + compressedData = compressImageByScale(originalImage, finalScale, formatName); + + // 如果仍然太大,强制质量压缩 + if (compressedData.length > maxSize) { + // 计算需要的质量值 + float finalQuality = (float) maxSize / compressedData.length * 0.7f; // 留一些余量 + finalQuality = Math.max(finalQuality, 0.005f); // 至少保留0.5%的质量 + compressedData = compressImageQuality(originalImage, formatName, finalQuality); + } + } + log.info("图片压缩完成,原始大小: {} bytes, 压缩后大小: {} bytes, 压缩率: {}%", imageData.length, compressedData.length, String.format("%.2f", (1.0 - (double) compressedData.length / imageData.length) * 100)); @@ -110,6 +126,12 @@ public class ImageCompressUtil { return imageData; } + // 特殊处理:如果目标大小是50KB或更小,确保最终结果符合要求 + if (maxSize <= 50 * 1024 && compressedData.length > maxSize) { + // 使用更强力的压缩策略 + compressedData = forceCompressToSize(originalImage, formatName, maxSize); + } + return compressedData; } catch (Exception e) { log.error("图片压缩失败: {}", e.getMessage(), e); @@ -117,6 +139,63 @@ public class ImageCompressUtil { } } + /** + * 强制压缩到指定大小 + * + * @param originalImage 原始图片 + * @param formatName 图片格式 + * @param maxSize 目标大小 + * @return 压缩后的图片数据 + */ + private static byte[] forceCompressToSize(BufferedImage originalImage, String formatName, int maxSize) throws IOException { + byte[] result = null; + int width = originalImage.getWidth(); + int height = originalImage.getHeight(); + + // 通过不断缩小尺寸来达到目标大小 + double scale = 0.9; + do { + int newWidth = (int) (width * scale); + int newHeight = (int) (height * scale); + + // 创建缩放后的图片 + Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); + BufferedImage bufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bufferedImage.createGraphics(); + + // 绘制缩放后的图片 + g2d.drawImage(scaledImage, 0, 0, null); + g2d.dispose(); + + // 以最低质量压缩 + result = compressImageQuality(bufferedImage, formatName, 0.01f); + + if (result.length <= maxSize) { + break; + } + + scale -= 0.1; + } while (scale > 0.1 && result.length > maxSize); + + // 如果还是太大,强制调整大小 + if (result.length > maxSize) { + // 计算精确的缩放比例 + double targetScale = Math.sqrt((double) maxSize / result.length) * 0.9; + int newWidth = Math.max((int) (width * targetScale), 5); + int newHeight = Math.max((int) (height * targetScale), 5); + + Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); + BufferedImage bufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bufferedImage.createGraphics(); + g2d.drawImage(scaledImage, 0, 0, null); + g2d.dispose(); + + result = compressImageQuality(bufferedImage, formatName, 0.005f); + } + + return result; + } + /** * 按比例缩放图片 * @@ -130,6 +209,10 @@ public class ImageCompressUtil { int width = (int) (originalImage.getWidth() * scale); int height = (int) (originalImage.getHeight() * scale); + // 确保最小尺寸不小于5像素 + width = Math.max(width, 5); + height = Math.max(height, 5); + // 创建缩放后的图片 Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH); BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java index 1ecd4db8..5038cd5c 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/converter/IgnoreFailedImageConverter.java @@ -34,9 +34,9 @@ public class IgnoreFailedImageConverter implements Converter { // 指数退避初始延迟(毫秒) private static final int INITIAL_DELAY = 1000; // 图片压缩阈值(1MB) - private static final int COMPRESSION_THRESHOLD = 1024 * 1024; - // 压缩目标大小(100KB) - private static final int COMPRESSION_TARGET = 100 * 1024; + private static final int COMPRESSION_THRESHOLD = 100 * 1024; + // 压缩目标大小(50KB) + private static final int COMPRESSION_TARGET = 50 * 1024; // 用于跟踪本次任务中使用到的URL缓存键 private static final ThreadLocal> USED_CACHE_KEYS = new ThreadLocal>() { @Override @@ -82,6 +82,7 @@ public class IgnoreFailedImageConverter implements Converter { /** * 加载图片数据的核心方法 + * * @param value 图片URL * @return WriteCellData对象 */ @@ -296,6 +297,7 @@ public class IgnoreFailedImageConverter implements Converter { /** * 预加载图片到缓存 + * * @param imageUrls 图片URL列表 */ public static void preloadImages(Set imageUrls) {