iFlyCode+SpecKit应用:照片等比智能压缩功能实现

iFlyCode+SpecKit

项目背景

**需求来源:**业务上需要上传考生相片,支持历年存储,预期每年新增20w+,上传质量大小不一,除了大小判断外,需要对相片超过配置阈值(默认300KB)的照片进行智能压缩,还不能影响显示效果,同时考虑压缩性能,否则前端返回时间比较久,用户等待时间长。

核心特性

  • 可配置阈值 : 通过系统配置 KsXpCompressSize 动态调整压缩阈值

  • 智能压缩: 质量递减压缩 + 尺寸缩放双重策略

  • 大图优化: 超大图片预缩放,显著降低内存占用

  • 透明通道支持: 智能识别图片类型,支持PNG/GIF透明背景

  • 三重清理机制: 正常清理 + 异常清理 + JVM退出清理

  • 详细日志: 完整的压缩过程日志记录

提问过程

将上述需求描述提交给iFlyCode,使用项目环境和设计智能体。

(执行片段如下图:)

技术架构

压缩流程图

核心方法调用链

scss 复制代码
readXpFile()    ├─ 判断文件大小 > KsXpCompressSize    ├─ compressImage()    │   ├─ 读取原始图片    │   ├─ 大图片检测与预缩放    │   │   ├─ 计算缩放比例    │   │   ├─ resizeImage() - 预缩放    │   │   └─ 释放原图内存    │   ├─ 质量压缩循环    │   │   └─ compressImageWithQuality()    │   ├─ 尺寸缩放备选    │   │   └─ resizeImage()    │   └─ 返回压缩文件    ├─ fileHandler.uploadFile()    └─ 清理临时文件

核心代码实现

1. 主压缩逻辑(readXpFile方法集成)

位置 : BkKsxpServiceImpl.java 第822-849行

2. 智能压缩方法(compressImage)

位置 : BkKsxpServiceImpl.java 第1960-2090行

核心特性:

  • 大图片预缩放优化(>2MB或>2000px)

  • 二分查找压缩算法

    (压缩次数减少50%)

  • 尺寸缩放备选方案(80%)

  • 完整的内存管理

  • 三重临时文件清理

markdown 复制代码
3. 质量压缩方法(compressImageWithQuality)

位置 : BkKsxpServiceImpl.java 第2096-2116行

java 复制代码
privatevoidcompressImageWithQuality(BufferedImage image, File outputFile, float quality) throws IOException {    javax.imageio.ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();    javax.imageio.ImageWriteParam param = writer.getDefaultWriteParam();        if (param.canWriteCompressed()) {        param.setCompressionMode(javax.imageio.ImageWriteParam.MODE_EXPLICIT);        param.setCompressionQuality(quality);    }        try (FileOutputStream fos = new FileOutputStream(outputFile);         javax.imageio.stream.ImageOutputStream ios = ImageIO.createImageOutputStream(fos)) {        writer.setOutput(ios);        writer.write(null, new javax.imageio.IIOImage(image, null, null), param);    } finally {        writer.dispose();    }}

4. 尺寸缩放方法(resizeImage)

位置 : BkKsxpServiceImpl.java 第2118-2141行

特性: 支持透明通道(ARGB)

