53 lines
3.6 KiB
TypeScript
53 lines
3.6 KiB
TypeScript
import { commandIds } from "@commands/ids";
|
|
import type { ImageDocument } from "@core/document";
|
|
import type { Layer } from "@core/layer";
|
|
import { getLayerMask } from "@core/layer-mask-utils";
|
|
import { resolveTransformTargetBounds } from "@editor/transform-targets";
|
|
import type { SelectionState } from "@editor/state";
|
|
import type { AppStore } from "@editor/store";
|
|
import type { ChromaKeySettings } from "@editor/tools";
|
|
import { createChromaKeyMask, createChromaKeyPreview } from "@platform/browser/chromaKey";
|
|
|
|
export function previewChromaKey(source: string, width: number, height: number, settings: ChromaKeySettings) { return createChromaKeyPreview(source, width, height, settings); }
|
|
|
|
export function resolveChromaKeyTarget(document: ImageDocument, selection: SelectionState) {
|
|
const layerId = selection.layerIds[0];
|
|
if (selection.layerIds.length !== 1 || !layerId) return undefined;
|
|
const layer = findLayer(document.artboards.find((artboard) => artboard.id === selection.artboardId)?.layers ?? [], layerId);
|
|
if (!layer || layer.type === "group" || layer.type === "adjustment") return undefined;
|
|
const asset = document.assets.find((candidate) => candidate.id === layer.assetId);
|
|
const bounds = resolveTransformTargetBounds(document, { type: "layer", id: layer.id });
|
|
const layerMask = getLayerMask(layer);
|
|
const maskLayer = layerMask?.enabled ? findLayer(document.artboards.flatMap((artboard) => artboard.layers), layerMask.maskLayerId) : undefined;
|
|
const maskAsset = maskLayer && maskLayer.type !== "group" && maskLayer.type !== "adjustment" ? document.assets.find((candidate) => candidate.id === maskLayer.assetId) : undefined;
|
|
return asset && bounds ? { layer, asset, bounds, maskLayer, maskAsset } : undefined;
|
|
}
|
|
|
|
export async function applyChromaKeyMask(target: NonNullable<ReturnType<typeof resolveChromaKeyTarget>>, settings: ChromaKeySettings, dispatch: AppStore["dispatch"]) {
|
|
const source = await createChromaKeyMask(target.asset.source, target.asset.intrinsicSize.w, target.asset.intrinsicSize.h, settings);
|
|
dispatch(commandIds.toolSetBrushStrokePreview, undefined);
|
|
if (target.maskAsset && target.maskLayer && target.maskLayer.type !== "group" && target.maskLayer.type !== "adjustment") {
|
|
dispatch(commandIds.documentApplyLayerMaskOperation, { maskLayerId: target.maskLayer.id, source, mimeType: "image/png", operation: { type: "chromaKey" } });
|
|
dispatch(commandIds.workspaceSetPanel, { panel: "none" });
|
|
return;
|
|
}
|
|
const assetId = crypto.randomUUID();
|
|
const maskLayerId = crypto.randomUUID();
|
|
const width = Math.max(1, Math.round(target.asset.intrinsicSize.w));
|
|
const height = Math.max(1, Math.round(target.asset.intrinsicSize.h));
|
|
dispatch(commandIds.documentAddLayerMask, {
|
|
layerId: target.layer.id,
|
|
asset: { id: assetId, name: `${target.layer.name} Chroma Mask`, mimeType: "image/png", source, intrinsicSize: { w: width, h: height } },
|
|
maskLayer: { id: maskLayerId, type: "raster", name: `${target.layer.name} Chroma Mask`, visible: true, locked: false, opacity: 1, assetId, transform: { position: { x: target.bounds.x, y: target.bounds.y }, scale: { x: target.bounds.w / width, y: target.bounds.h / height }, rotation: target.layer.transform.rotation } },
|
|
});
|
|
dispatch(commandIds.toolExitMaskEdit, undefined);
|
|
dispatch(commandIds.workspaceSetPanel, { panel: "none" });
|
|
}
|
|
|
|
function findLayer(layers: readonly Layer[], layerId: string): Layer | undefined {
|
|
for (const layer of layers) {
|
|
if (layer.id === layerId) return layer;
|
|
if (layer.type === "group") { const found = findLayer(layer.children, layerId); if (found) return found; }
|
|
}
|
|
}
|