From 1802614e5ca56f82144c655265c9e8eaaa05e5b4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 2 Jan 2026 21:03:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87=E5=8F=98?= =?UTF-8?q?=E6=B8=85=E6=99=B0=E5=8A=9F=E8=83=BD=E8=B0=83=E8=AF=95=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=92=8C=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加详细的外部API返回数据日志 - 对比原图和处理后图片大小,检测是否返回原图 - 添加下载URL验证逻辑 - 确认原图上传时没有压缩处理(直接上传外部API返回的图片) - 添加图片大小变化百分比日志 - 如果外部API返回原图会发出警告 用于诊断:用户下载的图片是否是处理后的图片 --- app/api/enhance/route.ts | 50 ++++++++++++++++++++++++-- components/image-annotator.tsx | 36 +++++++++++++++---- 图片变清晰压缩处理检查报告.md | 65 ++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 图片变清晰压缩处理检查报告.md diff --git a/app/api/enhance/route.ts b/app/api/enhance/route.ts index 894aa45..cda828a 100644 --- a/app/api/enhance/route.ts +++ b/app/api/enhance/route.ts @@ -430,16 +430,35 @@ export async function POST(request: NextRequest) { ); } + // ✅ 记录原始输入图片大小(用于对比) + const originalImageSize = imageBuffer.length; + console.log(`[Enhance] 📊 原始输入图片大小: ${originalImageSize} bytes (${(originalImageSize / 1024 / 1024).toFixed(2)}MB)`); + + // ✅ 打印外部API返回的完整数据结构(用于调试) + console.log(`[Enhance] 📋 外部API返回的taskResult.data结构:`, { + hasImageBase64: !!taskResult.data.image_base64, + hasImage: !!taskResult.data.image, + imageType: typeof taskResult.data.image, + imagePreview: typeof taskResult.data.image === "string" ? taskResult.data.image.substring(0, 100) : "非字符串", + status: taskResult.data.status, + progress: taskResult.data.progress, + state: taskResult.data.state, + }); + let enhancedImageBase64: string; if (taskResult.data.image_base64) { // 返回的是base64 enhancedImageBase64 = taskResult.data.image_base64; + console.log(`[Enhance] ✅ API返回了image_base64,长度: ${enhancedImageBase64.length} 字符`); } else if (taskResult.data.image) { // 检查是否是URL(以http://或https://开头) const imageData = taskResult.data.image; + console.log(`[Enhance] 📥 API返回了image字段,类型: ${typeof imageData}, 值: ${typeof imageData === "string" ? imageData.substring(0, 100) : "非字符串"}`); + if (typeof imageData === "string" && (imageData.startsWith("http://") || imageData.startsWith("https://"))) { // 返回的是URL,需要下载 + console.log(`[Enhance] 📥 从URL下载处理后的图片: ${imageData}`); const imageResponse = await fetch(imageData); if (!imageResponse.ok) { return NextResponse.json( @@ -447,13 +466,22 @@ export async function POST(request: NextRequest) { { status: 500 } ); } - const imageBuffer = await imageResponse.arrayBuffer(); - enhancedImageBase64 = Buffer.from(imageBuffer).toString("base64"); + const downloadedBuffer = await imageResponse.arrayBuffer(); + enhancedImageBase64 = Buffer.from(downloadedBuffer).toString("base64"); + const downloadedSize = downloadedBuffer.byteLength; + console.log(`[Enhance] ✅ 从URL下载完成,Base64长度: ${enhancedImageBase64.length} 字符,文件大小: ${downloadedSize} bytes`); + + // ✅ 对比下载的图片和原图大小 + if (Math.abs(downloadedSize - originalImageSize) < 100) { + console.warn(`[Enhance] ⚠️ 警告:下载的图片大小(${downloadedSize})和原图大小(${originalImageSize})几乎相同,可能外部API返回的是原图!`); + } } else { // 返回的是base64字符串(直接使用) enhancedImageBase64 = imageData; + console.log(`[Enhance] ✅ API返回了base64字符串,长度: ${enhancedImageBase64.length} 字符`); } } else { + console.error(`[Enhance] ❌ 轮询结果未包含图片数据,taskResult.data:`, JSON.stringify(taskResult.data, null, 2)); return NextResponse.json( { error: "变清晰处理失败", detail: "轮询结果未包含图片数据" }, { status: 500 } @@ -467,15 +495,33 @@ export async function POST(request: NextRequest) { ); } + // ✅ 验证:检查处理后的图片大小(应该和原图不同) + const enhancedBuffer = Buffer.from(enhancedImageBase64, "base64"); + const enhancedImageSize = enhancedBuffer.length; + console.log(`[Enhance] 📊 处理后的图片大小: ${enhancedImageSize} bytes (${(enhancedImageSize / 1024 / 1024).toFixed(2)}MB)`); + console.log(`[Enhance] 📊 处理后的图片Base64长度: ${enhancedImageBase64.length} 字符`); + + // ✅ 对比:如果处理后的图片大小和原图完全相同,可能是返回了原图 + if (Math.abs(enhancedImageSize - originalImageSize) < 100) { + console.warn(`[Enhance] ⚠️ 警告:处理后的图片大小(${enhancedImageSize})和原图大小(${originalImageSize})几乎相同,可能API返回的是原图!`); + } else { + const sizeDiff = ((enhancedImageSize - originalImageSize) / originalImageSize * 100).toFixed(1); + console.log(`[Enhance] ✅ 图片大小变化: ${sizeDiff}% (${sizeDiff.startsWith("-") ? "减小" : "增大"})`); + } + // 5. 上传处理后的图片到S3存储桶 let thumbnailUrl: string; let originalUrl: string; try { + // ✅ 确认:上传的是处理后的图片(enhancedImageBase64) + console.log(`[Enhance] 📤 准备上传处理后的图片到S3,Base64长度: ${enhancedImageBase64.length}`); const uploadResult = await uploadBase64ToS3(enhancedImageBase64, "image/jpeg"); thumbnailUrl = uploadResult.thumbnail; originalUrl = uploadResult.original; console.log(`[Enhance] ✅ Images uploaded to S3 successfully`); + console.log(`[Enhance] ✅ 处理后的原图URL: ${originalUrl}`); + console.log(`[Enhance] ✅ 处理后的缩略图URL: ${thumbnailUrl}`); } catch (uploadError) { console.error("[Enhance] ❌ Failed to upload to S3:", uploadError); return NextResponse.json( diff --git a/components/image-annotator.tsx b/components/image-annotator.tsx index c3448fd..ffef1f9 100644 --- a/components/image-annotator.tsx +++ b/components/image-annotator.tsx @@ -549,15 +549,25 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel, initialResizeMod const result = await response.json(); if (result.success && result.image_base64) { - // 保存处理后的图片URL和Base64(优先使用original_url,确保下载的是原图) + // 保存处理后的图片URL和Base64(优先使用original_url,确保下载的是处理后的原图) console.log("[变清晰] API返回结果:", { hasOriginalUrl: !!result.original_url, hasThumbnailUrl: !!result.thumbnail_url, - originalUrl: result.original_url?.substring(0, 100), - thumbnailUrl: result.thumbnail_url?.substring(0, 100) + originalUrl: result.original_url, + thumbnailUrl: result.thumbnail_url, + base64Length: result.image_base64?.length || 0 }); + + // ✅ 验证:检查返回的URL是否是处理后的图片 if (result.original_url) { - console.log("[变清晰] ✅ 使用原图URL:", result.original_url); + console.log("[变清晰] ✅ 使用处理后的原图URL:", result.original_url); + console.log("[变清晰] ✅ URL应该包含 'enhance-orig' 标识,确认是处理后的图片"); + + // 验证URL格式(应该包含enhance-orig) + if (!result.original_url.includes("enhance-orig") && !result.original_url.includes("enhance-orig")) { + console.warn("[变清晰] ⚠️ 警告:URL不包含 'enhance-orig' 标识,可能不是处理后的图片!"); + } + setProcessedImageUrl(result.original_url); } else if (result.thumbnail_url) { console.warn("[变清晰] ⚠️ 未找到original_url,使用thumbnail_url作为备选:", result.thumbnail_url); @@ -940,7 +950,12 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel, initialResizeMod return; } - // 确保使用的是原图URL(检查URL中是否包含thumb标识) + // ✅ 验证:确认下载的是处理后的图片URL + console.log("[下载] 📥 开始下载,processType:", processType); + console.log("[下载] 📥 processedImageUrl:", processedImageUrl); + console.log("[下载] 📥 这个URL应该是处理后的图片,不是原图!"); + + // 确保使用的是处理后的原图URL(检查URL中是否包含thumb标识) let downloadUrl = processedImageUrl; // 更完善的缩略图URL转换逻辑 @@ -977,7 +992,16 @@ export function ImageAnnotator({ imageUrl, onConfirm, onCancel, initialResizeMod } } - console.log("[下载] 最终下载URL:", downloadUrl); + // ✅ 验证:确认下载URL是正确的 + console.log("[下载] ✅ 最终下载URL:", downloadUrl); + console.log("[下载] ✅ 这个URL应该指向处理后的图片(不是原图)"); + + // 如果是变清晰,验证URL应该包含enhance相关标识 + if (processType === "enhance") { + if (!downloadUrl.includes("enhance") && !downloadUrl.includes("1767358346590")) { + console.warn("[下载] ⚠️ 警告:变清晰下载URL不包含 'enhance' 标识,可能下载了错误的图片!"); + } + } // 从原图URL下载(原图已上传到S3) const response = await fetch(downloadUrl); diff --git a/图片变清晰压缩处理检查报告.md b/图片变清晰压缩处理检查报告.md new file mode 100644 index 0000000..ca5de43 --- /dev/null +++ b/图片变清晰压缩处理检查报告.md @@ -0,0 +1,65 @@ +# 图片变清晰压缩处理检查报告 + +## 检查结果 + +### ✅ 确认:原图没有压缩处理 + +从代码分析: + +1. **`uploadBase64ToS3` 函数** (`app/api/enhance/route.ts` 第36-82行): + ```typescript + // 第39行:将base64转换为buffer + const buffer = Buffer.from(base64Data, "base64"); + + // 第51行:只对缩略图调用 createThumbnail(压缩到500px,质量80%) + const thumbnailBuffer = await createThumbnail(buffer, mimeType); + + // 第58-61行:原图直接使用原始buffer,没有任何压缩处理 + const originalArrayBuffer = buffer.buffer.slice( + buffer.byteOffset, + buffer.byteOffset + buffer.byteLength + ) as ArrayBuffer; + + // 第66-67行:上传时,缩略图是压缩后的,原图是原始的 + uploadFile(originalFilename, originalArrayBuffer) // ← 原图直接上传,无压缩 + ``` + +2. **`uploadFile` 函数** (`lib/storage/service.ts`): + - 直接上传buffer,没有任何压缩处理 + - 只是简单的S3上传 + +### 结论 + +**原图(`originalUrl`)没有压缩处理,直接上传了外部API返回的图片。** + +--- + +## 问题分析 + +如果用户下载的图片是原图(处理前的),可能的原因: + +1. **外部API返回的就是原图**(没有真正处理) + - 外部API可能处理失败,返回了原图 + - 或者外部API配置有问题 + +2. **外部API返回的是压缩后的原图**(不是处理后的) + - 虽然文件大小不同(5.2MB → 2MB),但可能是压缩,不是变清晰处理 + +--- + +## 建议 + +1. **添加日志验证外部API返回的图片**: + - 打印外部API返回的完整数据结构 + - 对比原图和处理后图片的大小 + - 如果大小几乎相同,发出警告 + +2. **验证外部API是否真的处理了图片**: + - 检查外部API的配置 + - 确认外部API是否正常工作 + - 可能需要联系外部API提供商 + +3. **如果外部API返回的是原图,需要处理**: + - 返回错误给用户 + - 或者提示用户外部API处理失败 +