perl 复制代码
private BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight){    // 保持原图的图片类型,支持透明通道    int imageType = originalImage.getType();    if (imageType == 0) {        imageType = originalImage.getTransparency() == BufferedImage.OPAQUE            ? BufferedImage.TYPE_INT_RGB            : BufferedImage.TYPE_INT_ARGB;    }        BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, imageType);    Graphics2D graphics = resizedImage.createGraphics();        // 设置高质量渲染    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);    graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);        graphics.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);    graphics.dispose();        return resizedImage;}

配置说明

系统配置参数

配置方法

方法1: 数据库配置(推荐)

java 复制代码
-- 插入配置(如果不存在)INSERT INTO basis_syscfg(syscfg_key, syscfg_value, syscfg_desc)VALUES('KsXpCompressSize', '300', '照片压缩阈值(KB)');-- 更新配置UPDATE basis_syscfg SET syscfg_value = '500'WHERE syscfg_key = 'KsXpCompressSize';

方法2: 系统管理界面

  1. 登录系统管理后台

  2. 进入"系统配置"模块

  3. 查找或添加 KsXpCompressSize 配置项

  4. 设置期望的阈值(单位:KB)

  5. 保存配置

性能优化详解

1. 大图片预缩放策略

优化前后对比

预缩放触发条件

ruby 复制代码
finallong LARGE_FILE_THRESHOLD = 2 * 1024 * 1024L; // 2MBfinalint LARGE_DIMENSION_THRESHOLD = 2000; // 2000像素// 满足以下任一条件触发预缩放:// 1. 文件大小 > 2MB// 2. 宽度 > 2000px// 3. 高度 > 2000px

缩放比例计算

erlang 复制代码
printf("hello world!");// 策略1: 尺寸超标 - 等比例缩放到2000px以内if (width > 2000 || height > 2000) {    scaleFactor = min(2000/width, 2000/height);}// 策略2: 文件超大但尺寸正常 - 缩小到70%if (fileSize > 2MB && scaleFactor == 1.0) {    scaleFactor = 0.7;}

2. 内存管理优化

内存释放时机

代码示例

yaml 复制代码
// 1. 预缩放后释放原图workingImage = resizeImage(originalImage, preScaledWidth, preScaledHeight);originalImage.flush();  // 立即释放originalImage = null;// 2. 压缩完成后释放工作图workingImage.flush();workingImage = null;// 3. finally块确保释放finally {    if (workingImage != null) {        workingImage.flush();    }}

3. 临时文件清理机制

三重保障

清理代码

vbnet 复制代码
// 1. 创建时设置自动清理compressedFile = File.createTempFile("compressed_", ".jpg");compressedFile.deleteOnExit();  // JVM退出时自动删除// 2. 正常使用后清理if (fileToUpload != readFile && fileToUpload.exists()) {    fileToUpload.delete();}// 3. 异常情况清理catch (Exception e) {    if (compressedFile != null && compressedFile.exists()) {        try {            compressedFile.delete();        } catch (Exception deleteEx) {            SysLogUtils.printLogger("删除临时文件失败");        }    }}

单元测试

测试场景

1. 功能测试

2. 性能测试

shell 复制代码
# 测试场景1: 单张大图片- 文件: 4000x3000, 2MB- 预期: 内存占用 < 20MB, 处理时间 < 3秒# 测试场景2: 批量上传- 文件: 100张混合大小照片- 预期: 无内存溢出, 总时间 < 30秒# 测试场景3: 极限测试- 文件: 8000x6000, 10MB- 预期: 成功压缩, 无崩溃

3. 边界测试

arduino 复制代码
// 测试用例1. 损坏的图片文件 → 应返回null,使用原图2. 非JPG格式 → 应正常处理(PNG/GIF)3. 阈值为0 → 应使用默认值300KB4. 极小图片(10KB) → 不压缩5. 正方形图片 → 等比例缩放6. 极窄/极宽图片 → 正确计算缩放比例

测试步骤

准备工作

arduino 复制代码
-- 1. 配置压缩阈值INSERT INTO basis_syscfg(syscfg_key, syscfg_value, syscfg_desc)VALUES('KsXpCompressSize', '300', '照片压缩阈值(KB)');

执行测试

shell 复制代码
# 2. 准备测试照片- 小照片: 150KB (不压缩)- 中照片: 500KB (质量压缩)- 大照片: 2MB (预缩放+压缩)- PNG照片: 带透明背景# 3. 批量上传测试- 打包成ZIP文件- 通过系统上传- 检查日志输出- 验证存储结果# 4. 验证结果- 检查照片大小是否符合阈值- 检查照片质量是否可接受- 检查透明通道是否保留- 检查临时文件是否清理

日志示例

正常压缩日志

scss 复制代码
照片 20240101001.jpg 从 450KB 压缩到 280KB (阈值: 300KB)

大图片预缩放日志

makefile 复制代码
大图片预缩放: IMG_4000x3000.jpg, 原尺寸: 4000x3000, 预缩放到: 2000x1500 (比例: 0.50)压缩成功: IMG_4000x3000.jpg, 质量: 0.7, 大小: 285KB

尺寸缩放日志

makefile 复制代码
通过缩小尺寸压缩: large_photo.jpg, 新尺寸: 1600x1200, 大小: 295KB

压缩失败日志

lua 复制代码
压缩照片失败: corrupted.jpg, Cannot read input file!

性能指标

压缩效果统计

效果总结

1、原计划3个工作日完成,使用iFlyCode,省去寻找方案的时间,1天左右完成,提效66%;

2、经过生产验证,该压缩方案成功率100%,效果符合预期,即300k以上相片压缩至300k内,不影响打印效果呈现,满足业务需求,后期可以将本方法抽象成为通用方法进行复用。

--- END ---

相关推荐
吃杠碰小鸡1 天前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone1 天前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 天前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 天前
Vue 2.3
前端·javascript·vue.js
夜郎king1 天前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳1 天前
JavaScript 的宏任务和微任务
javascript
夏幻灵1 天前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星1 天前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_1 天前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝1 天前
RBAC前端架构-01:项目初始化
前端·架构