diff --git a/components/canvas/nodes/ImageNode.tsx b/components/canvas/nodes/ImageNode.tsx index 812c652d2..b79853317 100644 --- a/components/canvas/nodes/ImageNode.tsx +++ b/components/canvas/nodes/ImageNode.tsx @@ -2336,15 +2336,38 @@ export function ImageNode({ ? agentExecutionSnapshotId.slice(0, 8) : ""; const isMultiSelected = isSelected && selectedNodeIds.length > 1; - const compareSource = useMemo(() => { + const compareSourceInfo = useMemo(() => { const targetIdentity = normalizeImageIdentityUrl(data.src || ""); - if (!targetIdentity) return ""; + if (!targetIdentity) return { url: "", width: 0, height: 0 }; - const candidates: string[] = []; - const pushCandidate = (value: unknown) => { + const candidates: Array<{ height: number; url: string; width: number }> = []; + const resolveCandidateResolution = ( + sourceNode?: CanvasNode | null, + sourceData?: Partial | null + ) => { + const metadata = sourceData?.metadata || {}; + const metadataWidth = Number((metadata as any).originalWidth || 0); + const metadataHeight = Number((metadata as any).originalHeight || 0); + const nodeWidth = Number(sourceNode?.size?.width || 0); + const nodeHeight = Number(sourceNode?.size?.height || 0); + const width = metadataWidth > 0 ? metadataWidth : nodeWidth; + const height = metadataHeight > 0 ? metadataHeight : nodeHeight; + return { + width: Number.isFinite(width) && width > 0 ? width : 0, + height: Number.isFinite(height) && height > 0 ? height : 0, + }; + }; + const pushCandidate = ( + value: unknown, + sourceNode?: CanvasNode | null, + sourceData?: Partial | null + ) => { const raw = String(value || "").trim(); if (!raw) return; - candidates.push(raw); + candidates.push({ + url: raw, + ...resolveCandidateResolution(sourceNode, sourceData), + }); }; const visited = new Set([node.id]); @@ -2360,9 +2383,9 @@ export function ImageNode({ const sourceNode = allNodes.find((item) => item.id === sourceNodeId); if (!sourceNode || sourceNode.type !== "image") continue; const sourceData = (sourceNode.data as any) || {}; - pushCandidate(sourceData.src); - pushCandidate(sourceData.originalSrc); - pushCandidate(sourceData.metadata?.compareSourceUrl); + pushCandidate(sourceData.src, sourceNode, sourceData); + pushCandidate(sourceData.originalSrc, sourceNode, sourceData); + pushCandidate(sourceData.metadata?.compareSourceUrl, sourceNode, sourceData); if ( Array.isArray(sourceNode.connections) && @@ -2372,18 +2395,18 @@ export function ImageNode({ } } - pushCandidate(data.originalSrc); - pushCandidate(data.metadata?.compareSourceUrl); + pushCandidate(data.originalSrc, node, data); + pushCandidate(data.metadata?.compareSourceUrl, node, data); for (const candidate of candidates) { - const identity = normalizeImageIdentityUrl(candidate); + const identity = normalizeImageIdentityUrl(candidate.url); if (!identity) continue; if (identity !== targetIdentity) { return candidate; } } - return ""; + return { url: "", width: 0, height: 0 }; }, [ allNodes, data.metadata, @@ -2391,9 +2414,33 @@ export function ImageNode({ data.src, node.connections, node.id, + node.size.height, + node.size.width, ]); + const compareSource = compareSourceInfo.url; const hasCompareSource = Boolean(data.src) && Boolean(compareSource); + const compareImageFrameStyle = useMemo(() => { + const boxWidth = Math.max(1, Number(node.size.width || 0)); + const boxHeight = Math.max(1, Number(node.size.height || 0)); + const naturalWidth = Math.max(1, Number(compareSourceInfo.width || boxWidth)); + const naturalHeight = Math.max(1, Number(compareSourceInfo.height || boxHeight)); + const scale = Math.min(boxWidth / naturalWidth, boxHeight / naturalHeight); + const renderedWidth = Math.max(1, naturalWidth * scale); + const renderedHeight = Math.max(1, naturalHeight * scale); + + return { + height: renderedHeight, + left: (boxWidth - renderedWidth) / 2, + top: (boxHeight - renderedHeight) / 2, + width: renderedWidth, + }; + }, [ + compareSourceInfo.height, + compareSourceInfo.width, + node.size.height, + node.size.width, + ]); const compareButtonVisualSize = useMemo(() => { const minSide = Math.max( 1, @@ -8401,66 +8448,77 @@ export function ImageNode({ onPointerMove={(event) => { updateCompareSplitByClientX(event.clientX); }} - ref={compareFrameRef} style={{ touchAction: "none" }} >
-
- {displayTitle} { - if (event.currentTarget.src !== data.src) { - event.currentTarget.src = data.src; - } - }} - style={activeImageAdjustmentsStyle} - src={displayImageSrc} - /> - {renderImageAdjustmentOverlays()} -
-
-
- {`${displayTitle}-原图`} { - if (event.currentTarget.src !== compareSource) { - event.currentTarget.src = compareSource; - } +
+
+ {displayTitle} { + if (event.currentTarget.src !== data.src) { + event.currentTarget.src = data.src; + } + }} + src={displayImageSrc} + style={activeImageAdjustmentsStyle} + /> + +
+
+
+ {`${displayTitle}-原图`} { + if (event.currentTarget.src !== compareSource) { + event.currentTarget.src = compareSource; + } + }} + src={displayCompareSrc} + /> +
+
-
-
-
+
-
- 对比 -
+ 对比
原图