feat: add ComfyUI integration for image generation and management
- Implemented ComfyGenerateRequest type and associated functions for generating images using various architectures and modes. - Added functions for listing generation options and handling image uploads. - Created workflows for different generation modes including SDXL, Z-Image, Z-Image Turbo, and Anima. - Introduced GenerationJobStatus component to display the status of ongoing generation jobs. - Developed MaskControls for managing mask operations and displaying mask analysis. - Created palette items for tool selection, layer management, and generation settings.
This commit is contained in:
64
commands/transform-document.ts
Normal file
64
commands/transform-document.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { ImageDocument } from "@core/document";
|
||||
import type { Rect } from "@core/geometry";
|
||||
import type { LayerId } from "@core/id";
|
||||
import type { Layer } from "@core/layer";
|
||||
import { getLayerMask } from "@core/layer-mask-utils";
|
||||
import { resolveTransformTargetBounds } from "@editor/transform-targets";
|
||||
import type { TransformTarget } from "@editor/transform";
|
||||
|
||||
export function applyTransformTargetBounds(document: ImageDocument, target: TransformTarget, bounds: Rect): ImageDocument {
|
||||
if (target.type === "artboard") return { ...document, artboards: document.artboards.map((artboard) => artboard.id === target.id ? { ...artboard, bounds: { ...bounds } } : artboard) };
|
||||
const layer = findLayer(document, target.id);
|
||||
if (!layer) return document;
|
||||
return layer.type === "group" ? applyGroupBounds(document, layer.id, bounds) : applyLeafBounds(document, layer.id, bounds);
|
||||
}
|
||||
|
||||
function applyLeafBounds(document: ImageDocument, layerId: LayerId, bounds: Rect): ImageDocument {
|
||||
const layer = findLayer(document, layerId);
|
||||
if (!layer) return document;
|
||||
const mask = getLayerMask(layer);
|
||||
return [layerId, ...(mask ? [mask.maskLayerId] : [])].reduce((next, id) => ({
|
||||
...next,
|
||||
artboards: next.artboards.map((artboard) => ({ ...artboard, layers: mapLeafBounds(next, artboard.layers, id, bounds) })),
|
||||
}), document);
|
||||
}
|
||||
|
||||
function applyGroupBounds(document: ImageDocument, groupId: LayerId, bounds: Rect): ImageDocument {
|
||||
const initial = resolveTransformTargetBounds(document, { type: "layer", id: groupId });
|
||||
if (!initial || initial.w === 0 || initial.h === 0) return document;
|
||||
const scale = { x: bounds.w / initial.w, y: bounds.h / initial.h };
|
||||
return { ...document, artboards: document.artboards.map((artboard) => ({ ...artboard, layers: mapGroupBounds(document, artboard.layers, groupId, initial, bounds, scale) })) };
|
||||
}
|
||||
|
||||
function mapGroupBounds(document: ImageDocument, layers: Layer[], groupId: LayerId, initial: Rect, bounds: Rect, scale: { x: number; y: number }): Layer[] {
|
||||
return layers.map((layer) => {
|
||||
if (layer.type === "group" && layer.id === groupId) return { ...layer, children: layer.children.map((child) => scaleSubtree(document, child, initial, bounds, scale)) };
|
||||
return layer.type === "group" ? { ...layer, children: mapGroupBounds(document, layer.children, groupId, initial, bounds, scale) } : layer;
|
||||
});
|
||||
}
|
||||
|
||||
function scaleSubtree(document: ImageDocument, layer: Layer, initial: Rect, bounds: Rect, scale: { x: number; y: number }): Layer {
|
||||
if (layer.type === "group") return { ...layer, children: layer.children.map((child) => scaleSubtree(document, child, initial, bounds, scale)) };
|
||||
if (!document.assets.some((asset) => asset.id === layer.assetId)) return layer;
|
||||
return { ...layer, transform: { ...layer.transform, position: { x: bounds.x + (layer.transform.position.x - initial.x) * scale.x, y: bounds.y + (layer.transform.position.y - initial.y) * scale.y }, scale: { x: layer.transform.scale.x * scale.x, y: layer.transform.scale.y * scale.y } } };
|
||||
}
|
||||
|
||||
function mapLeafBounds(document: ImageDocument, layers: Layer[], layerId: LayerId, bounds: Rect): Layer[] {
|
||||
return layers.map((layer) => {
|
||||
if (layer.id === layerId && layer.type !== "group") {
|
||||
const asset = document.assets.find((candidate) => candidate.id === layer.assetId);
|
||||
return asset ? { ...layer, transform: { ...layer.transform, position: { x: bounds.x, y: bounds.y }, scale: { x: bounds.w / asset.intrinsicSize.w, y: bounds.h / asset.intrinsicSize.h } } } : layer;
|
||||
}
|
||||
return layer.type === "group" ? { ...layer, children: mapLeafBounds(document, layer.children, layerId, bounds) } : layer;
|
||||
});
|
||||
}
|
||||
|
||||
function findLayer(document: ImageDocument, layerId: LayerId): Layer | undefined {
|
||||
const visit = (layers: readonly Layer[]): Layer | undefined => {
|
||||
for (const layer of layers) {
|
||||
if (layer.id === layerId) return layer;
|
||||
if (layer.type === "group") { const child = visit(layer.children); if (child) return child; }
|
||||
}
|
||||
};
|
||||
for (const artboard of document.artboards) { const layer = visit(artboard.layers); if (layer) return layer; }
|
||||
}
|
||||
Reference in New Issue
Block a user