fix(canvas): 图片生成尺寸 - 显式比例不再被参考图节点尺寸覆盖

This commit is contained in:
ddCat committed 2026-07-31 21:18:43 +08:00
1 parent adb22c9075
commit 8006149370
4 files changed
+40 -15

No files matched your search

@@ -48,10 +48,11 @@ export async function executeImageGeneration({
const parentConfig = NODE_DEFAULT_SIZE[isConfigNode ? CanvasNodeType.Config : isImageNode ? CanvasNodeType.Image : CanvasNodeType.Text];
const imageDefaults = NODE_DEFAULT_SIZE[CanvasNodeType.Image];
// 生成中占位框按设置比例显示,避免 16:9 任务显示成默认 340x240。
const imageConfig = nodeSizeFromRatio(generationConfig.size || "auto", imageDefaults.width, imageDefaults.height) || imageDefaults;
// 单图图生图沿用来源节点的可视尺寸,避免竖图回落到默认横向框后被压成窄卡片。
const requestedImageSize = nodeSizeFromRatio(generationConfig.size || "auto", imageDefaults.width, imageDefaults.height);
const imageConfig = requestedImageSize || imageDefaults;
// auto 图生图沿用来源节点尺寸;用户明确选择比例时必须以目标比例创建节点。
const referenceNode = referenceImages.length === 1 ? canvasNodes.find((node) => node.id === referenceImages[0].id && node.type === CanvasNodeType.Image) : undefined;
const imageSizeSource = isImageNode && sourceNode?.metadata?.content ? sourceNode : referenceNode;
const imageSizeSource = requestedImageSize ? undefined : (isImageNode && sourceNode?.metadata?.content ? sourceNode : referenceNode);
const outputNodeSize = imageSizeSource ? { width: imageSizeSource.width, height: imageSizeSource.height } : imageConfig;
const parentPosition = sourceNode?.position || { x: 0, y: 0 };
const parentWidth = sourceNode?.width || parentConfig.width;
@@ -5,7 +5,7 @@ import { buildNodeGenerationContext, hydrateNodeGenerationContext } from "@/comp
import type { CanvasNodeGenerationMode } from "@/components/canvas/canvas-node-prompt-panel";
import { NODE_DEFAULT_SIZE } from "@/constant/canvas";
import { audioMetadata, imageMetadata, videoMetadata } from "@/lib/canvas/canvas-generation-task-sync";
import { fitNodeSize, VIDEO_NODE_MAX_SIZE } from "@/lib/canvas/canvas-node-size";
import { fitNodeSize, nodeSizeFromRatio, VIDEO_NODE_MAX_SIZE } from "@/lib/canvas/canvas-node-size";
import { buildEmotionImageArtifacts, compositeEmotionImage, emotionGenerationSize } from "@/lib/canvas/canvas-emotion";
import {
buildAudioGenerationMetadata,
@@ -192,13 +192,14 @@ export function useCanvasGenerationRetry({ projectId, domainProjectId, activated
if (!image?.dataUrl) throw new Error("后端任务没有返回图片");
const uploadedImage = await uploadImage(image.dataUrl);
const imageConfig = NODE_DEFAULT_SIZE[CanvasNodeType.Image];
const imageSize = useReferenceImages
const requestedImageSize = nodeSizeFromRatio(generationConfig.size || "auto", imageConfig.width, imageConfig.height);
const imageSize = useReferenceImages && !requestedImageSize
? { width: node.width, height: node.height }
: fitNodeSize(uploadedImage.width, uploadedImage.height, imageConfig.width, imageConfig.height);
: fitNodeSize(uploadedImage.width, uploadedImage.height, requestedImageSize?.width || imageConfig.width, requestedImageSize?.height || imageConfig.height);
const generationMetadata = savedImageMetadata?.generationType
? { generationType: savedImageMetadata.generationType, model: generationConfig.model, size: generationConfig.size, quality: generationConfig.quality, transparentBackground: generationConfig.transparentBackground, count: savedImageMetadata.count || 1, references: savedImageMetadata.references }
: buildImageGenerationMetadata(useReferenceImages ? "edit" : "generation", generationConfig, 1, retryImages);
setNodes((current) => current.map((item) => (item.id === node.id ? { ...item, type: CanvasNodeType.Image, width: imageSize.width, height: imageSize.height, metadata: { ...item.metadata, ...imageMetadata(uploadedImage), prompt, ...generationMetadata } } : item)));
setNodes((current) => current.map((item) => (item.id === node.id ? { ...item, type: CanvasNodeType.Image, position: { x: item.position.x + item.width / 2 - imageSize.width / 2, y: item.position.y + item.height / 2 - imageSize.height / 2 }, width: imageSize.width, height: imageSize.height, metadata: { ...item.metadata, ...imageMetadata(uploadedImage), prompt, ...generationMetadata } } : item)));
} catch (error) {
if (isGenerationCanceled(error)) return;
const failure = generationFailureMetadata(error, retryPromptSource);