= 0
? "linear-gradient(135deg, rgba(255,188,109,0.9), rgba(255,232,194,0.42))"
: "linear-gradient(135deg, rgba(109,180,255,0.86), rgba(219,240,255,0.36))",
mixBlendMode: "soft-light",
opacity: temperatureOpacity,
}}
/>
) : null}
{tintOpacity > 0 ? (
= 0
? "linear-gradient(135deg, rgba(244,105,214,0.78), rgba(255,203,236,0.28))"
: "linear-gradient(135deg, rgba(76,214,141,0.76), rgba(194,255,221,0.28))",
mixBlendMode: "overlay",
opacity: tintOpacity,
}}
/>
) : null}
{softLightOpacity > 0 ? (
) : null}
{glowOpacity > 0 ? (
) : null}
{vignetteOpacity > 0 ? (
) : null}
{grainOpacity > 0 ? (
) : null}
>
);
}, [
activeImageAdjustments,
hasActiveImageAdjustments,
imageAdjustOverlayStyle,
]);
const cropPanelPosition = getCropPanelPosition();
const imageAdjustPanelPosition = getImageAdjustPanelPosition();
const toolbarPosition = getToolbarPosition();
const boxCutoutToolbarPosition = getBoxCutoutToolbarPosition();
const flipRotatePanelPosition = getFlipRotatePanelPosition();
const anglePanelPosition = getAnglePanelPosition();
const imageAdjustTabOptions = [
{
id: "light" as const,
label: "光线",
icon: SlidersHorizontal,
},
{
id: "color" as const,
label: "颜色",
icon: Blend,
},
{
id: "detail" as const,
label: "细节",
icon: CircleDot,
},
{
id: "effects" as const,
label: "效果",
icon: Box,
},
];
const imageAdjustSections: Record<
ImageAdjustPanelTab,
Array<{
key: ImageAdjustmentKey;
label: string;
min: number;
max: number;
trackClassName?: string;
}>
> = {
light: [
{ key: "light", label: "光线", min: -100, max: 100 },
{ key: "exposure", label: "曝光", min: -100, max: 100 },
{ key: "contrast", label: "对比度", min: -100, max: 100 },
{ key: "highlights", label: "高光", min: -100, max: 100 },
{ key: "shadows", label: "阴影", min: -100, max: 100 },
{ key: "whites", label: "白色", min: -100, max: 100 },
{ key: "blacks", label: "黑色", min: -100, max: 100 },
],
color: [
{ key: "vibrance", label: "自然饱和度", min: -100, max: 100 },
{ key: "saturation", label: "饱和度", min: -100, max: 100 },
{
key: "temperature",
label: "色温",
min: -100,
max: 100,
trackClassName: "h-[4px] bg-[linear-gradient(90deg,#4aa7ff,#f2c23a)]",
},
{
key: "tint",
label: "色调",
min: -100,
max: 100,
trackClassName: "h-[4px] bg-[linear-gradient(90deg,#ff66d7,#41d278)]",
},
],
detail: [
{ key: "sharpen", label: "锐化", min: 0, max: 100 },
{ key: "clarity", label: "清晰度", min: 0, max: 100 },
{ key: "grain", label: "颗粒", min: 0, max: 100 },
],
effects: [
{ key: "vignette", label: "晕影", min: 0, max: 100 },
{ key: "softLight", label: "柔光", min: 0, max: 100 },
{ key: "glow", label: "辉光", min: 0, max: 100 },
],
};
const boxCutoutHintText = boxCutoutSelection
? "确认后将仅抠出框选区域"
: isBoxCutoutDrawing
? "松开完成框选"
: "在图片中拖拽矩形框";
return (
<>
{/* 选中时在图片上方显示标题 */}
{isSelected && !isMultiSelected && data.src && !sceneFusionDialogOpen && (
{isEditingTitle ? (
setDraftTitle(e.target.value)}
onClick={(e) => e.stopPropagation()}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
handleSaveTitle();
} else if (e.key === "Escape") {
e.preventDefault();
setDraftTitle(displayTitle);
setIsEditingTitle(false);
}
}}
onMouseDown={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
value={draftTitle}
/>
) : (
{
e.stopPropagation();
setDraftTitle(displayTitle);
setIsEditingTitle(true);
}}
title="双击重命名"
>
{displayTitle}
)}
{resolutionLabel ? (
{resolutionLabel}
) : null}
)}
setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
ref={containerRef}
>
{/* 图片内容 - 使用 object-contain 保持原始比例 */}
{data.src ? (
{!shouldRequestDisplayImage ? (
) : isCompareMode && hasCompareSource ? (
{
event.stopPropagation();
updateCompareSplitByClientX(event.clientX);
}}
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;
}
}}
src={displayCompareSrc}
/>
<>
新图
原图
) : (
<>
![{displayTitle}]()
{
if (!isThisNodePicking && !boxCutoutMode) {
e.stopPropagation();
setFullscreenPreviewOpen(true);
}
}}
onError={(event) => {
if (event.currentTarget.src !== data.src) {
event.currentTarget.src = data.src;
}
}}
onLoad={refreshBoxCutoutMetrics}
ref={displayImageRef}
src={displayImageSrc}
style={activeImageAdjustmentsStyle}
/>
{renderImageAdjustmentOverlays()}
{shouldRenderDetailOverlay ? (
detailUiDslDocument ? (
) : (
)
) : null}
>
)}
{cropPanelOpen &&
!isThisNodePicking &&
!isCompareMode &&
boxCutoutMetrics &&
cropRectStyle &&
cropRect && (
{
event.preventDefault();
event.stopPropagation();
}}
onPointerCancel={handleCropPointerCancel}
onPointerDown={handleCropPointerDown}
onPointerMove={handleCropPointerMove}
onPointerUp={handleCropPointerUp}
ref={cropOverlayRef}
style={{
left: boxCutoutMetrics.offsetX,
top: boxCutoutMetrics.offsetY,
width: boxCutoutMetrics.renderedWidth,
height: boxCutoutMetrics.renderedHeight,
}}
>
{(
[
{ handle: "nw", className: "-left-3 -top-3 cursor-nwse-resize" },
{ handle: "ne", className: "-right-3 -top-3 cursor-nesw-resize" },
{ handle: "sw", className: "-left-3 -bottom-3 cursor-nesw-resize" },
{ handle: "se", className: "-right-3 -bottom-3 cursor-nwse-resize" },
{ handle: "n", className: "left-1/2 -top-3 -translate-x-1/2 cursor-ns-resize" },
{ handle: "s", className: "left-1/2 -bottom-3 -translate-x-1/2 cursor-ns-resize" },
{ handle: "w", className: "-left-3 top-1/2 -translate-y-1/2 cursor-ew-resize" },
{ handle: "e", className: "-right-3 top-1/2 -translate-y-1/2 cursor-ew-resize" },
] as const
).map((handleItem) => (
))}
)}
{boxCutoutMode && !isThisNodePicking && !isCompareMode && (
<>
{
event.preventDefault();
event.stopPropagation();
}}
onPointerCancel={handleBoxCutoutPointerCancel}
onPointerDown={handleBoxCutoutPointerDown}
onPointerMove={handleBoxCutoutPointerMove}
onPointerUp={handleBoxCutoutPointerUp}
/>
{activeBoxCutoutRectStyle ? (
) : (
)}
>
)}
{/* 🆕 拾取模式:当前点击位置(正在识别) */}
{isThisNodePicking && currentPickerClickStyle && (
)}
{/* 🆕 拾取模式:状态栏 */}
{isThisNodePicking && (
{isPickerLoading ? "正在识别..." : "点击标注物品"}
)}
{hasCompareSource &&
!isThisNodePicking &&
!isCompareMode &&
!boxCutoutMode &&
!cropPanelOpen &&
isSelected &&
!isMultiSelected && (
)}
) : data.status === "generating" ? (
{detailProgressLabel || "生成中..."}
图片处理中
) : data.status === "failed" ? (
) : (
上传图片
添加参考图、角色图或关键帧素材
{/* 隐藏的文件输入 */}
{/* 选择文件按钮 */}
)}
{/* 处理中遮罩 */}
{isProcessing && (
)}
{/* 工具栏使用 Portal 渲染到 body,避免被裁剪 */}
{/* 悬浮时的更多操作按钮 (右上角) */}
{isHovered &&
data.src &&
!isProcessing &&
!isSelected &&
hasHoverImageMoreMenu ? (
{imageRemoveBackgroundEnabled ? (
handleAction("rmbg")}>
{imageRemoveBackgroundItem.label}
) : null}
{imageRemoveWatermarkEnabled ? (
handleAction("watermark")}>
{imageRemoveWatermarkItem.label}
) : null}
{imageEnhanceEnabled ? (
handleAction("enhance")}>
{imageEnhanceItem.label}
) : null}
{imageNoteEnabled ? (
handleAction("note")}>
{imageNoteItem.label}
) : null}
{isLayerSplitEnabled && imageLayerSplitEnabledByToolbar ? (
handleAction("layer-split")}>
{imageLayerSplitItem.label}
) : null}
{imageResizeEnabled ? (
handleAction("resize")}>
{imageResizeItem.label}
) : null}
{imageMultiAngleEnabled ? (
handleAction("angle")}>
{imageMultiAngleItem.label}
) : null}
{imagePromptRegenerateEnabled ? (
handleAction("prompt-regenerate")}
>
{imagePromptRegenerateItem.label}
) : null}
{imageTextEditEnabled ? (
handleAction("text-edit")}>
{imageTextEditItem.label}
) : null}
{imageExtendEnabled ? (
handleAction("extend")}>
{imageExtendItem.label}
) : null}
{imageCropEnabled ? (
handleAction("crop")}>
{imageCropItem.label}
) : null}
{imageAdjustEnabled ? (
handleAction("adjust")}>
{imageAdjustItem.label}
) : null}
{imageFlipRotateEnabled ? (
handleAction("flip-rotate")}>
{imageFlipRotateItem.label}
) : null}
{imageRenameEnabled ? (
{
setDraftTitle(displayTitle);
setIsEditingTitle(true);
}}
>
{imageRenameItem.label}
) : null}
{hasHoverImageMorePrimaryActions &&
hasHoverImageMoreSecondaryActions ? (
) : null}
{imageDownloadEnabled ? (
{imageDownloadItem.label}
) : null}
{imageDeleteEnabled ? (
deleteNode(node.id)}
>
{imageDeleteItem.label}
) : null}
) : null}
{data.note && !isSelected && (
{imageNoteItem.label}
)}
{shortAgentExecutionSnapshotId ? (
) : null}
{/* 批量处理对话框 */}
{batchProcessingEnabled ? (
) : null}
{/* 提示词重绘对话框 */}
{/* 工具栏使用 Portal 渲染到 body,避免被裁剪 */}
{isSelected &&
!isMultiSelected &&
data.src &&
!isEditingTitle &&
!sceneFusionDialogOpen &&
!promptDialogOpen &&
!threedGenerationDialogMode &&
!notePanelOpen &&
!boxCutoutMode &&
!cropPanelOpen &&
typeof document !== "undefined" &&
createPortal(
e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
ref={toolbarRef}
style={{
top: toolbarPosition.top,
left: toolbarPosition.left,
transform: `scale(${FLOATING_TOOLBAR_SCALE})`,
transformOrigin: "top left",
pointerEvents: "auto",
maxWidth: `${Math.max(
180,
Math.floor(toolbarPosition.maxWidth / FLOATING_TOOLBAR_SCALE)
)}px`,
overflowX: "auto",
scrollbarWidth: "none",
}}
>
{imageAddToChatEnabled ? (
) : null}
{imageAddToChatEnabled && hasSelectedImagePrimaryToolbarActions ? (
) : null}
{imagePickObjectEnabled ? (
) : null}
{imageEnhanceEnabled ? (
) : null}
{imageRemoveBackgroundEnabled ? (
) : null}
{imageBoxCutoutEnabled ? (
) : null}
{imageRemoveWatermarkEnabled ? (
) : null}
{imageResizeEnabled ? (
) : null}
{imageTextEditEnabled ? (
) : null}
{imageMultiAngleEnabled ? (
) : null}
{imageGenerate3dModelEnabled ? (
) : null}
{imageGenerate3dWorldEnabled ? (
) : null}
{imageLayerSplitEnabled ? (
) : null}
{hasSelectedImagePrimaryToolbarActions &&
hasSelectedImageSecondaryToolbarActions ? (
) : null}
{hasSelectedImageMoreMenu ? (
{imageExtendEnabled ? (
handleAction("extend")}>
{imageExtendItem.label}
) : null}
{imageCropEnabled ? (
handleAction("crop")}>
{imageCropItem.label}
) : null}
{imageAdjustEnabled ? (
handleAction("adjust")}>
{imageAdjustItem.label}
) : null}
{imageFlipRotateEnabled ? (
handleAction("flip-rotate")}>
{imageFlipRotateItem.label}
) : null}
{imagePromptRegenerateEnabled ? (
handleAction("prompt-regenerate")}
>
{imagePromptRegenerateItem.label}
) : null}
{imageNoteEnabled ? (
handleAction("note")}>
{imageNoteItem.label}
) : null}
{hasSelectedImageMorePrimaryActions && imageDeleteEnabled ? (
) : null}
{imageDeleteEnabled ? (
deleteNode(node.id)}
>
{imageDeleteItem.label}
) : null}
) : null}
{imageDownloadEnabled ? (
) : null}
,
document.body
)}
{isSelected &&
!isMultiSelected &&
data.src &&
boxCutoutMode &&
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
ref={boxCutoutToolbarRef}
style={{
top: boxCutoutToolbarPosition.top,
left: boxCutoutToolbarPosition.left,
transform: `scale(${FLOATING_TOOLBAR_SCALE})`,
transformOrigin: "top left",
pointerEvents: "auto",
maxWidth: `${Math.max(
180,
Math.floor(boxCutoutToolbarPosition.maxWidth / FLOATING_TOOLBAR_SCALE)
)}px`,
overflowX: "auto",
scrollbarWidth: "none",
}}
>
{boxCutoutHintText}
,
document.body
)}
{/* 图片备注对话框 */}
{isSelected &&
cropPanelOpen &&
data.src &&
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
style={{
top: cropPanelPosition.top,
left: cropPanelPosition.left,
transform: `scale(${IMAGE_EDIT_PANEL_SCALE})`,
transformOrigin: "top left",
}}
>
{imageCropItem.label}
预设
{CROP_PRESET_GROUPS.map((group) => {
const expanded = cropExpandedGroups[group.key];
return (
{expanded ? (
{group.options.map((option) => {
const selected = cropPresetId === option.id;
return (
);
})}
) : null}
);
})}
,
document.body
)}
{isSelected &&
imageAdjustPanelOpen &&
data.src &&
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
style={{
top: imageAdjustPanelPosition.top,
left: imageAdjustPanelPosition.left,
transform: `scale(${IMAGE_EDIT_PANEL_SCALE})`,
transformOrigin: "top left",
}}
>
{imageAdjustItem.label}
{imageAdjustTabOptions.map((item) => {
const active = imageAdjustTab === item.id;
const Icon = item.icon;
return (
);
})}
{imageAdjustSections[imageAdjustTab].map((field) => (
setImageAdjustmentsDraft((prev) => ({
...prev,
[field.key]: value,
}))
}
trackClassName={field.trackClassName}
value={imageAdjustmentsDraft[field.key]}
/>
))}
,
document.body
)}
{isSelected &&
flipRotatePanelOpen &&
data.src &&
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
style={{
top: flipRotatePanelPosition.top,
left: flipRotatePanelPosition.left,
maxWidth: `${Math.floor(
flipRotatePanelPosition.maxWidth / IMAGE_EDIT_PANEL_SCALE
)}px`,
transform: `scale(${IMAGE_EDIT_PANEL_SCALE})`,
transformOrigin: "top left",
}}
>
{imageFlipRotateItem.label}
0°
恢复原图
水平翻转
垂直翻转
关闭
,
document.body
)}
{isSelected &&
anglePanelOpen &&
data.src &&
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
style={{
top: anglePanelPosition.top,
left: anglePanelPosition.left,
transform: `scale(${ANGLE_PANEL_SCALE})`,
transformOrigin: "top left",
}}
>
多角度
{(
[
{ id: "subject", label: "主体" },
{ id: "camera", label: "摄像头" },
] as const
).map((item) => {
const active = anglePanelMode === item.id;
return (
);
})}
{ANGLE_PREVIEW_VERTICAL_RING_ROTATIONS.map((rotation, index) => (
))}
{ANGLE_PREVIEW_HORIZONTAL_RING_ROTATIONS.map((rotation, index) => (
))}
{ANGLE_PREVIEW_DIAGONAL_RING_ROTATIONS.map((rotation, index) => (
))}
{anglePanelMode === "subject" ? (
) : (
)}
{anglePanelMode === "subject" ? (
) : null}
,
document.body
)}
{/* 文字编辑面板(显示在图片节点旁边) */}
{isSelected &&
textEditPanelOpen &&
data.src &&
typeof document !== "undefined" &&
createPortal(
e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onPointerDown={(e) => e.stopPropagation()}
style={{
top: getTextPanelPosition().top,
left: getTextPanelPosition().left,
}}
>
编辑文字
识别图片文字后可逐条修改或删除,应用后会在保持画面风格的前提下完成文字更新。
{isDetectingText && (
正在识别图片文字...
)}
{textEditError && !isDetectingText && (
{textEditError}
)}
{!isDetectingText &&
textEditItems.length === 0 &&
!textEditError && (
未识别到可编辑文字,可点击“重新识别”再试一次。
)}
{textEditItems.map((item, index) => (
文本 {index + 1}
{typeof item.confidence === "number" &&
` · 置信度 ${(item.confidence * 100).toFixed(0)}%`}
原文:{item.originalText}
handleTextItemChange(item.id, e.target.value)
}
placeholder="输入替换后的文字"
value={item.editedText}
/>
))}
{deletedTextItems.length > 0 && (
已标记删除 {deletedTextItems.length}{" "}
条文字,应用时会明确告诉生图模型移除这些文字并修复背景。
)}
,
document.body
)}
{/* 图片标注器 */}
{annotatorOpen && data.src && (
setAnnotatorOpen(false)}
onConfirm={handleAnnotateComplete}
onOpenChange={setAnnotatorOpen}
open={annotatorOpen}
/>
)}
{resizeAnnotatorOpen && data.src && (
setResizeAnnotatorOpen(false)}
onConfirm={handleResizeEditorComplete}
onOpenChange={setResizeAnnotatorOpen}
open={resizeAnnotatorOpen}
/>
)}
{/* 双击放大预览弹窗 */}
{fullscreenPreviewOpen &&
data.src &&
createPortal(
setFullscreenPreviewOpen(false)}
>
{/* 关闭按钮 */}
{/* 图片 */}
![{data.prompt]()
e.stopPropagation()}
src={fullscreenPreviewSrc}
style={activeImageAdjustmentsStyle}
/>
{/* 底部提示 */}
点击任意位置关闭
,
document.body
)}
>
);
}