feat(compress): improve quality guardrails and format conversion
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
<ul class="mt-2 list-disc space-y-1 pl-5">
|
||||
<li>Base URL:<code>https://ys.workyai.cn/api/v1</code></li>
|
||||
<li>认证方式:<code>X-API-Key</code>(推荐)或 <code>Authorization: Bearer <token></code></li>
|
||||
<li>支持格式:PNG / JPG / JPEG / WebP / AVIF / GIF(静态)/ BMP / TIFF / ICO</li>
|
||||
<li>支持格式:PNG / JPG / JPEG / WebP / AVIF / GIF(静态)/ BMP / TIFF / ICO(支持 output_format 转码)</li>
|
||||
<li>压缩率:<code>compression_rate</code> 1-100,表示压缩后体积占原图比例,100 为不压缩</li>
|
||||
<li>计量:成功压缩 1 个文件计 1 次;若体积未变小或压缩率为 100,则不扣额度</li>
|
||||
</ul>
|
||||
@@ -28,14 +28,15 @@
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-5 text-sm text-slate-700">
|
||||
<div class="font-medium text-slate-900">同步压缩(返回 JSON + 下载链接)</div>
|
||||
<div class="mt-2 text-xs text-slate-500">
|
||||
<code>POST /compress</code>,表单字段:<code>file</code>、<code>compression_rate</code>、
|
||||
<code>max_width</code>、<code>max_height</code>、<code>preserve_metadata</code>
|
||||
<code>POST /compress</code>,表单字段:<code>file</code>、<code>compression_rate</code>/<code>target_size_bytes</code>、
|
||||
<code>output_format</code>、<code>max_width</code>、<code>max_height</code>、<code>preserve_metadata</code>
|
||||
</div>
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \\
|
||||
-H \"X-API-Key: if_live_xxx\" \\
|
||||
-F \"file=@./demo.jpg\" \\
|
||||
-F \"compression_rate=20\" \\
|
||||
-F \"max_width=2000\" \\
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \
|
||||
-H "X-API-Key: if_live_xxx" \
|
||||
-F "file=@./demo.jpg" \
|
||||
-F "compression_rate=20" \
|
||||
-F "output_format=webp" \
|
||||
-F "max_width=2000" \
|
||||
https://ys.workyai.cn/api/v1/compress</code></pre>
|
||||
<div class="mt-3 text-xs text-slate-500">
|
||||
返回字段包含 <code>download_url</code>、<code>saved_percent</code> 与 <code>billing.units_charged</code>。
|
||||
@@ -45,12 +46,13 @@
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-5 text-sm text-slate-700">
|
||||
<div class="font-medium text-slate-900">同步压缩(直接返回二进制)</div>
|
||||
<div class="mt-2 text-xs text-slate-500">
|
||||
<code>POST /compress/direct</code>,响应头包含原/压缩大小与扣费信息。
|
||||
<code>POST /compress/direct</code>,支持同样参数(含 output_format、target_size_bytes),响应头包含原/压缩大小与扣费信息。
|
||||
</div>
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \\
|
||||
-H \"X-API-Key: if_live_xxx\" \\
|
||||
-F \"file=@./demo.jpg\" \\
|
||||
-F \"compression_rate=20\" \\
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \
|
||||
-H "X-API-Key: if_live_xxx" \
|
||||
-F "file=@./demo.jpg" \
|
||||
-F "target_size_bytes=120000" \
|
||||
-F "output_format=jpeg" \
|
||||
https://ys.workyai.cn/api/v1/compress/direct -o out.jpg -D headers.txt</code></pre>
|
||||
<div class="mt-3 text-xs text-slate-500">
|
||||
重点响应头:<code>ImageForge-Original-Size</code>、
|
||||
@@ -64,16 +66,16 @@
|
||||
<div class="mt-2 text-xs text-slate-500">
|
||||
<code>POST /compress/batch</code>,上传多文件后返回任务 ID。
|
||||
</div>
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \\
|
||||
-H \"X-API-Key: if_live_xxx\" \\
|
||||
-F \"files[]=@./a.jpg\" \\
|
||||
-F \"files[]=@./b.jpg\" \\
|
||||
-F \"compression_rate=30\" \\
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -X POST \
|
||||
-H "X-API-Key: if_live_xxx" \
|
||||
-F "files[]=@./a.jpg" \
|
||||
-F "files[]=@./b.jpg" \
|
||||
-F "compression_rate=30" \
|
||||
https://ys.workyai.cn/api/v1/compress/batch</code></pre>
|
||||
<div class="mt-3 text-xs text-slate-500">
|
||||
轮询任务:<code>GET /compress/tasks/<task_id></code>,响应包含每个文件的 <code>download_url</code> 和 <code>download_all_url</code>(ZIP)。
|
||||
</div>
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -H \"X-API-Key: if_live_xxx\" \\
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -H "X-API-Key: if_live_xxx" \
|
||||
https://ys.workyai.cn/api/v1/compress/tasks/550e8400-e29b-41d4-a716-446655440200</code></pre>
|
||||
</div>
|
||||
|
||||
@@ -82,10 +84,10 @@
|
||||
<div class="mt-2 text-xs text-slate-500">
|
||||
下载地址不在 <code>/api/v1</code> 下,需带同样的认证头。
|
||||
</div>
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -H \"X-API-Key: if_live_xxx\" \\
|
||||
<pre class="mt-3 overflow-auto rounded-lg bg-slate-950 p-4 text-xs text-slate-100"><code>curl -H "X-API-Key: if_live_xxx" \
|
||||
-L https://ys.workyai.cn/downloads/<file_id> -o result.jpg
|
||||
|
||||
curl -H \"X-API-Key: if_live_xxx\" \\
|
||||
curl -H "X-API-Key: if_live_xxx" \
|
||||
-L https://ys.workyai.cn/downloads/tasks/<task_id> -o batch.zip</code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,12 +21,14 @@ interface UploadItem {
|
||||
const auth = useAuthStore()
|
||||
|
||||
type CompressionMode = 'percent' | 'size'
|
||||
type OutputFormatOption = 'auto' | 'png' | 'jpeg' | 'webp' | 'avif' | 'gif' | 'bmp' | 'tiff' | 'ico'
|
||||
|
||||
const options = reactive({
|
||||
mode: 'percent' as CompressionMode, // 压缩模式:百分比 / 目标大小
|
||||
compressionRate: 60,
|
||||
targetSize: '' as string, // 目标大小数值
|
||||
targetUnit: 'KB' as 'KB' | 'MB', // 目标大小单位
|
||||
outputFormat: 'auto' as OutputFormatOption,
|
||||
maxWidth: '' as string,
|
||||
maxHeight: '' as string,
|
||||
})
|
||||
@@ -114,7 +116,9 @@ 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
|
||||
const bytes = options.targetUnit === 'MB' ? size * 1024 * 1024 : size * 1024
|
||||
if (!Number.isFinite(bytes) || bytes < 1024) return undefined
|
||||
return Math.round(bytes)
|
||||
}
|
||||
|
||||
async function runOne(item: UploadItem) {
|
||||
@@ -122,14 +126,25 @@ async function runOne(item: UploadItem) {
|
||||
item.error = undefined
|
||||
|
||||
try {
|
||||
const targetSizeBytes = getTargetSizeBytes()
|
||||
if (options.mode === 'size' && !targetSizeBytes) {
|
||||
item.status = 'error'
|
||||
item.error = '请填写有效目标大小(至少 1KB)'
|
||||
return
|
||||
}
|
||||
|
||||
const outputFormat = options.outputFormat === 'auto' ? undefined : options.outputFormat
|
||||
|
||||
const compressOptions = options.mode === 'percent'
|
||||
? {
|
||||
compression_rate: options.compressionRate,
|
||||
output_format: outputFormat,
|
||||
max_width: toInt(options.maxWidth),
|
||||
max_height: toInt(options.maxHeight),
|
||||
}
|
||||
: {
|
||||
target_size_bytes: getTargetSizeBytes(),
|
||||
target_size_bytes: targetSizeBytes,
|
||||
output_format: outputFormat,
|
||||
max_width: toInt(options.maxWidth),
|
||||
max_height: toInt(options.maxHeight),
|
||||
}
|
||||
@@ -542,6 +557,25 @@ async function resendVerification() {
|
||||
<div class="text-xs text-slate-500">直接指定压缩后的目标大小,系统会自动调整质量以逼近目标(仅 JPEG/WebP/AVIF 支持)。</div>
|
||||
</div>
|
||||
|
||||
<label class="space-y-1">
|
||||
<div class="text-xs font-medium text-slate-600">输出格式</div>
|
||||
<select
|
||||
v-model="options.outputFormat"
|
||||
class="w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm text-slate-800"
|
||||
>
|
||||
<option value="auto">保持原格式(推荐)</option>
|
||||
<option value="jpeg">JPEG</option>
|
||||
<option value="png">PNG</option>
|
||||
<option value="webp">WebP</option>
|
||||
<option value="avif">AVIF</option>
|
||||
<option value="gif">GIF(仅静态)</option>
|
||||
<option value="bmp">BMP</option>
|
||||
<option value="tiff">TIFF</option>
|
||||
<option value="ico">ICO</option>
|
||||
</select>
|
||||
<div class="text-xs text-slate-500">支持按需转码。目标大小模式建议配合 JPEG/WebP/AVIF。</div>
|
||||
</label>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<label class="space-y-1">
|
||||
<div class="text-xs font-medium text-slate-600">最大宽度(px)</div>
|
||||
|
||||
Reference in New Issue
Block a user