From 7ba2a64da7b3c50afa982ee10c0ea73927a42560 Mon Sep 17 00:00:00 2001 From: XianYuDaXian Date: Fri, 13 Mar 2026 22:28:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E7=B2=98=E8=B4=B4=E6=A0=BC=E5=BC=8F=E5=85=BC=E5=AE=B9=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/static/public/js/imagine_workbench.js | 57 ++++++++++++++++++----- app/static/public/js/video.js | 57 +++++++++++++++++------ 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/app/static/public/js/imagine_workbench.js b/app/static/public/js/imagine_workbench.js index 0e50cb8..c465ce3 100644 --- a/app/static/public/js/imagine_workbench.js +++ b/app/static/public/js/imagine_workbench.js @@ -969,22 +969,55 @@ renderReferenceStrip(); } + function inferImageMimeFromName(name) { + const lower = String(name || '').trim().toLowerCase(); + if (lower.endsWith('.png')) return 'image/png'; + if (lower.endsWith('.jpg') || lower.endsWith('.jpeg')) return 'image/jpeg'; + if (lower.endsWith('.webp')) return 'image/webp'; + if (lower.endsWith('.gif')) return 'image/gif'; + if (lower.endsWith('.bmp')) return 'image/bmp'; + if (lower.endsWith('.svg')) return 'image/svg+xml'; + if (lower.endsWith('.avif')) return 'image/avif'; + if (lower.endsWith('.heic')) return 'image/heic'; + if (lower.endsWith('.heif')) return 'image/heif'; + if (lower.endsWith('.tif') || lower.endsWith('.tiff')) return 'image/tiff'; + if (lower.endsWith('.ico')) return 'image/x-icon'; + return ''; + } + + function normalizeImageFile(file, fallbackMime = '') { + if (!(file instanceof Blob)) return null; + const detectedMime = String(file.type || fallbackMime || inferImageMimeFromName(file.name) || '').trim(); + if (!detectedMime.startsWith('image/')) return null; + if (String(file.type || '').trim()) { + return file; + } + const safeName = String(file.name || '').trim() || `clipboard.${detectedMime.split('/')[1] || 'png'}`; + try { + return new File([file], safeName, { type: detectedMime }); + } catch (e) { + const blob = file.slice(0, file.size, detectedMime); + blob.name = safeName; + return blob; + } + } + function pickImageFilesFromDataTransfer(dataTransfer) { if (!dataTransfer) return []; const files = []; - const pushIfImage = (file) => { - if (!file) return; - if (!String(file.type || '').startsWith('image/')) return; - files.push(file); + const pushIfImage = (file, fallbackMime = '') => { + const normalized = normalizeImageFile(file, fallbackMime); + if (!normalized) return; + files.push(normalized); }; if (dataTransfer.files && dataTransfer.files.length) { - Array.from(dataTransfer.files).forEach(pushIfImage); + Array.from(dataTransfer.files).forEach((file) => pushIfImage(file)); } - if (!files.length && dataTransfer.items && dataTransfer.items.length) { + if (dataTransfer.items && dataTransfer.items.length) { Array.from(dataTransfer.items).forEach((item) => { if (!item || item.kind !== 'file') return; const file = item.getAsFile ? item.getAsFile() : null; - pushIfImage(file); + pushIfImage(file, String(item.type || '').trim()); }); } return files; @@ -1007,14 +1040,14 @@ let added = 0; for (const file of targets) { - const mimeType = String(file.type || ''); - if (mimeType && !mimeType.startsWith('image/')) continue; - const dataUrl = await readFileAsDataUrl(file); + const normalizedFile = normalizeImageFile(file); + if (!normalizedFile) continue; + const dataUrl = await readFileAsDataUrl(normalizedFile); if (!dataUrl.startsWith('data:image/')) continue; state.referenceImages.push({ id: buildRefId(), - name: file.name || source || '未命名图片', - mime: file.type || '', + name: normalizedFile.name || source || '未命名图片', + mime: normalizedFile.type || '', data: dataUrl, source: source || 'upload', isPrimary: false, diff --git a/app/static/public/js/video.js b/app/static/public/js/video.js index 992e7f4..aabee5b 100644 --- a/app/static/public/js/video.js +++ b/app/static/public/js/video.js @@ -1256,6 +1256,39 @@ }); } + function inferImageMimeFromName(name) { + const lower = String(name || '').trim().toLowerCase(); + if (lower.endsWith('.png')) return 'image/png'; + if (lower.endsWith('.jpg') || lower.endsWith('.jpeg')) return 'image/jpeg'; + if (lower.endsWith('.webp')) return 'image/webp'; + if (lower.endsWith('.gif')) return 'image/gif'; + if (lower.endsWith('.bmp')) return 'image/bmp'; + if (lower.endsWith('.svg')) return 'image/svg+xml'; + if (lower.endsWith('.avif')) return 'image/avif'; + if (lower.endsWith('.heic')) return 'image/heic'; + if (lower.endsWith('.heif')) return 'image/heif'; + if (lower.endsWith('.tif') || lower.endsWith('.tiff')) return 'image/tiff'; + if (lower.endsWith('.ico')) return 'image/x-icon'; + return ''; + } + + function normalizeImageFile(file, fallbackMime = '') { + if (!(file instanceof Blob)) return null; + const detectedMime = String(file.type || fallbackMime || inferImageMimeFromName(file.name) || '').trim(); + if (!detectedMime.startsWith('image/')) return null; + if (String(file.type || '').trim()) { + return file; + } + const safeName = String(file.name || '').trim() || `clipboard.${detectedMime.split('/')[1] || 'png'}`; + try { + return new File([file], safeName, { type: detectedMime }); + } catch (e) { + const blob = file.slice(0, file.size, detectedMime); + blob.name = safeName; + return blob; + } + } + function hasFiles(dataTransfer) { if (!dataTransfer) return false; if (dataTransfer.files && dataTransfer.files.length > 0) return true; @@ -1267,19 +1300,19 @@ function pickImageFilesFromDataTransfer(dataTransfer) { if (!dataTransfer) return []; const files = []; - const pushIfImage = (file) => { - if (!file) return; - if (!String(file.type || '').startsWith('image/')) return; - files.push(file); + const pushIfImage = (file, fallbackMime = '') => { + const normalized = normalizeImageFile(file, fallbackMime); + if (!normalized) return; + files.push(normalized); }; if (dataTransfer.files && dataTransfer.files.length) { - Array.from(dataTransfer.files).forEach(pushIfImage); + Array.from(dataTransfer.files).forEach((file) => pushIfImage(file)); } - if (!files.length && dataTransfer.items && dataTransfer.items.length) { + if (dataTransfer.items && dataTransfer.items.length) { Array.from(dataTransfer.items).forEach((item) => { if (!item || item.kind !== 'file') return; const file = item.getAsFile ? item.getAsFile() : null; - pushIfImage(file); + pushIfImage(file, String(item.type || '').trim()); }); } return files; @@ -1301,11 +1334,9 @@ const accepted = targets.slice(0, slotsLeft); let added = 0; for (const file of accepted) { - const mimeType = String(file.type || ''); - if (mimeType && !mimeType.startsWith('image/')) { - continue; - } - const dataUrl = await readFileAsDataUrl(file); + const normalizedFile = normalizeImageFile(file); + if (!normalizedFile) continue; + const dataUrl = await readFileAsDataUrl(normalizedFile); if (!dataUrl.startsWith('data:image/')) { continue; } @@ -1315,7 +1346,7 @@ sourceUrl: dataUrl, url: dataUrl, parentPostId: '', - name: file.name || sourceLabel || '已选择图片', + name: normalizedFile.name || sourceLabel || '已选择图片', mentionLabel: getReferenceMentionLabel(referenceImages.length) }); added += 1;