# 图片压缩功能详细说明

[返回1.0.4目录](./api.md) | [返回主文档](../../README.md)

## 📋 功能概述
1.0.4版本引入 视频压缩,并且异步化
oss支持压缩； todo 测试上传；生成代码的权限码问题排查： mov不是太友好;

压缩内核是macos；
一件化安装ffmg

[方案调研](#方案调研)

## 🎯 设计目标

### 1. 性能目标 todo
- **压缩比**: 平均减少60-80%文件大小
- **处理速度**: 单张图片<500ms (1920x1080)
- **并发能力**: 支持100+并发处理
- **内存使用**: <256MB/线程

### 2. 质量目标
- **视觉质量**: SSIM > 0.95 (与原图相似度)
- **格式支持**: JPEG, PNG, WebP, GIF
- **元数据**: 可选保留EXIF信息
- **颜色保真**: sRGB色彩空间

## 🏗️ 架构设计

### 处理流程
### 组件架构
```
```

## 📊 版本规格详细说明
### 1. Original (原始版本)-todo
| 参数 | 值 | 说明 |
|------|-----|------|
| 处理方式 | 直通 | 不进行任何处理 |
| 格式 | 原格式 | 保持上传时格式 |
| 质量 | 100% | 无损 |
| 尺寸 | 原始尺寸 | 保持原图大小 |
| 用途 | 备份、下载、后期处理 | |
| 存储成本 | 高 | 占用最大空间 |

### 2. Medium (中等版本)-todo
| 参数 | 值 | 说明 |
|------|-----|------|
| 目标尺寸 | 1920×1080 | 适合全屏显示 |
| 宽高限制 | 最大1920px | 等比例缩放 |
| 默认格式 | WebP | 自动转换 |
| 质量设置 | 85% | 高质量压缩 |
| 处理算法 | Lanczos3 | 高质量重采样 |
| 色彩空间 | sRGB | 标准色彩 |
| 用途 | 网页大图、文章配图 | |
| 文件大小 | 原图的20-40% | |
| 视觉质量 | 优秀 | 人眼几乎无法区分 |

### 3. Thumbnail (缩略图版本)-todo
| 参数 | 值 | 说明 |
|------|-----|------|
| 目标尺寸 | 800×600 | 适合预览 |
| 宽高限制 | 最大800px | 等比例缩放 |
| 默认格式 | WebP | 自动转换 |
| 质量设置 | 75% | 平衡质量与大小 |
| 处理算法 | Mitchell | 平衡速度与质量 |
| 裁剪模式 | 居中裁剪 | 保持比例填充 |
| 背景填充 | 白色 | 非等比时的填充 |
| 用途 | 列表页、搜索结果 | |
| 文件大小 | 原图的10-20% | |
| 视觉质量 | 良好 | 小尺寸下清晰 |

### 4. Small (小图版本)-todo
| 参数 | 值 | 说明 |
|------|-----|------|
| 目标尺寸 | 320×240 | 移动端优化 |
| 宽高限制 | 最大320px | 等比例缩放 |
| 默认格式 | WebP | 自动转换 |
| 质量设置 | 70% | 高压缩比 |
| 处理算法 | CatmullRom | 快速处理 |
| 智能裁剪 | 关注点检测 | 自动选择重要区域 |
| 渐进加载 | 支持 | 优化加载体验 |
| 用途 | 移动端、图标、头像 | |
| 文件大小 | 原图的5-10% | |
| 视觉质量 | 可接受 | 小尺寸下可用 |

## 🛠️ 处理算法详解

## 📈 性能基准
### 1. 处理速度测试
- macos m2芯片
视频压缩记录表
压缩参数：CRF23, preset=slow, libx264, AAC音频128k

| 视频时长 | 原始大小 | 分辨率 | 压缩耗时 | 实时倍率 | 处理速度 | 压缩后大小 | 压缩率 | 备注 |
|----------|----------|--------|----------|----------|----------|------------|--------|------|
| 5分13秒 | 614.69MB | 1920×1080 | 423.59秒 | 0.73x | 41-42fps | - | - | 长视频测试 |
| 6秒 | 20.04MB | 1920×1080 | 9.59秒 | 0.47x | 29fps | 1.51MB | 92.48% | 短视频测试 |
| 3分46秒 | 115.38MB | 1920×1080 | 63.48秒 | ≈3.56x | 53-106fps | 19.87MB | 82.78% | 中等长度视频，原编码h264 |
| 4分07秒 | 50.28MB | 854×480 | 29.10秒 | ≈8.49x | 260-277fps | 18.31MB | 63.58% | 分辨率较低，原编码h264 |

- Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz
视频压缩记录表
压缩参数：CRF23, preset=slow, libx264, AAC音频128k

| 视频时长 | 原始大小 | 分辨率 | 压缩耗时 | 实时倍率 | 处理速度 | 压缩后大小 | 压缩率 | 备注 |
|----------|----------|--------|----------|----------|----------|------------|--------|------|
| 6秒 | 20.04MB | 1920×1080 | 9.02秒 | 0.394x | 24fps | 1.49MB | 92.57% | **相同视频重复测试**，原编码hevc |
### 2. 压缩效果测试

| 视频类型 | 原始大小 | 压缩后大小 | 节省空间 | 压缩比 | 质量保持 | SSIM评分 | 备注 |
|----------|----------|------------|----------|--------|----------|----------|------|
| H.264高清 | 614.69MB | 137.54MB | 477.15MB | 77.63% | 优秀 | 0.98-0.99 | CRF23, 1920×1080 |

## 🔧 高级功能
### 1. 渐进式加载
### 2. 懒加载集成
### 3. 响应式图片

## 🚀 最佳实践
### 1. 上传优化
### 2. 缓存策略
### 3. 监控告警

## 🔍 故障排除
### 常见问题
#### 问题1：图片处理失败


## 📚 相关资源
### 学习资源

### 工具推荐
### 性能测试套件

## 方案调研
dockerfile
```bash
docker exec -it ruiqiu-prod sh
https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz

scp /Users/sunyafei/Downloads/azer1/ffmpeg-release-amd64-static.tar.xz  \
100:/home

docker cp /home/ffmpeg-release-amd64-static.tar.xz ruiqiu-prod:/tmp
docker exec -it ruiqiu-prod sh

tar -xf /tmp/ffmpeg-release-amd64-static.tar.xz -C /opt/

find /opt -name "ffmpeg" -type f
find /opt -name "ffprobe" -type f

/opt/ffmpeg-7.0.2-amd64-static/ffmpeg -version
ln -s /opt/ffmpeg-7.0.2-amd64-static/ffmpeg /usr/local/bin/ffmpeg 2>/dev/null || true
ln -s /opt/ffmpeg-7.0.2-amd64-static/ffprobe /usr/local/bin/ffprobe 2>/dev/null || true
/usr/local/bin/ffmpeg -version
    
todo 测试上传
```

```yaml
video:
  compression:
    ffmpeg:
      path: ${FFMPEG_PATH:/usr/bin/ffmpeg}
      temp-dir: ${TEMP_DIR:/tmp/video_compress}
      max-concurrent: ${MAX_CONCURRENT_PROCESSES:2}
    
    defaults:
      crf: 23
      preset: slow
      profile: high          # 新增：baseline, main, high
      level: "4.1"          # 新增：编码级别
      audio-bitrate: 128k
      max-width: 1920
      max-height: 1080
      enable-smart-scaling: true
      two-pass-encoding: false
      output-format: mp4
    
    cleanup:
      enabled: true
      cron: "0 0 2 * * ?"
      retention-days: 7
```
### linux-arm
```
tar -xf ffmpeg-release-arm64-static.tar.xz
mkdir -p /Users/sunyafei/workspace/app/ffmpeg
tar -xf /Users/sunyafei/Downloads/azer1/ffmpeg-release-arm64-static.tar.xz -C /Users/sunyafei/workspace/app/ffmpeg

/Users/sunyafei/workspace/app/ffmpeg/ffmpeg-7.0.2-arm64-static/ffmpeg -version
```
### macos
```
curl -L -o ffmpeg-7.0.2-macos.zip https://evermeet.cx/ffmpeg/ffmpeg-7.0.2.zip

mkdir -p /Users/sunyafei/workspace/app/ffmpeg
mv /Users/sunyafei/Downloads/azer1/ffmpeg-7.0.2-macos.zip /Users/sunyafei/workspace/app/ffmpeg
unzip ffmpeg-7.0.2-macos.zip  
/Users/sunyafei/workspace/app/ffmpeg/ffmpeg -version
```
```java
//使用案例

    @Autowired
    private FFmpegCompressor ffmpegCompressor;
    /**
     * 通用上传请求（单个）
     */
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file) throws Exception
    {
        try
        {
            AjaxResult ajax = AjaxResult.success();
            // 保存上传的文件到临时目录
            String tempDir = System.getProperty("java.io.tmpdir");
            String originalFileName = file.getOriginalFilename();
            String inputFilePath = tempDir + File.separator +
                    UUID.randomUUID() + "_" + originalFileName;

            Files.copy(file.getInputStream(), Paths.get(inputFilePath));
            // 生成输出文件路径
            String outputFileName = "compressed_" + originalFileName;
            if (outputFileName.lastIndexOf('.') > 0) {
                outputFileName = outputFileName.substring(0, outputFileName.lastIndexOf('.')) + ".mp4";
            }
            String outputFilePath = tempDir + File.separator + outputFileName;
            // 根据预设选择配置
            CompressionConfig config  = CompressionConfig.standardQuality();
            // 执行压缩
            CompressionResult result = ffmpegCompressor.compress(inputFilePath, outputFilePath, config);
            // 清理上传的原始文件
            Files.deleteIfExists(Paths.get(inputFilePath));

            ajax.put("key",result);
            return ajax;
        }
        catch (Exception e)
        {
            return AjaxResult.error(e.getMessage());
        }
    }
```
```yaml

video:
  compression:
    enabled: true  # 视频压缩功能开关
    ffmpeg:
      path: ${FFMPEG_PATH:/Users/sunyafei/workspace/app/ffmpeg/ffmpeg}
      temp-dir: ${TEMP_DIR:/tmp/video_compress}
      max-concurrent: ${MAX_CONCURRENT_PROCESSES:2}

    defaults:
      crf: 23
      preset: slow
      profile: high          # 新增：baseline, main, high
      level: "4.1"          # 新增：编码级别
      audio-bitrate: 128k
      max-width: 1920
      max-height: 1080
      enable-smart-scaling: true
      two-pass-encoding: false
      output-format: mp4

    cleanup:
      enabled: true
      cron: "0 0 2 * * ?"
      retention-days: 7
```
## 🔗 相关文档
1.0.4 API文档
1.0.4配置文档
版本对比
更新日志
[处理速度测试链接入口deepseek](https://chat.deepseek.com/a/chat/s/e86930b0-745e-43dd-aa9a-983d8c2d6695)
[指标数据](https://chat.deepseek.com/a/chat/s/1f95c002-7290-48c7-8e98-2ec45ec52ac1)
[返回主文档](../../README.md)

*功能版本: 1.0.4-SNAPSHOT | 最后更新: 2025-12-17*