@pixerate/editor 0.206.0 → 0.208.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/animation-editor/index.cjs +60 -59
  2. package/dist/animation-editor/index.js +6 -5
  3. package/dist/{brushstrokeRender-7LXCU7PD.js → brushstrokeRender-C3UU6GVC.js} +5 -4
  4. package/dist/{brushstrokeRender-VO4ZTWVA.cjs → brushstrokeRender-EAJNE6WP.cjs} +12 -11
  5. package/dist/canvas/index.cjs +8 -8
  6. package/dist/canvas/index.js +1 -1
  7. package/dist/{chunk-2N2QPO3H.js → chunk-2PBZBRP5.js} +9 -7
  8. package/dist/{chunk-7NW46N7I.cjs → chunk-3EHPLDFQ.cjs} +54 -52
  9. package/dist/{chunk-H367YTXI.js → chunk-42TWUPNJ.js} +13 -387
  10. package/dist/chunk-474IQG74.cjs +384 -0
  11. package/dist/{chunk-MLC7HUHO.js → chunk-BGOCAUXH.js} +1 -1
  12. package/dist/chunk-DWYQPL2A.js +2010 -0
  13. package/dist/{chunk-YXKLVD56.js → chunk-F7YA3MMC.js} +2 -2
  14. package/dist/{chunk-ZZGPYNS2.js → chunk-G4E6RUPC.js} +1 -1
  15. package/dist/chunk-HVVR5PZW.js +384 -0
  16. package/dist/{chunk-FR2Q2LVF.cjs → chunk-I7G3RSUJ.cjs} +35 -35
  17. package/dist/chunk-K6PXS6DO.cjs +102 -0
  18. package/dist/{chunk-ZIDUPSP4.js → chunk-KFIOEOCQ.js} +24 -761
  19. package/dist/{chunk-V7GWZIZK.cjs → chunk-KWNMBMKG.cjs} +23 -21
  20. package/dist/chunk-L3G23N5Y.js +763 -0
  21. package/dist/{chunk-GHCXLQ47.js → chunk-NDMXB4PR.js} +2 -2
  22. package/dist/{chunk-CWM3CUUX.cjs → chunk-OLNIPTB3.cjs} +39 -413
  23. package/dist/{chunk-EBDCRTZI.cjs → chunk-PQ3H2AAN.cjs} +92 -90
  24. package/dist/{chunk-BRKVNXDZ.cjs → chunk-QAUIZPYI.cjs} +7 -7
  25. package/dist/{chunk-UYXL6ZWQ.cjs → chunk-QE7D7TZR.cjs} +494 -1231
  26. package/dist/chunk-QYLWG22N.cjs +763 -0
  27. package/dist/{chunk-YQ5C5BVK.cjs → chunk-ROVK6AXX.cjs} +60 -60
  28. package/dist/{chunk-HGTDMKNE.cjs → chunk-UOGKSVRQ.cjs} +126 -221
  29. package/dist/{chunk-EL5PAHNP.js → chunk-USQCKRZG.js} +6 -4
  30. package/dist/{chunk-36OKQDCF.js → chunk-WJ2RBZMM.js} +5 -3
  31. package/dist/chunk-X4LUGTQX.cjs +2010 -0
  32. package/dist/{chunk-NQMP3CWF.js → chunk-YBJXCQTR.js} +15 -110
  33. package/dist/chunk-ZIF4UJJ6.js +102 -0
  34. package/dist/{chunk-WTW7QRTS.cjs → chunk-ZMHPQ6HP.cjs} +1 -1
  35. package/dist/image-editor/controller.d.cts +28 -3
  36. package/dist/image-editor/controller.d.ts +28 -3
  37. package/dist/image-editor/index.cjs +2150 -3380
  38. package/dist/image-editor/index.js +675 -1905
  39. package/dist/image-editor/selection/index.d.cts +2 -0
  40. package/dist/image-editor/selection/index.d.ts +2 -0
  41. package/dist/image-editor/selection/refine-edits.d.cts +13 -4
  42. package/dist/image-editor/selection/refine-edits.d.ts +13 -4
  43. package/dist/image-editor/selection/segment/focus.d.cts +2 -0
  44. package/dist/image-editor/selection/segment/focus.d.ts +2 -0
  45. package/dist/image-editor/selection/segment/grabcut.d.cts +4 -2
  46. package/dist/image-editor/selection/segment/grabcut.d.ts +4 -2
  47. package/dist/image-editor/selection/segment/sky.d.cts +2 -0
  48. package/dist/image-editor/selection/segment/sky.d.ts +2 -0
  49. package/dist/image-editor/selection/segment/subject.d.cts +2 -1
  50. package/dist/image-editor/selection/segment/subject.d.ts +2 -1
  51. package/dist/image-editor/selection/segment/work.d.cts +5 -0
  52. package/dist/image-editor/selection/segment/work.d.ts +5 -0
  53. package/dist/image-editor/selection/select-and-mask.d.cts +136 -0
  54. package/dist/image-editor/selection/select-and-mask.d.ts +136 -0
  55. package/dist/image-editor/selection/worker.d.cts +126 -0
  56. package/dist/image-editor/selection/worker.d.ts +126 -0
  57. package/dist/image-editor/selection-worker.cjs +14 -0
  58. package/dist/image-editor/selection-worker.d.cts +12 -0
  59. package/dist/image-editor/selection-worker.d.ts +12 -0
  60. package/dist/image-editor/selection-worker.js +14 -0
  61. package/dist/image-editor/types.d.cts +8 -0
  62. package/dist/image-editor/types.d.ts +8 -0
  63. package/dist/paint/index.cjs +6 -5
  64. package/dist/paint/index.js +5 -4
  65. package/dist/paint-editor/index.cjs +394 -390
  66. package/dist/paint-editor/index.js +18 -14
  67. package/dist/raster/index.cjs +22 -18
  68. package/dist/raster/index.js +29 -25
  69. package/dist/vector/index.cjs +986 -985
  70. package/dist/vector/index.js +6 -5
  71. package/package.json +11 -1
  72. package/skills/pixerate-image-editor/SKILL.md +1 -1
  73. package/skills/pixerate-image-selection-masking/SKILL.md +4 -2
