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 { MediaCropOverlay, type MediaCropAspectRatio, type MediaCropConfirmPayload } from "@/components/media/MediaCropOverlay";
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 { createSplitGridImageNodes } from "@/utils/splitGridNodes";
import { createDerivedImageNode } from "@/utils/derivedImageNodes";
import { createPendingDerivedImageNode } from "@/utils/derivedImageNodes";
import { SplitGridSelectionOverlay } from "@/components/media/SplitGridSelectionOverlay";
import { SplitGridSelectionToolbar } from "@/components/media/SplitGridSelectionToolbar";
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 [cropAspectRatio, setCropAspectRatio] = useState<MediaCropAspectRatio>("original");
const [cropPayload, setCropPayload] = useState<MediaCropConfirmPayload | null>(null);
const [isCropUploading, setIsCropUploading] = useState(false);
const [isSplitGridRunning, setIsSplitGridRunning] = useState(false);
const [gridSelection, setGridSelection] = useState<SplitGridSelection | null>(null);
const [selectedGridCellKeys, setSelectedGridCellKeys] = useState<Set<string>>(() => new Set());
@ -205,57 +202,40 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
}, nextItem.dimensions ?? null);
}, [id, nodeData.imageHistory, nodeData.selectedHistoryIndex, updateMediaNodeData, updateNodeData]);
const handleConfirmCrop = useCallback(async (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 currentPosition = currentNode?.position ?? { x: 0, y: 0 };
const currentWidth = typeof currentNode?.width === "number"
? currentNode.width
: typeof currentNode?.style?.width === "number"
? currentNode.style.width
: 300;
createDerivedImageNode({
sourceNodeId: id,
position: {
x: currentPosition.x + currentWidth + 220,
y: currentPosition.y,
},
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 handleConfirmCrop = useCallback((payload: MediaCropConfirmPayload) => {
const currentNode = getNodeById(id);
if (!currentNode) return;
const currentPosition = currentNode.position ?? { x: 0, y: 0 };
const currentWidth = typeof currentNode.width === "number"
? currentNode.width
: typeof currentNode.style?.width === "number"
? currentNode.style.width
: 300;
const filename = `crop-${Date.now()}.png`;
const nodeId = createPendingDerivedImageNode({
sourceNodeId: id,
position: {
x: currentPosition.x + currentWidth + 220,
y: currentPosition.y,
},
filename,
customTitle: t("imageInput.crop"),
operation: "crop",
task: {
cropRect: payload.cropRect,
outputWidth: payload.outputWidth,
outputHeight: payload.outputHeight,
aspectRatio: payload.aspectRatio,
},
addNode,
onConnect,
selectSingleNode,
});
setIsCropping(false);
setCropPayload(null);
void regenerateNode(nodeId);
}, [addNode, getNodeById, id, onConnect, regenerateNode, selectSingleNode, t]);
const handleStartGridSelection = useCallback((selection: SplitGridSelection) => {
setIsCropping(false);
@ -564,7 +544,6 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
<MediaEditToolbar
activeTool={activeMediaTool}
tools={IMAGE_MEDIA_EDIT_TOOLS}
busy={isCropUploading}
onCancel={() => setIsCropping(false)}
context={{
value: cropAspectRatio,
@ -629,7 +608,6 @@ export function GenerateImageNodeView({ id, data, selected }: GenerateImageNodeV
naturalWidth={overlayImageDimensions?.width}
naturalHeight={overlayImageDimensions?.height}
aspectRatio={cropAspectRatio}
busy={isCropUploading}
onCropChange={setCropPayload}
/>
)}

Loading…
Cancel
Save