From 5f432998a3a6486b78b1275d6d547864273f784f Mon Sep 17 00:00:00 2001 From: yuyx <237899745@qq.com> Date: Sat, 10 Jan 2026 17:51:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=8C=89=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E5=A4=A7=E5=B0=8F=E5=8E=8B=E7=BC=A9=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 target_size_bytes 参数,支持直接指定压缩后的目标大小(字节) - 实现自动缩放算法:当仅调整质量无法达到目标时,自动缩小图片尺寸 - 前端新增压缩模式切换:百分比模式 / 目标大小模式 - 支持 KB/MB 单位选择 - 优化二分搜索算法,提高目标大小的精准度 Co-Authored-By: Claude Opus 4.5 --- frontend/src/pages/HomePage.vue | 78 +++++++++++- frontend/src/services/api.ts | 2 + src/api/compress.rs | 23 ++++ src/services/compress.rs | 211 ++++++++++++++++++++++++++++---- src/worker/mod.rs | 1 + 5 files changed, 288 insertions(+), 27 deletions(-) diff --git a/frontend/src/pages/HomePage.vue b/frontend/src/pages/HomePage.vue index 7688a67..f1e47bc 100644 --- a/frontend/src/pages/HomePage.vue +++ b/frontend/src/pages/HomePage.vue @@ -20,8 +20,13 @@ interface UploadItem { const auth = useAuthStore() +type CompressionMode = 'percent' | 'size' + const options = reactive({ + mode: 'percent' as CompressionMode, // 压缩模式:百分比 / 目标大小 compressionRate: 60, + targetSize: '' as string, // 目标大小数值 + targetUnit: 'KB' as 'KB' | 'MB', // 目标大小单位 maxWidth: '' as string, maxHeight: '' as string, }) @@ -105,18 +110,33 @@ function toInt(v: string): number | undefined { return Math.floor(n) } +function getTargetSizeBytes(): number | undefined { + if (options.mode !== 'size') return undefined + const size = Number(options.targetSize) + if (!Number.isFinite(size) || size <= 0) return undefined + return options.targetUnit === 'MB' ? size * 1024 * 1024 : size * 1024 +} + async function runOne(item: UploadItem) { item.status = 'compressing' item.error = undefined try { + const compressOptions = options.mode === 'percent' + ? { + compression_rate: options.compressionRate, + max_width: toInt(options.maxWidth), + max_height: toInt(options.maxHeight), + } + : { + target_size_bytes: getTargetSizeBytes(), + max_width: toInt(options.maxWidth), + max_height: toInt(options.maxHeight), + } + const result = await compressFile( item.file, - { - compression_rate: options.compressionRate, - max_width: toInt(options.maxWidth), - max_height: toInt(options.maxHeight), - }, + compressOptions, auth.token, ) @@ -460,7 +480,31 @@ async function resendVerification() {
压缩参数
-