diff --git a/components/canvas/LiblibVideoCanvasReplica.tsx b/components/canvas/LiblibVideoCanvasReplica.tsx index d8ab6aa45..5adbd86ec 100644 --- a/components/canvas/LiblibVideoCanvasReplica.tsx +++ b/components/canvas/LiblibVideoCanvasReplica.tsx @@ -5375,14 +5375,54 @@ export function LiblibVideoCanvasReplica({ }; }, []); + const readImageIntrinsicSize = useCallback(async (file: File) => { + if (!file.type.startsWith("image/")) return null; + try { + const bitmap = await createImageBitmap(file); + const size = { width: bitmap.width, height: bitmap.height }; + bitmap.close(); + return size; + } catch { + try { + return await new Promise<{ width: number; height: number }>((resolve, reject) => { + const url = URL.createObjectURL(file); + const image = new Image(); + image.onload = () => { + URL.revokeObjectURL(url); + resolve({ width: image.naturalWidth, height: image.naturalHeight }); + }; + image.onerror = () => { + URL.revokeObjectURL(url); + reject(new Error("image decode failed")); + }; + image.src = url; + }); + } catch { + return null; + } + } + }, []); + const addUploadedFilesAtPoint = useCallback( - (files: File[], center: { x: number; y: number }, connectTargetId?: string) => { + async (files: File[], center: { x: number; y: number }, connectTargetId?: string) => { if (files.length === 0) return; const { files: batch, errors } = prepareCanvasMediaFiles(files); if (errors.length) toast.error(errors.slice(0, 3).join("\n")); if (!batch.length) return; + const sizes = await Promise.all(batch.map(file => readImageIntrinsicSize(file))); const newNodes = batch.map((file, index) => { const created = createUploadedMediaNode(file, "", 0, 0, nodes.length + index + 1); + const size = sizes[index]; + if (size && size.width > 0 && size.height > 0) { + const aspect = size.width / size.height; + if (aspect >= 1) { + created.width = 420; + created.height = Math.min(560, Math.max(180, Math.round(420 / aspect))); + } else { + created.height = 560; + created.width = Math.min(420, Math.max(220, Math.round(560 * aspect))); + } + } return { ...created, x: Math.round(center.x - created.width / 2 + index * 450), y: Math.round(center.y - created.height / 2), draftValues: { ...created.draftValues, uploadStatus: "uploading" } }; @@ -5412,12 +5452,12 @@ export function LiblibVideoCanvasReplica({ } }); }, - [addNodes, nodes.length, uploadCanvasMediaFile] + [addNodes, nodes.length, readImageIntrinsicSize, uploadCanvasMediaFile] ); const addUploadedFiles = useCallback( (files: File[]) => { - addUploadedFilesAtPoint(files, toCanvasPoint(window.innerWidth / 2, window.innerHeight / 2)); + void addUploadedFilesAtPoint(files, toCanvasPoint(window.innerWidth / 2, window.innerHeight / 2)); }, [addUploadedFilesAtPoint, toCanvasPoint] ); @@ -5763,7 +5803,7 @@ export function LiblibVideoCanvasReplica({ const addCanvasCommandUploadedFiles = useCallback( (files: File[]) => { if (!canvasCommand) return; - addUploadedFilesAtPoint(files, { x: canvasCommand.canvasX, y: canvasCommand.canvasY }); + void addUploadedFilesAtPoint(files, { x: canvasCommand.canvasX, y: canvasCommand.canvasY }); }, [addUploadedFilesAtPoint, canvasCommand] ); @@ -10111,7 +10151,7 @@ export function LiblibVideoCanvasReplica({ if (isBusy) { toast.error("画布正在加载,请稍候再拖入素材"); return; } const files = Array.from(event.dataTransfer.files); if (!files.length) { toast.error("未能读取拖入的文件,请从桌面直接拖拽素材后松开"); return; } - addUploadedFilesAtPoint(files, toCanvasPoint(event.clientX, event.clientY)); + void addUploadedFilesAtPoint(files, toCanvasPoint(event.clientX, event.clientY)); }} >
@@ -10547,7 +10587,7 @@ export function LiblibVideoCanvasReplica({ setNodes(current => current.map(node => node.id === selectedNode.id ? {...node,draftValues:{...node.draftValues,smartEditDraft:{...(node.draftValues?.smartEditDraft as Record || {}),assets:((node.draftValues?.smartEditDraft as Record)?.assets || []).filter((asset:{id:string}) => asset.id !== source)}}} : node)); }} onReference={() => setLineConnectState({sourceId:null,targetId:selectedNode.id,cursorCanvasX:selectedNode.x-80,cursorCanvasY:selectedNode.y+selectedNode.height/2})} - onUpload={files => addUploadedFilesAtPoint(files,{x:selectedNode.x-600,y:selectedNode.y},selectedNode.id)} + onUpload={files => void addUploadedFilesAtPoint(files,{x:selectedNode.x-600,y:selectedNode.y},selectedNode.id)} onSubmit={async () => { assertConnectedInputsReady(selectedTargetSourceNodes); const draft = resolveSmartEditIntent((selectedNode.draftValues?.smartEditDraft || {}) as Record);