@@ -15,3 +15,5 @@ export * from './path.cjs';
15
15
  export * from './magnetic.cjs';
16
16
  export * from './segment/index.cjs';
17
17
  export * from './refine-edits.cjs';
18
+ export * from './select-and-mask.cjs';
19
+ export * from './worker.cjs';
@@ -15,3 +15,5 @@ export * from './path.js';
15
15
  export * from './magnetic.js';
16
16
  export * from './segment/index.js';
17
17
  export * from './refine-edits.js';
18
+ export * from './select-and-mask.js';
19
+ export * from './worker.js';
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * The Select and Mask workspace's strokes as plain data, so an agent can send what a person
3
3
  * paints: Quick Selection strokes (grow to the region's edges), Brush strokes (paint the
4
- * selection in or out directly) and Refine Edge Brush strokes (mark where the edge should be
5
- * re-estimated from the image, e.g. over hair).
4
+ * selection in or out directly), Refine Edge Brush strokes (mark where the edge should be
5
+ * re-estimated from the image, e.g. over hair), Lasso outlines and Object Selection boxes.
6
6
  */
7
- import type { ImagePoint } from '../types.cjs';
7
+ import type { CropBox, ImagePoint } from '../types.cjs';
8
8
  import { type PixelBuffer, type SelectionMask } from './mask.cjs';
9
9
  /** One stroke in the workspace, in natural image pixels. */
