From 61fa9cb820cf0cbda3b43b59d655749dbebefb40 Mon Sep 17 00:00:00 2001 From: 237899745 <237899745@users.noreply.git.workyai.cn> Date: Sat, 25 Jul 2026 12:23:35 +0800 Subject: [PATCH] fix: harden compression boundaries and target search --- README.md | 2 +- docs/api.md | 18 +- docs/billing.md | 1 + frontend/src/pages/DocsPage.vue | 7 +- frontend/src/pages/HomePage.vue | 53 +- src/api/compress.rs | 33 +- src/api/tasks.rs | 8 +- src/services/compress.rs | 829 ++++++++++++++++++++++++++------ src/worker/mod.rs | 5 +- 9 files changed, 787 insertions(+), 169 deletions(-) diff --git a/README.md b/README.md index 0605e69..dbac907 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ### 核心功能 -- **图片压缩**:支持 PNG/JPG/JPEG/WebP/AVIF/GIF/BMP/TIFF/ICO(GIF 仅静态,支持格式转换) +- **图片压缩**:支持 PNG/JPG/JPEG/WebP/AVIF/GIF/BMP/TIFF/ICO(仅静态图片,支持格式转换) - **批量处理**:支持多图片同时上传和处理 - **压缩率**:1-100(JPEG/WebP/AVIF 以该比例为体积上限;无损格式按安全方式尽力优化) - **用户系统**:注册、登录、API Key 管理 diff --git a/docs/api.md b/docs/api.md index d68dd18..aa86ef5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -272,13 +272,19 @@ Idempotency-Key: # 建议 | 字段 | 类型 | 必填 | 说明 | |---|---|---:|---| | `file` | File | 是 | 图片文件 | -| `compression_rate` | Integer | 否 | 压缩率 1-100;JPEG/WebP/AVIF 以该比例为体积上限,无损格式为尽力优化,100 表示不压缩;优先级高于 `level` | +| `compression_rate` | Integer | 否 | 压缩率 1-100;JPEG/WebP/AVIF 以该比例为体积上限,无损格式为尽力优化;同格式且不缩放时,100 保留原始编码;优先级高于 `level` | | `level` | String | 否 | `high` / `medium` / `low`(兼容参数,默认 `medium`) | | `output_format` | String | 否 | 输出格式:`png/jpeg/webp/avif/gif/bmp/tiff/ico`(默认保持原格式;ICO 自动等比缩至 256x256 边界) | -| `max_width` | Integer | 否 | 最大宽度(等比缩放) | -| `max_height` | Integer | 否 | 最大高度(等比缩放) | -| `target_size_bytes` | Integer | 否 | 目标体积(字节),仅 `jpeg/webp/avif` 输出支持;会优先保清晰度并在必要时小幅缩放 | -| `preserve_metadata` | Boolean | 否 | 是否保留元数据(默认 `false`) | +| `max_width` | Integer | 否 | 大于 0 的最大宽度(等比缩放) | +| `max_height` | Integer | 否 | 大于 0 的最大高度(等比缩放) | +| `target_size_bytes` | Integer | 否 | 不小于 1024 的目标体积(字节),仅 `jpeg/webp/avif` 输出支持;不能与 `compression_rate` 同时指定 | +| `preserve_metadata` | Boolean | 否 | 是否保留 EXIF/ICC(默认 `false`);元数据输出仅支持 `jpeg/png/webp` | + +处理约束: +- 动画 GIF/APNG/WebP/AVIF 不会静默截取首帧,而是返回 `400 UNSUPPORTED_FORMAT`。 +- EXIF 方向会先应用到像素,再移除或归一化方向标记;透明图片转 JPEG 时以白色合成背景。 +- 目标体积搜索优先保持原分辨率,必要时在清晰度保护范围内缩放;仍无法达到时返回 `400 INVALID_REQUEST`,不会把超出目标的文件作为成功结果。 +- `compression_rate=100` 只有在同格式且未指定缩放时属于免计量原样请求;格式转换或缩放后若体积变小,正常计 1 次。 响应: ```json @@ -340,7 +346,7 @@ Idempotency-Key: # 建议 | 字段 | 类型 | 必填 | 说明 | |---|---|---:|---| | `files[]` | File[] | 是 | 图片文件数组(上限由套餐决定) | -| `compression_rate` | Integer | 否 | 压缩率 1-100;JPEG/WebP/AVIF 以该比例为体积上限,无损格式为尽力优化,100 表示不压缩;优先级高于 `level` | +| `compression_rate` | Integer | 否 | 压缩率 1-100;JPEG/WebP/AVIF 以该比例为体积上限,无损格式为尽力优化;同格式且不缩放时,100 保留原始编码;优先级高于 `level` | | `level` | String | 否 | `high` / `medium` / `low`(兼容参数) | | `output_format` | String | 否 | 输出格式:`png/jpeg/webp/avif/gif/bmp/tiff/ico`(默认保持原格式) | | `preserve_metadata` | Boolean | 否 | 是否保留元数据(默认 `false`) | diff --git a/docs/billing.md b/docs/billing.md index e9ab781..781f79a 100644 --- a/docs/billing.md +++ b/docs/billing.md @@ -24,6 +24,7 @@ - 同一任务中失败的文件不计费。 - 同一请求重试若携带相同 `Idempotency-Key`,不重复计费(返回相同结果)。 - 输出格式转换(png->webp 等)不额外加价(首期),后续可按“高级功能”计价。 +- 输出体积未变小不计费;`compression_rate=100` 仅在同格式且无缩放的原样请求中免计费,格式转换或缩放后若体积变小则正常计 1 单位。 ### 1.2 套餐(Plan) 套餐是“功能 + 配额 + 限制”的集合,建议存为可配置(DB 或配置中心)。 diff --git a/frontend/src/pages/DocsPage.vue b/frontend/src/pages/DocsPage.vue index f9b9005..222f6b2 100644 --- a/frontend/src/pages/DocsPage.vue +++ b/frontend/src/pages/DocsPage.vue @@ -19,9 +19,10 @@ @@ -40,6 +41,7 @@ https://ys.workyai.cn/api/v1/compress
返回字段包含 download_urlsaved_percentbilling.units_charged。 + 目标小于清晰度保护边界时返回 INVALID_REQUEST,不会返回超过目标的文件。
@@ -95,6 +97,7 @@ curl -H "X-API-Key: if_live_xxx" \
错误处理与常见问题