Browse Source

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

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

58
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;
if (!sourceImage) return;
let blob: Blob | null = null;
try {
blob = await createCroppedImageBlob(sourceImage, payload);
} catch {
alert(t("imageInput.cropFailed"));
return;
}
if (!blob) {
alert(t("imageInput.cropFailed"));
return;
}
setIsCropUploading(true);
try {
const filename = `crop-${Date.now()}.png`;
const uploaded = await uploadBlobToGatewayMedia(blob, filename, "image/png", "image");
const currentNode = getNodeById(id); const currentNode = getNodeById(id);
const currentPosition = currentNode?.position ?? { x: 0, y: 0 }; if (!currentNode) return;
const currentWidth = typeof currentNode?.width === "number"
const currentPosition = currentNode.position ?? { x: 0, y: 0 };
const currentWidth = typeof currentNode.width === "number"
? currentNode.width ? currentNode.width
: typeof currentNode?.style?.width === "number" : typeof currentNode.style?.width === "number"
? currentNode.style.width ? currentNode.style.width
: 300; : 300;
createDerivedImageNode({ const filename = `crop-${Date.now()}.png`;
const nodeId = createPendingDerivedImageNode({
sourceNodeId: id, sourceNodeId: id,
position: { position: {
x: currentPosition.x + currentWidth + 220, x: currentPosition.x + currentWidth + 220,
y: currentPosition.y, y: currentPosition.y,
}, },
image: uploaded.url,
previewImage: uploaded.previewUrl,
filename, filename,
dimensions: { width: payload.outputWidth, height: payload.outputHeight },
customTitle: t("imageInput.crop"), customTitle: t("imageInput.crop"),
operation: "crop", operation: "crop",
task: {
cropRect: payload.cropRect,
outputWidth: payload.outputWidth,
outputHeight: payload.outputHeight,
aspectRatio: payload.aspectRatio,
},
addNode, addNode,
onConnect, onConnect,
selectSingleNode, selectSingleNode,
}); });
setIsCropping(false); setIsCropping(false);
} catch (error) { setCropPayload(null);
alert(error instanceof Error ? error.message : t("imageInput.cropFailed")); void regenerateNode(nodeId);
} finally { }, [addNode, getNodeById, id, onConnect, regenerateNode, selectSingleNode, t]);
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