10
10
  export type RefineEdit = {
@@ -22,8 +22,17 @@ export type RefineEdit = {
22
22
  kind: 'refine-brush';
23
23
  points: ImagePoint[];
24
24
  size?: number;
25
+ } | {
26
+ kind: 'lasso';
27
+ points: ImagePoint[];
28
+ mode?: 'add' | 'subtract';
29
+ } | {
30
+ kind: 'object';
31
+ rect?: CropBox;
32
+ point?: ImagePoint;
33
+ mode?: 'add' | 'subtract';
25
34
  };
26
- export declare const REFINE_EDIT_KINDS: readonly ["quick-select", "brush", "refine-brush"];
35
+ export declare const REFINE_EDIT_KINDS: readonly ["quick-select", "brush", "refine-brush", "lasso", "object"];
27
36
  /**
28
37
  * Coverage of a round brush of diameter `size` dragged along `points` (one point is a dab), over
29
38
  * a `width × height` image. `hardness` 0..1 (default 1): the solid share of the radius; the rest
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * The Select and Mask workspace's strokes as plain data, so an agent can send what a person
3
3
  * paints: Quick Selection strokes (grow to the region's edges), Brush strokes (paint the
4
- * selection in or out directly) and Refine Edge Brush strokes (mark where the edge should be
5
- * re-estimated from the image, e.g. over hair).
4
+ * selection in or out directly), Refine Edge Brush strokes (mark where the edge should be
5
+ * re-estimated from the image, e.g. over hair), Lasso outlines and Object Selection boxes.
6
6
  */
7
- import type { ImagePoint } from '../types.js';
7
+ import type { CropBox, ImagePoint } from '../types.js';
8
8
  import { type PixelBuffer, type SelectionMask } from './mask.js';
9
9
  /** One stroke in the workspace, in natural image pixels. */
10
10
  export type RefineEdit = {
@@ -22,8 +22,17 @@ export type RefineEdit = {
22
22
  kind: 'refine-brush';
23
23
  points: ImagePoint[];
24
24
  size?: number;
25
+ } | {
26
+ kind: 'lasso';
27
+ points: ImagePoint[];
28
+ mode?: 'add' | 'subtract';
29
+ } | {
30
+ kind: 'object';
31
+ rect?: CropBox;
32
+ point?: ImagePoint;
33
+ mode?: 'add' | 'subtract';
25
34
  };
26
- export declare const REFINE_EDIT_KINDS: readonly ["quick-select", "brush", "refine-brush"];
35
+ export declare const REFINE_EDIT_KINDS: readonly ["quick-select", "brush", "refine-brush", "lasso", "object"];
27
36
  /**
28
37
  * Coverage of a round brush of diameter `size` dragged along `points` (one point is a dab), over
29
38
  * a `width × height` image. `hardness` 0..1 (default 1): the solid share of the radius; the rest
@@ -5,6 +5,7 @@
5
5
  * and fitted to the image's edges with a guided filter.
6
6
  */
7
7
  import type { PixelBuffer, SelectionMask } from '../mask.cjs';
8
+ import { type SelectionProgress } from './work.cjs';
8
9
  export interface FocusAreaOptions {
9
10
  /** In-Focus Range 0..100 (default 50): higher takes in less sharp areas too. */
10
11
  range?: number;
@@ -12,6 +13,7 @@ export interface FocusAreaOptions {
12
13
  noise?: number;
13
14
  /** Soften the edge over this many natural pixels (default 4; 0 for a hard edge). */
14
15
  softness?: number;
16
+ onProgress?: SelectionProgress;
15
17
  }
16
18
  export interface FocusAreaResult {
17
19
  selection: SelectionMask;
@@ -5,6 +5,7 @@
5
5
  * and fitted to the image's edges with a guided filter.
6
6
  */
7
7
  import type { PixelBuffer, SelectionMask } from '../mask.js';
8
+ import { type SelectionProgress } from './work.js';
8
9
  export interface FocusAreaOptions {
9
10
  /** In-Focus Range 0..100 (default 50): higher takes in less sharp areas too. */
10
11
  range?: number;
@@ -12,6 +13,7 @@ export interface FocusAreaOptions {
12
13
  noise?: number;
13
14
  /** Soften the edge over this many natural pixels (default 4; 0 for a hard edge). */
14
15
  softness?: number;
16
+ onProgress?: SelectionProgress;
15
17
  }
16
18
  export interface FocusAreaResult {
17
19
  selection: SelectionMask;
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { CropBox, ImagePoint } from '../../types.cjs';
9
9
  import { type PixelBuffer, type SelectionMask } from '../mask.cjs';
10
- import { type Rect, type WorkImage } from './work.cjs';
10
+ import { type Rect, type SelectionProgress, type WorkImage } from './work.cjs';
11
11
  /** A mixture of {@link K} full-covariance Gaussians over RGB. */
12
12
  export declare class ColorGmm {
13
13
  private readonly logWeight;
@@ -36,7 +36,8 @@ export interface GrabCutSetup {
36
36
  hardFg: Uint8Array | null;
37
37
  }
38
38
  /** GrabCut over the setup's window; returns 1 for the object per window pixel. */
39
- export declare function grabCutLabels(work: WorkImage, setup: GrabCutSetup, iterations: number): Uint8Array;
39
+ /** GrabCut over the setup's window; `onRound` is called after each round with the share done. */
40
+ export declare function grabCutLabels(work: WorkImage, setup: GrabCutSetup, iterations: number, onRound?: (fraction: number) => void): Uint8Array;
40
41
  /**
41
42
  * Keeps the object's main parts: the pieces (4-connected) holding `seed` (window index), or
42
43
  * without one, every piece at least a fifth the size of the largest.
@@ -47,6 +48,7 @@ export interface ObjectSelectionOptions {
47
48
  enhanceEdge?: boolean;
48
49
  /** Most rounds of fitting and cutting (default 5; it stops early once the labels settle). */
49
50
  iterations?: number;
51
+ onProgress?: SelectionProgress;
50
52
  }
51
53
  /** What to select: a box around the object, or a point on it (natural pixels). */
52
54
  export type ObjectTarget = {
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { CropBox, ImagePoint } from '../../types.js';
9
9
  import { type PixelBuffer, type SelectionMask } from '../mask.js';
10
- import { type Rect, type WorkImage } from './work.js';
10
+ import { type Rect, type SelectionProgress, type WorkImage } from './work.js';
11
11
  /** A mixture of {@link K} full-covariance Gaussians over RGB. */
12
12
  export declare class ColorGmm {
13
13
  private readonly logWeight;
@@ -36,7 +36,8 @@ export interface GrabCutSetup {
36
36
  hardFg: Uint8Array | null;
37
37
  }
38
38
  /** GrabCut over the setup's window; returns 1 for the object per window pixel. */
39
- export declare function grabCutLabels(work: WorkImage, setup: GrabCutSetup, iterations: number): Uint8Array;
39
+ /** GrabCut over the setup's window; `onRound` is called after each round with the share done. */
40
+ export declare function grabCutLabels(work: WorkImage, setup: GrabCutSetup, iterations: number, onRound?: (fraction: number) => void): Uint8Array;
40
41
  /**
41
42
  * Keeps the object's main parts: the pieces (4-connected) holding `seed` (window index), or
42
43
  * without one, every piece at least a fifth the size of the largest.
@@ -47,6 +48,7 @@ export interface ObjectSelectionOptions {
47
48
  enhanceEdge?: boolean;
48
49
  /** Most rounds of fitting and cutting (default 5; it stops early once the labels settle). */
49
50
  iterations?: number;
51
+ onProgress?: SelectionProgress;
50
52
  }
51
53
  /** What to select: a box around the object, or a point on it (natural pixels). */
52
54
  export type ObjectTarget = {
@@ -6,11 +6,13 @@
6
6
  * with the colour guided filter.
7
7
  */
8
8
  import { type PixelBuffer, type SelectionMask } from '../mask.cjs';
9
+ import { type SelectionProgress } from './work.cjs';
9
10
  export interface SkyOptions {
10
11
  /** 0..100 (default 50): higher takes in less sky-like pixels (haze, a sunset glow). */
11
12
  threshold?: number;
12
13
  /** Soften the edge over this many natural pixels (default 4; 0 for a hard edge). */
13
14
  softness?: number;
15
+ onProgress?: SelectionProgress;
14
16
  }
15
17
  export interface FoundSky {
16
18
  selection: SelectionMask;
@@ -6,11 +6,13 @@
6
6
  * with the colour guided filter.
7
7
  */
8
8
  import { type PixelBuffer, type SelectionMask } from '../mask.js';
9
+ import { type SelectionProgress } from './work.js';
9
10
  export interface SkyOptions {
10
11
  /** 0..100 (default 50): higher takes in less sky-like pixels (haze, a sunset glow). */
11
12
  threshold?: number;
12
13
  /** Soften the edge over this many natural pixels (default 4; 0 for a hard edge). */
13
14
  softness?: number;
15
+ onProgress?: SelectionProgress;
14
16
  }
15
17
  export interface FoundSky {
16
18
  selection: SelectionMask;
@@ -12,7 +12,7 @@
12
12
  * It cannot tell which object a description names: it selects what stands out.
13
13
  */
14
14
  import type { PixelBuffer, SelectionMask } from '../mask.cjs';
15
- import { type WorkImage } from './work.cjs';
15
+ import { type SelectionProgress, type WorkImage } from './work.cjs';
16
16
  export interface Superpixels {
17
17
  /** Superpixel of each work pixel. */
18
18
  label: Int32Array;
@@ -41,4 +41,5 @@ export interface FoundSubject {
41
41
  */
42
42
  export declare function findSubject(pixels: PixelBuffer, options?: {
43
43
  enhanceEdge?: boolean;
44
+ onProgress?: SelectionProgress;
44
45
  }): FoundSubject;
@@ -12,7 +12,7 @@
12
12
  * It cannot tell which object a description names: it selects what stands out.
13
13
  */
14
14
  import type { PixelBuffer, SelectionMask } from '../mask.js';
15
- import { type WorkImage } from './work.js';
15
+ import { type SelectionProgress, type WorkImage } from './work.js';
16
16
  export interface Superpixels {
17
17
  /** Superpixel of each work pixel. */
18
18
  label: Int32Array;
@@ -41,4 +41,5 @@ export interface FoundSubject {
41
41
  */
42
42
  export declare function findSubject(pixels: PixelBuffer, options?: {
43
43
  enhanceEdge?: boolean;
44
+ onProgress?: SelectionProgress;
44
45
  }): FoundSubject;
@@ -3,6 +3,11 @@
3
3
  * Area) work on, and scaling their result back up to the image.
4
4
  */
5
5
  import { type PixelBuffer, type SelectionMask } from '../mask.cjs';
6
+ /**
7
+ * Progress of a long selection: `fraction` 0..1 done and what it is doing. The segmentations call
8
+ * it between their stages; in a worker it is posted back to the page.
9
+ */
10
+ export type SelectionProgress = (fraction: number, stage: string) => void;
6
11
  /** The reduced image the segmentations work on (sRGB, 0..255 per channel). */
7
12
  export interface WorkImage {
8
13
  /** Natural size of the image it was made from. */
@@ -3,6 +3,11 @@
3
3
  * Area) work on, and scaling their result back up to the image.
4
4
  */
5
5
  import { type PixelBuffer, type SelectionMask } from '../mask.js';
6
+ /**
7
+ * Progress of a long selection: `fraction` 0..1 done and what it is doing. The segmentations call
8
+ * it between their stages; in a worker it is posted back to the page.
9
+ */
10
+ export type SelectionProgress = (fraction: number, stage: string) => void;
6
11
  /** The reduced image the segmentations work on (sRGB, 0..255 per channel). */
7
12
  export interface WorkImage {
8
13
  /** Natural size of the image it was made from. */
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The Select and Mask workspace without a UI: its settings, strokes, preview and view modes, shared
3
+ * by the React and Svelte workspaces. Everything it holds is plain data (the strokes are
4
+ * `RefineEdit`s), and OK runs the same `refineSelectionTo` call an agent makes with `edits`, so
5
+ * the workspace and an agent produce the same result in one undo step.
6
+ *
7
+ * The preview is computed on a copy reduced to {@link PREVIEW_SIZE} px (or at full size with High
8
+ * Quality Preview), in the controller's selection worker when it has one, and drawn as RGBA in
9
+ * the chosen view mode.
10
+ */
11
+ import type { ImageEditorController, RefineOutput, RefineOutputResult } from '../controller.cjs';
12
+ import type { ImagePoint } from '../types.cjs';
13
+ import { type RefineEdgeParams } from './refine.cjs';
14
+ import { type RefineEdit } from './refine-edits.cjs';
15
+ export type SelectAndMaskView = 'onion-skin' | 'marching-ants' | 'overlay' | 'on-black' | 'on-white' | 'black-white' | 'on-layers';
16
+ export type SelectAndMaskTool = 'quick-select' | 'refine-brush' | 'brush' | 'object' | 'lasso' | 'hand' | 'zoom';
17
+ /** The view modes with Photoshop's keys, in menu order. */
18
+ export declare const SELECT_AND_MASK_VIEWS: readonly {
19
+ id: SelectAndMaskView;
20
+ label: string;
21
+ key: string;
22
+ opacity: number;
23
+ }[];
24
+ /** The workspace tools with Photoshop's keys. */
25
+ export declare const SELECT_AND_MASK_TOOLS: readonly {
26
+ id: SelectAndMaskTool;
27
+ label: string;
28
+ key: string;
29
+ }[];
30
+ export interface SelectAndMaskSettings {
31
+ params: Required<RefineEdgeParams>;
32
+ output: RefineOutput;
33
+ /** Decontaminate Colors amount 0..100 (new-layer outputs). */
34
+ decontaminate: number;
35
+ refineMode: 'color' | 'object';
36
+ view: SelectAndMaskView;
37
+ /** How strongly the view shows what is not selected, 0..1. */
38
+ opacity: number;
39
+ /** Show only the area the refinement changes. */
40
+ showEdge: boolean;
41
+ /** Show the selection as it was, before the workspace. */
42
+ showOriginal: boolean;
43
+ /** Update the preview while painting (otherwise on release). */
44
+ realTime: boolean;
45
+ /** Preview at full size instead of a reduced copy. */
46
+ highQuality: boolean;
47
+ /** Keep these settings for the next time the workspace opens. */
48
+ remember: boolean;
49
+ tool: SelectAndMaskTool;
50
+ /** Brush diameter in natural pixels. */
51
+ brushSize: number;
52
+ brushMode: 'add' | 'subtract';
53
+ }
54
+ export declare const DEFAULT_SELECT_AND_MASK_SETTINGS: SelectAndMaskSettings;
55
+ /** Long side of the reduced preview. */
56
+ export declare const PREVIEW_SIZE = 1024;
57
+ export declare class SelectAndMaskSession {
58
+ readonly controller: ImageEditorController;
59
+ private settingsValue;
60
+ private readonly editsList;
61
+ /** The edit being painted, shown in the preview but not yet in `edits`. */
62
+ private live;
63
+ private dragStart;
64
+ private pixels;
65
+ private previewPixels;
66
+ private base;
67
+ private previewMask;
68
+ private baseMask;
69
+ private readonly listeners;
70
+ /** Why the preview could not be made (no pixels), for the UI. */
71
+ error: string | null;
72
+ /** A note for the UI, such as object aware refinement applying only on OK. */
73
+ note: string | null;
74
+ /** Bumped each time the preview changes, so a UI can redraw. */
75
+ revision: number;
76
+ /** True while the worker computes a preview. */
77
+ computing: boolean;
78
+ private dirty;
79
+ constructor(controller: ImageEditorController);
80
+ get settings(): SelectAndMaskSettings;
81
+ get edits(): readonly RefineEdit[];
82
+ /** Reads the image and makes the first preview. Resolves to false when the pixels are unavailable. */
83
+ open(): Promise<boolean>;
84
+ subscribe(listener: () => void): () => void;
85
+ private emit;
86
+ /** Preview size and the scale from natural pixels to it. */
87
+ get previewSize(): {
88
+ width: number;
89
+ height: number;
90
+ scale: number;
91
+ };
92
+ /** Changes settings; the preview follows. Choosing a view also sets its usual opacity. */
93
+ update(changes: Partial<SelectAndMaskSettings>): void;
94
+ private rescale;
95
+ /**
96
+ * Recomputes the preview mask from the base selection, the strokes and the settings: at once on
97
+ * the page, or in the worker, where one job runs at a time and the newest state follows it.
98
+ */
99
+ recompute(): void;
100
+ private recomputeInWorker;
101
+ /** Resolves once no preview is being computed (immediately without a worker). */
102
+ idle(): Promise<void>;
103
+ /** Coverage 0..1 of the preview at (x, y) in preview pixels (for tests and hover readouts). */
104
+ coverageAt(x: number, y: number): number;
105
+ /** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
106
+ render(): Uint8ClampedArray;
107
+ /**
108
+ * Pointer down at `point` (natural pixels) with the current tool: starts a stroke (Quick
109
+ * Selection, brushes, lasso) or a box (Object Selection). Alt (or the subtract mode) removes.
110
+ * Hand and Zoom are the UI's own; they return false here.
111
+ */
112
+ begin(point: ImagePoint, modifiers?: {
113
+ altKey?: boolean;
114
+ }): boolean;
115
+ /** Pointer move while a stroke is down. */
116
+ move(point: ImagePoint): void;
117
+ /** Pointer up: the stroke becomes an edit (one step of the workspace's own undo). */
118
+ end(): void;
119
+ /** Removes the last stroke (Ctrl/⌘+Z in the workspace). Returns false when there is none. */
120
+ undoEdit(): boolean;
121
+ /** Clears the strokes and goes back to the default settings (Reset). */
122
+ reset(): void;
123
+ /**
124
+ * Photoshop's keys in the workspace: a view letter, F (next view), X (all views off and on:
125
+ * Show Original), J (Show Edge), P (Show Original), a tool letter, [ and ] (brush size).
126
+ * Returns true when the key was used.
127
+ */
128
+ handleKey(key: string): boolean;
129
+ /**
130
+ * OK: applies the strokes and settings to the image as one undo step (the same call an agent
131
+ * makes) and remembers the settings when asked to.
132
+ */
133
+ commit(): Promise<RefineOutputResult>;
134
+ }
135
+ /** Forgets the remembered workspace settings. */
136
+ export declare function forgetSelectAndMaskSettings(): void;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The Select and Mask workspace without a UI: its settings, strokes, preview and view modes, shared
3
+ * by the React and Svelte workspaces. Everything it holds is plain data (the strokes are
4
+ * `RefineEdit`s), and OK runs the same `refineSelectionTo` call an agent makes with `edits`, so
5
+ * the workspace and an agent produce the same result in one undo step.
6
+ *
7
+ * The preview is computed on a copy reduced to {@link PREVIEW_SIZE} px (or at full size with High
8
+ * Quality Preview), in the controller's selection worker when it has one, and drawn as RGBA in
9
+ * the chosen view mode.
10
+ */
11
+ import type { ImageEditorController, RefineOutput, RefineOutputResult } from '../controller.js';
12
+ import type { ImagePoint } from '../types.js';
13
+ import { type RefineEdgeParams } from './refine.js';
14
+ import { type RefineEdit } from './refine-edits.js';
15
+ export type SelectAndMaskView = 'onion-skin' | 'marching-ants' | 'overlay' | 'on-black' | 'on-white' | 'black-white' | 'on-layers';
16
+ export type SelectAndMaskTool = 'quick-select' | 'refine-brush' | 'brush' | 'object' | 'lasso' | 'hand' | 'zoom';
17
+ /** The view modes with Photoshop's keys, in menu order. */
18
+ export declare const SELECT_AND_MASK_VIEWS: readonly {
19
+ id: SelectAndMaskView;
20
+ label: string;
21
+ key: string;
22
+ opacity: number;
23
+ }[];
24
+ /** The workspace tools with Photoshop's keys. */
25
+ export declare const SELECT_AND_MASK_TOOLS: readonly {
26
+ id: SelectAndMaskTool;
27
+ label: string;
28
+ key: string;
29
+ }[];
30
+ export interface SelectAndMaskSettings {
31
+ params: Required<RefineEdgeParams>;
32
+ output: RefineOutput;
33
+ /** Decontaminate Colors amount 0..100 (new-layer outputs). */
34
+ decontaminate: number;
35
+ refineMode: 'color' | 'object';
36
+ view: SelectAndMaskView;
37
+ /** How strongly the view shows what is not selected, 0..1. */
38
+ opacity: number;
39
+ /** Show only the area the refinement changes. */
40
+ showEdge: boolean;
41
+ /** Show the selection as it was, before the workspace. */
42
+ showOriginal: boolean;
43
+ /** Update the preview while painting (otherwise on release). */
44
+ realTime: boolean;
45
+ /** Preview at full size instead of a reduced copy. */
46
+ highQuality: boolean;
47
+ /** Keep these settings for the next time the workspace opens. */
48
+ remember: boolean;
49
+ tool: SelectAndMaskTool;
50
+ /** Brush diameter in natural pixels. */
51
+ brushSize: number;
52
+ brushMode: 'add' | 'subtract';
53
+ }
54
+ export declare const DEFAULT_SELECT_AND_MASK_SETTINGS: SelectAndMaskSettings;
55
+ /** Long side of the reduced preview. */
56
+ export declare const PREVIEW_SIZE = 1024;
57
+ export declare class SelectAndMaskSession {
58
+ readonly controller: ImageEditorController;
59
+ private settingsValue;
60
+ private readonly editsList;
61
+ /** The edit being painted, shown in the preview but not yet in `edits`. */
62
+ private live;
63
+ private dragStart;
64
+ private pixels;
65
+ private previewPixels;
66
+ private base;
67
+ private previewMask;
68
+ private baseMask;
69
+ private readonly listeners;
70
+ /** Why the preview could not be made (no pixels), for the UI. */
71
+ error: string | null;
72
+ /** A note for the UI, such as object aware refinement applying only on OK. */
73
+ note: string | null;
74
+ /** Bumped each time the preview changes, so a UI can redraw. */
75
+ revision: number;
76
+ /** True while the worker computes a preview. */
77
+ computing: boolean;
78
+ private dirty;
79
+ constructor(controller: ImageEditorController);
80
+ get settings(): SelectAndMaskSettings;
81
+ get edits(): readonly RefineEdit[];
82
+ /** Reads the image and makes the first preview. Resolves to false when the pixels are unavailable. */
83
+ open(): Promise<boolean>;
84
+ subscribe(listener: () => void): () => void;
85
+ private emit;
86
+ /** Preview size and the scale from natural pixels to it. */
87
+ get previewSize(): {
88
+ width: number;
89
+ height: number;
90
+ scale: number;
91
+ };
92
+ /** Changes settings; the preview follows. Choosing a view also sets its usual opacity. */
93
+ update(changes: Partial<SelectAndMaskSettings>): void;
94
+ private rescale;
95
+ /**
96
+ * Recomputes the preview mask from the base selection, the strokes and the settings: at once on
97
+ * the page, or in the worker, where one job runs at a time and the newest state follows it.
98
+ */
99
+ recompute(): void;
100
+ private recomputeInWorker;
101
+ /** Resolves once no preview is being computed (immediately without a worker). */
102
+ idle(): Promise<void>;
103
+ /** Coverage 0..1 of the preview at (x, y) in preview pixels (for tests and hover readouts). */
104
+ coverageAt(x: number, y: number): number;
105
+ /** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
106
+ render(): Uint8ClampedArray;
107
+ /**
108
+ * Pointer down at `point` (natural pixels) with the current tool: starts a stroke (Quick
109
+ * Selection, brushes, lasso) or a box (Object Selection). Alt (or the subtract mode) removes.
110
+ * Hand and Zoom are the UI's own; they return false here.
111
+ */
112
+ begin(point: ImagePoint, modifiers?: {
113
+ altKey?: boolean;
114
+ }): boolean;
115
+ /** Pointer move while a stroke is down. */
116
+ move(point: ImagePoint): void;
117
+ /** Pointer up: the stroke becomes an edit (one step of the workspace's own undo). */
118
+ end(): void;
119
+ /** Removes the last stroke (Ctrl/⌘+Z in the workspace). Returns false when there is none. */
120
+ undoEdit(): boolean;
121
+ /** Clears the strokes and goes back to the default settings (Reset). */
122
+ reset(): void;
123
+ /**
124
+ * Photoshop's keys in the workspace: a view letter, F (next view), X (all views off and on:
125
+ * Show Original), J (Show Edge), P (Show Original), a tool letter, [ and ] (brush size).
126
+ * Returns true when the key was used.
127
+ */
128
+ handleKey(key: string): boolean;
129
+ /**
130
+ * OK: applies the strokes and settings to the image as one undo step (the same call an agent
131
+ * makes) and remembers the settings when asked to.
132
+ */
133
+ commit(): Promise<RefineOutputResult>;
134
+ }
135
+ /** Forgets the remembered workspace settings. */
136
+ export declare function forgetSelectAndMaskSettings(): void;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Running the long selections (Select Subject, Object Selection, Focus Area, Select Sky, Quick
3
+ * Selection strokes and the Select and Mask preview) off the page in a Web Worker, with progress
4
+ * and cancelling.
5
+ *
6
+ * - `runSelectionJob` does one job synchronously; the worker and the page's fallback both use it.
7
+ * - `startSelectionWorker` answers jobs inside a worker (the `selection-worker` entry calls it).
8
+ * - `SelectionWorkerClient` sends jobs from the page. The image is sent once per pixel buffer and
9
+ * kept in the worker; masks travel as their bounds and bytes. Cancelling terminates the worker
10
+ * (a running job can't be interrupted otherwise) and the next job starts a fresh one.
11
+ */
12
+ import type { CropBox, ImagePoint } from '../types.cjs';
13
+ import { type PixelBuffer, type SelectionMask } from './mask.cjs';
14
+ import { type RefineEdgeParams } from './refine.cjs';
15
+ import { type RefineEdit } from './refine-edits.cjs';
16
+ import { type FocusAreaOptions } from './segment/focus.cjs';
17
+ import { type ObjectTarget } from './segment/grabcut.cjs';
18
+ import { type SkyOptions } from './segment/sky.cjs';
19
+ import type { SelectionProgress } from './segment/work.cjs';
20
+ /** A selection as plain data: its size, bounds and the bytes inside the bounds. */
21
+ export interface SerializedMask {
22
+ width: number;
23
+ height: number;
24
+ bounds: CropBox | null;
25
+ bytes: Uint8Array;
26
+ }
27
+ export declare function serializeMask(mask: SelectionMask): SerializedMask;
28
+ export declare function deserializeMask(s: SerializedMask): SelectionMask;
29
+ /** One long selection, as data. */
30
+ export type SelectionJob = {
31
+ op: 'subject';
32
+ enhanceEdge?: boolean;
33
+ } | {
34
+ op: 'object';
35
+ target: ObjectTarget;
36
+ enhanceEdge?: boolean;
37
+ } | {
38
+ op: 'focus';
39
+ options?: Omit<FocusAreaOptions, 'onProgress'>;
40
+ } | {
41
+ op: 'sky';
42
+ options?: Omit<SkyOptions, 'onProgress'>;
43
+ } | {
44
+ op: 'quick';
45
+ stroke: ImagePoint[];
46
+ size?: number;
47
+ grow?: boolean;
48
+ enhanceEdge?: boolean;
49
+ selection?: SerializedMask | null;
50
+ } | {
51
+ op: 'refine-preview';
52
+ base: SerializedMask | null;
53
+ edits: RefineEdit[];
54
+ params: RefineEdgeParams;
55
+ };
56
+ /** What a job found: a selection of the whole image, and the job's notes. */
57
+ export interface SelectionJobResult {
58
+ mask: SelectionMask;
59
+ /** Why nothing was selected (subject, sky). */
60
+ reason?: string;
61
+ /** Focus Area: the noise level it measured. */
62
+ noiseLevel?: number;
63
+ }
64
+ /** Runs `job` on `pixels` here and now. */
65
+ export declare function runSelectionJob(job: SelectionJob, pixels: PixelBuffer, onProgress?: SelectionProgress): SelectionJobResult;
66
+ /** Messages from the page to the worker. */
67
+ export type SelectionWorkerRequest = {
68
+ type: 'pixels';
69
+ key: number;
70
+ pixels: PixelBuffer;
71
+ } | {
72
+ type: 'job';
73
+ id: number;
74
+ key: number;
75
+ job: SelectionJob;
76
+ };
77
+ /** Messages from the worker to the page. */
78
+ export type SelectionWorkerResponse = {
79
+ type: 'progress';
80
+ id: number;
81
+ fraction: number;
82
+ stage: string;
83
+ } | {
84
+ type: 'done';
85
+ id: number;
86
+ mask: SerializedMask;
87
+ reason?: string;
88
+ noiseLevel?: number;
89
+ } | {
90
+ type: 'error';
91
+ id: number;
92
+ message: string;
93
+ };
94
+ /**
95
+ * The part of a worker (or its global scope) the protocol uses; a DOM `Worker` is one. The event
96
+ * parameters are loose so a `Worker`'s `MessageEvent` / `ErrorEvent` handlers fit.
97
+ */
98
+ export interface SelectionWorkerLike {
99
+ postMessage(message: unknown, transfer?: Transferable[]): void;
100
+ onmessage: ((event: any) => void) | null;
101
+ onerror?: ((event: any) => void) | null;
102
+ terminate?(): void;
103
+ }
104
+ /** Makes a fresh selection worker, e.g. `() => new SelectionWorker()` with Vite's `?worker`. */
105
+ export type SelectionWorkerFactory = () => SelectionWorkerLike;
106
+ /** Answers selection jobs inside a worker: `scope` is the worker's global (`self`). */
107
+ export declare function startSelectionWorker(scope: SelectionWorkerLike): void;
108
+ /** Sends selection jobs to a worker made by `factory`, one worker at a time. */
109
+ export declare class SelectionWorkerClient {
110
+ private readonly factory;
111
+ private worker;
112
+ /** Pixel buffers this worker already has, by their data array. */
113
+ private sent;
114
+ private nextKey;
115
+ private nextId;
116
+ private readonly pending;
117
+ constructor(factory: SelectionWorkerFactory);
118
+ /** Runs `job` on `pixels` in the worker. Aborting `signal` terminates the worker and rejects with an `AbortError`. */
119
+ run(job: SelectionJob, pixels: PixelBuffer, options?: {
120
+ signal?: AbortSignal;
121
+ onProgress?: SelectionProgress;
122
+ }): Promise<SelectionJobResult>;
123
+ /** Stops the worker; jobs still running reject with `reason` (default an `AbortError`). */
124
+ terminate(reason?: unknown): void;
125
+ private ensure;
126
+ }