Files
image-studio/editor/tools.ts
syntaxbullet f5c610dac5 feat: implement inpainting functionality with mask handling
- Added `createMaskedPixelReplacementSource` function to handle pixel replacement using inpainting.
- Introduced `buildInpaintBundle` to prepare inpainting data including mask generation and validation.
- Created utility functions for mask operations such as `applyMaskedContentModeToRgba`, `expandRectWithinBounds`, and others for mask manipulation.
- Developed tests for inpainting preparation and mask raster utilities to ensure functionality and correctness.
- Implemented mask raster operations including inversion, feathering, blurring, and more.
2026-07-05 09:35:16 +02:00

110 lines
2.9 KiB
TypeScript

export const availableToolIds = ["select", "generate", "brush", "eraser", "chromaKey", "magicWand", "pan"] as const;
export type ToolId = (typeof availableToolIds)[number];
export type InteractionMode =
| { type: "tool"; tool: ToolId }
| { type: "temporary-pan"; previousTool: ToolId };
export type BrushSettings = {
color: string;
size: number;
hardness: number;
};
export type ChromaKeySettings = {
color: string;
tolerance: number;
softness: number;
feather: number;
choke: number;
despeckle: number;
spill: number;
};
export type MagicWandMode = "replace" | "add" | "subtract";
export type GenerateMode = "text-to-image" | "image-to-image" | "inpaint" | "outpaint";
export type GenerateModel = string;
export type InpaintMaskedContent = "neutral" | "original" | "originalColor" | "edges";
export type GenerateSettings = {
mode: GenerateMode;
model: GenerateModel;
prompt: string;
negativePrompt: string;
strength: number;
steps: number;
cfg: number;
seed: number;
sampler: string;
scheduler: string;
width: number;
height: number;
outpaint: {
left: number;
top: number;
right: number;
bottom: number;
feathering: number;
};
inpaint: {
maskedAreaOnly: boolean;
cropPadding: number;
maskPolarity: "hidden" | "revealed";
maskedContent: InpaintMaskedContent;
growMaskBy: number;
maskExpand: number;
maskFeather: number;
maskBlur: number;
maskDespeckle: number;
};
};
export type MagicWandSettings = {
tolerance: number;
feather: number;
choke: number;
despeckle: number;
contiguous: boolean;
mode: MagicWandMode;
};
export type ToolState = {
activeTool: ToolId;
interactionMode: InteractionMode;
brush: BrushSettings;
chromaKey: ChromaKeySettings;
magicWand: MagicWandSettings;
generate: GenerateSettings;
};
export const initialToolState: ToolState = {
activeTool: "select",
interactionMode: { type: "tool", tool: "select" },
brush: { color: "#111827", size: 8, hardness: 100 },
chromaKey: { color: "#00ff00", tolerance: 32, softness: 24, feather: 0, choke: 0, despeckle: 0, spill: 50 },
magicWand: { tolerance: 32, feather: 0, choke: 0, despeckle: 0, contiguous: true, mode: "replace" },
generate: {
mode: "text-to-image",
model: "auto",
prompt: "",
negativePrompt: "",
strength: 75,
steps: 30,
cfg: 7,
seed: -1,
sampler: "euler",
scheduler: "normal",
width: 1024,
height: 1024,
outpaint: { left: 128, top: 128, right: 128, bottom: 128, feathering: 32 },
inpaint: { maskedAreaOnly: true, cropPadding: 96, maskPolarity: "hidden", maskedContent: "neutral", growMaskBy: 6, maskExpand: 0, maskFeather: 0, maskBlur: 0, maskDespeckle: 0 },
},
};
export function isPanInteractionMode(interactionMode: InteractionMode): boolean {
return interactionMode.type === "temporary-pan" || (interactionMode.type === "tool" && interactionMode.tool === "pan");
}