Browse Source

裁剪使用先创建在调用接口

feature/071
yun 1 week ago
parent
commit
ce5fa9fdee
  1. 92
      src/components/nodes/GenerateImageNode.tsx

92
src/components/nodes/GenerateImageNode.tsx

@ -31,11 +31,9 @@ import { NodeActionCapsule, type NodeActionCapsuleAction } from "./NodeActionCap
import { SaveToAssetLibraryModal } from "@/components/SaveToAssetLibraryModal"; import { SaveToAssetLibraryModal } from "@/components/SaveToAssetLibraryModal";
import { MediaCropOverlay, type MediaCropAspectRatio, type MediaCropConfirmPayload } from "@/components/media/MediaCropOverlay"; import { MediaCropOverlay, type MediaCropAspectRatio, type MediaCropConfirmPayload } from "@/components/media/MediaCropOverlay";
import { CropRatioSelect, MEDIA_EDIT_TOOL, MediaEditToolbar, type MediaEditTool, type MediaEditToolOption } from "@/components/media/MediaEditToolbar"; import { CropRatioSelect, MEDIA_EDIT_TOOL, MediaEditToolbar, type MediaEditTool, type MediaEditToolOption } from "@/components/media/MediaEditToolbar";
import { createCroppedImageBlob } from "@/components/media/imageCropUtils";
import { uploadBlobToGatewayMedia } from "@/utils/gatewayMediaUpload";
import { SplitGridCapsuleMenu, type SplitGridSelection } from "@/components/media/SplitGridCapsuleMenu"; import { SplitGridCapsuleMenu, type SplitGridSelection } from "@/components/media/SplitGridCapsuleMenu";
import { createSplitGridImageNodes } from "@/utils/splitGridNodes"; import { createSplitGridImageNodes } from "@/utils/splitGridNodes";
import { createDerivedImageNode } from "@/utils/derivedImageNodes"; import { createPendingDerivedImageNode } from "@/utils/derivedImageNodes";
import { SplitGridSelectionOverlay } from "@/components/media/SplitGridSelectionOverlay"; import { SplitGridSelectionOverlay } from "@/components/media/SplitGridSelectionOverlay";
import { SplitGridSelectionToolbar } from "@/components/media/SplitGridSelectionToolbar"; import { SplitGridSelectionToolbar } from "@/components/media/SplitGridSelectionToolbar";
import { getAutoMediaElementClassName, getAutoMediaFrameClassName } from "./mediaAutoSize"; import { getAutoMediaElementClassName, getAutoMediaFrameClassName } from "./mediaAutoSize";
@ -91,7 +89,6 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
const [activeMediaTool, setActiveMediaTool] = useState<MediaEditTool>(MEDIA_EDIT_TOOL.crop); const [activeMediaTool, setActiveMediaTool] = useState<MediaEditTool>(MEDIA_EDIT_TOOL.crop);
const [cropAspectRatio, setCropAspectRatio] = useState<MediaCropAspectRatio>("original"); const [cropAspectRatio, setCropAspectRatio] = useState<MediaCropAspectRatio>("original");
const [cropPayload, setCropPayload] = useState<MediaCropConfirmPayload | null>(null); const [cropPayload, setCropPayload] = useState<MediaCropConfirmPayload | null>(null);
const [isCropUploading, setIsCropUploading] = useState(false);
const [isSplitGridRunning, setIsSplitGridRunning] = useState(false); const [isSplitGridRunning, setIsSplitGridRunning] = useState(false);
const [gridSelection, setGridSelection] = useState<SplitGridSelection | null>(null); const [gridSelection, setGridSelection] = useState<SplitGridSelection | null>(null);
const [selectedGridCellKeys, setSelectedGridCellKeys] = useState<Set<string>>(() => new Set()); const [selectedGridCellKeys, setSelectedGridCellKeys] = useState<Set<string>>(() => new Set());
@ -205,57 +202,40 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
}, nextItem.dimensions ?? null); }, nextItem.dimensions ?? null);
}, [id, nodeData.imageHistory, nodeData.selectedHistoryIndex, updateMediaNodeData, updateNodeData]); }, [id, nodeData.imageHistory, nodeData.selectedHistoryIndex, updateMediaNodeData, updateNodeData]);
const handleConfirmCrop = useCallback(async (payload: MediaCropConfirmPayload) => { const handleConfirmCrop = useCallback((payload: MediaCropConfirmPayload) => {
const sourceImage = nodeData.outputImage || displayImage; const currentNode = getNodeById(id);
if (!sourceImage) return; if (!currentNode) return;
let blob: Blob | null = null; const currentPosition = currentNode.position ?? { x: 0, y: 0 };
try { const currentWidth = typeof currentNode.width === "number"
blob = await createCroppedImageBlob(sourceImage, payload); ? currentNode.width
} catch { : typeof currentNode.style?.width === "number"
alert(t("imageInput.cropFailed")); ? currentNode.style.width
return; : 300;
} const filename = `crop-${Date.now()}.png`;
const nodeId = createPendingDerivedImageNode({
if (!blob) { sourceNodeId: id,
alert(t("imageInput.cropFailed")); position: {
return; x: currentPosition.x + currentWidth + 220,
} y: currentPosition.y,
},
setIsCropUploading(true); filename,
try { customTitle: t("imageInput.crop"),
const filename = `crop-${Date.now()}.png`; operation: "crop",
const uploaded = await uploadBlobToGatewayMedia(blob, filename, "image/png", "image"); task: {
const currentNode = getNodeById(id); cropRect: payload.cropRect,
const currentPosition = currentNode?.position ?? { x: 0, y: 0 }; outputWidth: payload.outputWidth,
const currentWidth = typeof currentNode?.width === "number" outputHeight: payload.outputHeight,
? currentNode.width aspectRatio: payload.aspectRatio,
: typeof currentNode?.style?.width === "number" },
? currentNode.style.width addNode,
: 300; onConnect,
createDerivedImageNode({ selectSingleNode,
sourceNodeId: id, });
position: { setIsCropping(false);
x: currentPosition.x + currentWidth + 220, setCropPayload(null);
y: currentPosition.y, void regenerateNode(nodeId);
}, }, [addNode, getNodeById, id, onConnect, regenerateNode, selectSingleNode, t]);
image: uploaded.url,
previewImage: uploaded.previewUrl,
filename,
dimensions: { width: payload.outputWidth, height: payload.outputHeight },
customTitle: t("imageInput.crop"),
operation: "crop",
addNode,
onConnect,
selectSingleNode,
});
setIsCropping(false);
} catch (error) {
alert(error instanceof Error ? error.message : t("imageInput.cropFailed"));
} finally {
setIsCropUploading(false);
}
}, [addNode, displayImage, getNodeById, id, nodeData.outputImage, onConnect, selectSingleNode, t]);
const handleStartGridSelection = useCallback((selection: SplitGridSelection) => { const handleStartGridSelection = useCallback((selection: SplitGridSelection) => {
setIsCropping(false); setIsCropping(false);
@ -564,7 +544,6 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
<MediaEditToolbar <MediaEditToolbar
activeTool={activeMediaTool} activeTool={activeMediaTool}
tools={IMAGE_MEDIA_EDIT_TOOLS} tools={IMAGE_MEDIA_EDIT_TOOLS}
busy={isCropUploading}
onCancel={() => setIsCropping(false)} onCancel={() => setIsCropping(false)}
context={{ context={{
value: cropAspectRatio, value: cropAspectRatio,
@ -629,7 +608,6 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
naturalWidth={overlayImageDimensions?.width} naturalWidth={overlayImageDimensions?.width}
naturalHeight={overlayImageDimensions?.height} naturalHeight={overlayImageDimensions?.height}
aspectRatio={cropAspectRatio} aspectRatio={cropAspectRatio}
busy={isCropUploading}
onCropChange={setCropPayload} onCropChange={setCropPayload}
/> />
)} )}

Loading…
Cancel
Save