@pixerate/editor 0.185.0 → 0.187.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 (40) hide show
  1. package/dist/{chunk-GYYSPMVU.js → chunk-FW7N64XK.js} +295 -188
  2. package/dist/{chunk-C6TRAAG4.cjs → chunk-X2KQQZBT.cjs} +355 -248
  3. package/dist/image-editor/controller.d.cts +89 -0
  4. package/dist/image-editor/controller.d.ts +89 -0
  5. package/dist/image-editor/index.cjs +1602 -1030
  6. package/dist/image-editor/index.js +591 -19
  7. package/dist/image-editor/layers/model.d.cts +5 -1
  8. package/dist/image-editor/layers/model.d.ts +5 -1
  9. package/dist/image-editor/layers/paint-ui.d.cts +2 -1
  10. package/dist/image-editor/layers/paint-ui.d.ts +2 -1
  11. package/dist/image-editor/layers/serialize.d.cts +3 -0
  12. package/dist/image-editor/layers/serialize.d.ts +3 -0
  13. package/dist/image-editor/psd/channels.d.cts +24 -0
  14. package/dist/image-editor/psd/channels.d.ts +24 -0
  15. package/dist/image-editor/psd/export.d.cts +3 -0
  16. package/dist/image-editor/psd/export.d.ts +3 -0
  17. package/dist/image-editor/psd/import.d.cts +10 -0
  18. package/dist/image-editor/psd/import.d.ts +10 -0
  19. package/dist/image-editor/renderer.d.cts +6 -0
  20. package/dist/image-editor/renderer.d.ts +6 -0
  21. package/dist/image-editor/selection/channels.d.cts +52 -0
  22. package/dist/image-editor/selection/channels.d.ts +52 -0
  23. package/dist/image-editor/selection/gesture.d.cts +7 -0
  24. package/dist/image-editor/selection/gesture.d.ts +7 -0
  25. package/dist/image-editor/selection/index.d.cts +2 -0
  26. package/dist/image-editor/selection/index.d.ts +2 -0
  27. package/dist/image-editor/selection/mask-files.d.cts +20 -0
  28. package/dist/image-editor/selection/mask-files.d.ts +20 -0
  29. package/dist/image-editor/selection/overlay.d.cts +2 -0
  30. package/dist/image-editor/selection/overlay.d.ts +2 -0
  31. package/dist/image-editor/tools.d.cts +3 -1
  32. package/dist/image-editor/tools.d.ts +3 -1
  33. package/dist/image-editor/types.d.cts +10 -0
  34. package/dist/image-editor/types.d.ts +10 -0
  35. package/dist/paint-editor/index.cjs +6 -6
  36. package/dist/paint-editor/index.js +1 -1
  37. package/package.json +1 -1
  38. package/skills/pixerate-image-editor/SKILL.md +12 -24
  39. package/skills/pixerate-image-editor/references/painting.md +29 -0
  40. package/skills/pixerate-image-selection-masking/SKILL.md +20 -2
@@ -474,7 +474,11 @@ export interface SmartObjectLayer extends LayerBase {
474
474
  export type ImageLayer = PixelLayer | AdjustmentLayerNode | GroupLayer | AnnotationLayer | SmartObjectLayer | ShapeLayer | TypeLayer;
475
475
  export type ImageLayerType = ImageLayer['type'];
476
476
  /** Which part of the active layer painting targets (`filter-mask`: a smart object's filter mask). */
477
- export type LayerTarget = 'pixels' | 'mask' | 'filter-mask';
477
+ /**
478
+ * What a paint, fill or retouch writes: a layer's pixels, its mask, a smart object's filter mask,
479
+ * or (in Quick Mask mode) the selection itself (`quick-mask`, not a layer).
480
+ */
481
+ export type LayerTarget = 'pixels' | 'mask' | 'filter-mask' | 'quick-mask';
478
482
  /** A fresh id with `prefix` (`layer`, `flt`, …). */
479
483
  export declare function newLayerId(prefix?: string): string;
480
484
  export type LayerLocation = RasterLayerLocation<ImageLayer>;
@@ -474,7 +474,11 @@ export interface SmartObjectLayer extends LayerBase {
474
474
  export type ImageLayer = PixelLayer | AdjustmentLayerNode | GroupLayer | AnnotationLayer | SmartObjectLayer | ShapeLayer | TypeLayer;
475
475
  export type ImageLayerType = ImageLayer['type'];
476
476
  /** Which part of the active layer painting targets (`filter-mask`: a smart object's filter mask). */
477
- export type LayerTarget = 'pixels' | 'mask' | 'filter-mask';
477
+ /**
478
+ * What a paint, fill or retouch writes: a layer's pixels, its mask, a smart object's filter mask,
479
+ * or (in Quick Mask mode) the selection itself (`quick-mask`, not a layer).
480
+ */
481
+ export type LayerTarget = 'pixels' | 'mask' | 'filter-mask' | 'quick-mask';
478
482
  /** A fresh id with `prefix` (`layer`, `flt`, …). */
479
483
  export declare function newLayerId(prefix?: string): string;
480
484
  export type LayerLocation = RasterLayerLocation<ImageLayer>;
@@ -139,7 +139,8 @@ export interface ShortcutEvent {
139
139
  /**
140
140
  * Applies a paint shortcut. Returns true when it was one (the caller then prevents the default).
141
141
  * B / Shift+B (Mixer Brush) / E / V choose the tool; [ and ] change the size, with Shift the hardness by 25 %; 1..9 set the
142
- * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them.
142
+ * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them; Q
143
+ * toggles Quick Mask mode (painting then edits the selection).
143
144
  */
144
145
  export declare function handlePaintShortcut(controller: ImageEditorController, e: ShortcutEvent): boolean;
145
146
  /** One pointer sample in document pixels. */
@@ -139,7 +139,8 @@ export interface ShortcutEvent {
139
139
  /**
140
140
  * Applies a paint shortcut. Returns true when it was one (the caller then prevents the default).
141
141
  * B / Shift+B (Mixer Brush) / E / V choose the tool; [ and ] change the size, with Shift the hardness by 25 %; 1..9 set the
142
- * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them.
142
+ * opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them; Q
143
+ * toggles Quick Mask mode (painting then edits the selection).
143
144
  */
144
145
  export declare function handlePaintShortcut(controller: ImageEditorController, e: ShortcutEvent): boolean;
145
146
  /** One pointer sample in document pixels. */
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.cjs';
10
10
  import type { SerializedSelection } from '../selection/mask.cjs';
11
+ import type { SerializedAlphaChannel } from '../selection/channels.cjs';
11
12
  import type { SerializedColorMode, SerializedColorProfile } from '../color-management.cjs';
12
13
  import { type PsdSmartFilter, type EffectSmartFilter, type ImageEffectGenerator, type SmartContents, type ImageLayer, type LayerFilter, type LayerLocks, type ShapeComponent, type ShapePaint, type ShapeStroke, type ParagraphRun, type TextRun, type TypeLayer } from './model.cjs';
13
14
  import { type GlobalLight, type LayerEffect, type LayerEffects } from '../../raster/effects/model.cjs';
@@ -222,6 +223,8 @@ export interface SerializedLayeredImageEditorState {
222
223
  /** Blur migrated from a v1 / v2 document with adjustment layers (runs after the layers). */
223
224
  legacyOutputBlur?: number;
224
225
  selection?: SerializedSelection;
226
+ /** Alpha channels (saved selections), run-length encoded. */
227
+ channels?: SerializedAlphaChannel[];
225
228
  /** Global light for layer effects (missing = 120°, 30°). */
226
229
  globalLight?: GlobalLight;
227
230
  /** The document's patterns for pattern effects, each an RGBA PNG data URL. */
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.js';
10
10
  import type { SerializedSelection } from '../selection/mask.js';
11
+ import type { SerializedAlphaChannel } from '../selection/channels.js';
11
12
  import type { SerializedColorMode, SerializedColorProfile } from '../color-management.js';
12
13
  import { type PsdSmartFilter, type EffectSmartFilter, type ImageEffectGenerator, type SmartContents, type ImageLayer, type LayerFilter, type LayerLocks, type ShapeComponent, type ShapePaint, type ShapeStroke, type ParagraphRun, type TextRun, type TypeLayer } from './model.js';
13
14
  import { type GlobalLight, type LayerEffect, type LayerEffects } from '../../raster/effects/model.js';
@@ -222,6 +223,8 @@ export interface SerializedLayeredImageEditorState {
222
223
  /** Blur migrated from a v1 / v2 document with adjustment layers (runs after the layers). */
223
224
  legacyOutputBlur?: number;
224
225
  selection?: SerializedSelection;
226
+ /** Alpha channels (saved selections), run-length encoded. */
227
+ channels?: SerializedAlphaChannel[];
225
228
  /** Global light for layer effects (missing = 120°, 30°). */
226
229
  globalLight?: GlobalLight;
227
230
  /** The document's patterns for pattern effects, each an RGBA PNG data URL. */
@@ -0,0 +1,24 @@
1
+ import type { PsdResource } from './file.cjs';
2
+ /** An alpha channel as the PSD code reads and writes it: an 8-bit plane over the canvas. */
3
+ export interface PsdAlphaChannel {
4
+ name: string;
5
+ /** `width × height` coverage, 255 = selected. */
6
+ data: Uint8Array;
7
+ /** `#rrggbb` overlay colour. */
8
+ color: string;
9
+ /** 0..1. */
10
+ opacity: number;
11
+ indicates: 'masked' | 'selected';
12
+ }
13
+ /** The image resources that name and describe `channels`. */
14
+ export declare function alphaChannelResources(channels: readonly PsdAlphaChannel[]): PsdResource[];
15
+ /**
16
+ * The alpha channels of a file: merged planes `first … channels − 1`, named from 1045 (or
17
+ * 1006), described by 1077. Spot colour channels (kind 2) are left out and reported.
18
+ */
19
+ export declare function readAlphaChannels(planes: Uint8Array, header: {
20
+ width: number;
21
+ height: number;
22
+ depth: number;
23
+ channels: number;
24
+ }, first: number, resource: (id: number) => Uint8Array | undefined, warn: (message: string) => void): PsdAlphaChannel[];
@@ -0,0 +1,24 @@
1
+ import type { PsdResource } from './file.js';
2
+ /** An alpha channel as the PSD code reads and writes it: an 8-bit plane over the canvas. */
3
+ export interface PsdAlphaChannel {
4
+ name: string;
5
+ /** `width × height` coverage, 255 = selected. */
6
+ data: Uint8Array;
7
+ /** `#rrggbb` overlay colour. */
8
+ color: string;
9
+ /** 0..1. */
10
+ opacity: number;
11
+ indicates: 'masked' | 'selected';
12
+ }
13
+ /** The image resources that name and describe `channels`. */
14
+ export declare function alphaChannelResources(channels: readonly PsdAlphaChannel[]): PsdResource[];
15
+ /**
16
+ * The alpha channels of a file: merged planes `first … channels − 1`, named from 1045 (or
17
+ * 1006), described by 1077. Spot colour channels (kind 2) are left out and reported.
18
+ */
19
+ export declare function readAlphaChannels(planes: Uint8Array, header: {
20
+ width: number;
21
+ height: number;
22
+ depth: number;
23
+ channels: number;
24
+ }, first: number, resource: (id: number) => Uint8Array | undefined, warn: (message: string) => void): PsdAlphaChannel[];
@@ -1,4 +1,5 @@
1
1
  import { type ImageLayer, type SmartContents } from '../layers/model.cjs';
2
+ import { type PsdAlphaChannel } from './channels.cjs';
2
3
  import { type GlobalLight } from '../../raster/effects/model.cjs';
3
4
  import { type EffectPattern } from '../../raster/effects/patterns.cjs';
4
5
  export interface PsdExportInput {
@@ -8,6 +9,8 @@ export interface PsdExportInput {
8
9
  layers: readonly ImageLayer[];
9
10
  /** The composite, `width × height` RGBA, written as the merged image. */
10
11
  merged: ArrayLike<number>;
12
+ /** Alpha channels, written as extra merged planes with their names and display info. */
13
+ alphaChannels?: readonly PsdAlphaChannel[];
11
14
  /** Pixels per inch (default 72). */
12
15
  resolution?: number;
13
16
  /** The document's patterns; those the effects use are embedded (built-in ones too). */
@@ -1,4 +1,5 @@
1
1
  import { type ImageLayer, type SmartContents } from '../layers/model.js';
2
+ import { type PsdAlphaChannel } from './channels.js';
2
3
  import { type GlobalLight } from '../../raster/effects/model.js';
3
4
  import { type EffectPattern } from '../../raster/effects/patterns.js';
4
5
  export interface PsdExportInput {
@@ -8,6 +9,8 @@ export interface PsdExportInput {
8
9
  layers: readonly ImageLayer[];
9
10
  /** The composite, `width × height` RGBA, written as the merged image. */
10
11
  merged: ArrayLike<number>;
12
+ /** Alpha channels, written as extra merged planes with their names and display info. */
13
+ alphaChannels?: readonly PsdAlphaChannel[];
11
14
  /** Pixels per inch (default 72). */
12
15
  resolution?: number;
13
16
  /** The document's patterns; those the effects use are embedded (built-in ones too). */
@@ -1,3 +1,11 @@
1
+ /**
2
+ * PSD / PSB → our layer tree. Everything the model holds maps directly (smart objects with their
3
+ * embedded contents, placement, warp, smart filters and filter mask; shape layers with their
4
+ * paths, fill, stroke and live shapes; type layers with their text, styles and Photoshop's pixels
5
+ * until edited); everything else comes in as close as it can (fill layers as their stored pixels)
6
+ * with a warning naming the layers.
7
+ */
8
+ import { type PsdAlphaChannel } from './channels.cjs';
1
9
  import type { ImageLayer, LayerBlendMode } from '../layers/model.cjs';
2
10
  import { type PsdFile } from './file.cjs';
3
11
  import type { DocumentColorProfile } from '../color-management.cjs';
@@ -54,6 +62,8 @@ export interface PsdImportResult {
54
62
  };
55
63
  /** The bits per channel the layers keep: 16 or 32 for such files (not indexed or bitmap), else 8. */
56
64
  bitDepth: 8 | 16 | 32;
65
+ /** The file's alpha channels (saved selections), as 8-bit planes. */
66
+ alphaChannels?: PsdAlphaChannel[];
57
67
  }
58
68
  export interface PsdImportOptions {
59
69
  /** Makes layer ids (defaults to `psd-<n>`). */
@@ -1,3 +1,11 @@
1
+ /**
2
+ * PSD / PSB → our layer tree. Everything the model holds maps directly (smart objects with their
3
+ * embedded contents, placement, warp, smart filters and filter mask; shape layers with their
4
+ * paths, fill, stroke and live shapes; type layers with their text, styles and Photoshop's pixels
5
+ * until edited); everything else comes in as close as it can (fill layers as their stored pixels)
6
+ * with a warning naming the layers.
7
+ */
8
+ import { type PsdAlphaChannel } from './channels.js';
1
9
  import type { ImageLayer, LayerBlendMode } from '../layers/model.js';
2
10
  import { type PsdFile } from './file.js';
3
11
  import type { DocumentColorProfile } from '../color-management.js';
@@ -54,6 +62,8 @@ export interface PsdImportResult {
54
62
  };
55
63
  /** The bits per channel the layers keep: 16 or 32 for such files (not indexed or bitmap), else 8. */
56
64
  bitDepth: 8 | 16 | 32;
65
+ /** The file's alpha channels (saved selections), as 8-bit planes. */
66
+ alphaChannels?: PsdAlphaChannel[];
57
67
  }
58
68
  export interface PsdImportOptions {
59
69
  /** Makes layer ids (defaults to `psd-<n>`). */
@@ -174,6 +174,12 @@ export declare class ImageEditorRenderer {
174
174
  private publishHistogram;
175
175
  private quickMaskCache;
176
176
  private outlineCache;
177
+ private emptyMaskCache;
178
+ /** An empty selection of the image's size (Quick Mask mode with nothing selected). */
179
+ private emptyMask;
180
+ private overlayCache;
181
+ /** A channel's tint (colour, opacity, masked or selected area), drawn in natural image space. */
182
+ private drawMaskOverlay;
177
183
  /** Rubylith over the unselected area, drawn in natural image space. */
178
184
  private drawQuickMask;
179
185
  /**
@@ -174,6 +174,12 @@ export declare class ImageEditorRenderer {
174
174
  private publishHistogram;
175
175
  private quickMaskCache;
176
176
  private outlineCache;
177
+ private emptyMaskCache;
178
+ /** An empty selection of the image's size (Quick Mask mode with nothing selected). */
179
+ private emptyMask;
180
+ private overlayCache;
181
+ /** A channel's tint (colour, opacity, masked or selected area), drawn in natural image space. */
182
+ private drawMaskOverlay;
177
183
  /** Rubylith over the unselected area, drawn in natural image space. */
178
184
  private drawQuickMask;
179
185
  /**
@@ -0,0 +1,52 @@
1
+ import { type SelectionMask, type SerializedSelection } from './mask.cjs';
2
+ /**
3
+ * An alpha channel: a saved selection kept with the document (Select › Save Selection), shown
4
+ * as a tinted overlay when visible. Its mask is the selection's 8-bit coverage over the canvas
5
+ * (immutable, so undo steps share it).
6
+ */
7
+ export interface AlphaChannel {
8
+ id: string;
9
+ name: string;
10
+ /** Coverage (255 = selected). An empty channel has a mask with `bounds: null`. */
11
+ mask: SelectionMask;
12
+ /** Overlay tint, `#rrggbb` (default red, the Quick Mask's). */
13
+ color: string;
14
+ /** Overlay opacity 0..1 (default 0.5). */
15
+ opacity: number;
16
+ /** Whether the tint covers the `masked` (unselected, default) or the `selected` area. */
17
+ indicates: 'masked' | 'selected';
18
+ /** Shown as an overlay on the canvas (default false). */
19
+ visible: boolean;
20
+ }
21
+ /** An alpha channel as stored in a document. */
22
+ export interface SerializedAlphaChannel extends Omit<AlphaChannel, 'mask'> {
23
+ mask: SerializedSelection;
24
+ }
25
+ export declare const DEFAULT_CHANNEL_COLOR = "#ff0000";
26
+ /** A summary of a channel for agents and panels (no pixels). */
27
+ export declare function describeChannel(channel: AlphaChannel): {
28
+ bounds: import("../index.cjs").CropBox | null;
29
+ percent: number;
30
+ id: string;
31
+ name: string;
32
+ /** Overlay tint, `#rrggbb` (default red, the Quick Mask's). */
33
+ color: string;
34
+ /** Overlay opacity 0..1 (default 0.5). */
35
+ opacity: number;
36
+ /** Whether the tint covers the `masked` (unselected, default) or the `selected` area. */
37
+ indicates: "masked" | "selected";
38
+ /** Shown as an overlay on the canvas (default false). */
39
+ visible: boolean;
40
+ };
41
+ export declare function serializeChannels(channels: readonly AlphaChannel[]): SerializedAlphaChannel[];
42
+ /** Restores stored channels, skipping (and reporting) damaged ones or ones of another size. */
43
+ export declare function deserializeChannels(value: unknown, size: {
44
+ width: number;
45
+ height: number;
46
+ }, problems?: string[]): AlphaChannel[];
47
+ /** A channel's grey thumbnail (white = selected) as RGBA pixels, at most `maxSide` px. */
48
+ export declare function channelThumbnail(channel: AlphaChannel, maxSide?: number): {
49
+ width: number;
50
+ height: number;
51
+ data: Uint8ClampedArray;
52
+ };
@@ -0,0 +1,52 @@
1
+ import { type SelectionMask, type SerializedSelection } from './mask.js';
2
+ /**
3
+ * An alpha channel: a saved selection kept with the document (Select › Save Selection), shown
4
+ * as a tinted overlay when visible. Its mask is the selection's 8-bit coverage over the canvas
5
+ * (immutable, so undo steps share it).
6
+ */
7
+ export interface AlphaChannel {
8
+ id: string;
9
+ name: string;
10
+ /** Coverage (255 = selected). An empty channel has a mask with `bounds: null`. */
11
+ mask: SelectionMask;
12
+ /** Overlay tint, `#rrggbb` (default red, the Quick Mask's). */
13
+ color: string;
14
+ /** Overlay opacity 0..1 (default 0.5). */
15
+ opacity: number;
16
+ /** Whether the tint covers the `masked` (unselected, default) or the `selected` area. */
17
+ indicates: 'masked' | 'selected';
18
+ /** Shown as an overlay on the canvas (default false). */
19
+ visible: boolean;
20
+ }
21
+ /** An alpha channel as stored in a document. */
22
+ export interface SerializedAlphaChannel extends Omit<AlphaChannel, 'mask'> {
23
+ mask: SerializedSelection;
24
+ }
25
+ export declare const DEFAULT_CHANNEL_COLOR = "#ff0000";
26
+ /** A summary of a channel for agents and panels (no pixels). */
27
+ export declare function describeChannel(channel: AlphaChannel): {
28
+ bounds: import("../index.js").CropBox | null;
29
+ percent: number;
30
+ id: string;
31
+ name: string;
32
+ /** Overlay tint, `#rrggbb` (default red, the Quick Mask's). */
33
+ color: string;
34
+ /** Overlay opacity 0..1 (default 0.5). */
35
+ opacity: number;
36
+ /** Whether the tint covers the `masked` (unselected, default) or the `selected` area. */
37
+ indicates: "masked" | "selected";
38
+ /** Shown as an overlay on the canvas (default false). */
39
+ visible: boolean;
40
+ };
41
+ export declare function serializeChannels(channels: readonly AlphaChannel[]): SerializedAlphaChannel[];
42
+ /** Restores stored channels, skipping (and reporting) damaged ones or ones of another size. */
43
+ export declare function deserializeChannels(value: unknown, size: {
44
+ width: number;
45
+ height: number;
46
+ }, problems?: string[]): AlphaChannel[];
47
+ /** A channel's grey thumbnail (white = selected) as RGBA pixels, at most `maxSide` px. */
48
+ export declare function channelThumbnail(channel: AlphaChannel, maxSide?: number): {
49
+ width: number;
50
+ height: number;
51
+ data: Uint8ClampedArray;
52
+ };
@@ -76,3 +76,10 @@ export declare function handleSelectionShortcut(controller: ImageEditorControlle
76
76
  shiftKey?: boolean;
77
77
  altKey?: boolean;
78
78
  }, onError?: (message: string) => void): boolean;
79
+ /** Q (no modifiers) toggles Quick Mask mode. Returns true when the key was used. */
80
+ export declare function handleQuickMaskKey(controller: ImageEditorController, e: {
81
+ key: string;
82
+ ctrlKey?: boolean;
83
+ metaKey?: boolean;
84
+ altKey?: boolean;
85
+ }): boolean;
@@ -76,3 +76,10 @@ export declare function handleSelectionShortcut(controller: ImageEditorControlle
76
76
  shiftKey?: boolean;
77
77
  altKey?: boolean;
78
78
  }, onError?: (message: string) => void): boolean;
79
+ /** Q (no modifiers) toggles Quick Mask mode. Returns true when the key was used. */
80
+ export declare function handleQuickMaskKey(controller: ImageEditorController, e: {
81
+ key: string;
82
+ ctrlKey?: boolean;
83
+ metaKey?: boolean;
84
+ altKey?: boolean;
85
+ }): boolean;
@@ -9,3 +9,5 @@ export * from './tool-options.cjs';
9
9
  export * from './gesture.cjs';
10
10
  export * from './segmentation.cjs';
11
11
  export * from './stroke.cjs';
12
+ export * from './channels.cjs';
13
+ export * from './mask-files.cjs';
@@ -9,3 +9,5 @@ export * from './tool-options.js';
9
9
  export * from './gesture.js';
10
10
  export * from './segmentation.js';
11
11
  export * from './stroke.js';
12
+ export * from './channels.js';
13
+ export * from './mask-files.js';
@@ -0,0 +1,20 @@
1
+ /** Framework-free helpers behind the Import and Export PNG buttons of the React and Svelte Channels panels. */
2
+ import type { ImageEditorController, MaskImageSource } from '../controller.cjs';
3
+ import type { AlphaChannel } from './channels.cjs';
4
+ /** Types the mask file pickers accept. */
5
+ export declare const MASK_FILE_ACCEPT = "image/png,image/jpeg,image/webp,image/gif,image/bmp";
6
+ /** A channel name from a file name: without its extension, or `Alpha n`. */
7
+ export declare function maskNameFromFile(file: Blob): string | undefined;
8
+ /** Reads a picked mask image (white = selected) into a new alpha channel named after the file (one undo step). */
9
+ export declare function openMaskFile(controller: ImageEditorController, file: Blob): Promise<AlphaChannel>;
10
+ /** A file name for an exported mask: `name` with a `.png` extension. */
11
+ export declare function maskFileName(name: string): string;
12
+ /**
13
+ * Writes the selection, a channel or a layer mask as a full-size greyscale PNG and offers it as a
14
+ * download (in a browser). Returns the file name and size.
15
+ */
16
+ export declare function downloadMaskImage(controller: ImageEditorController, source: MaskImageSource, name?: string): {
17
+ fileName: string;
18
+ width: number;
19
+ height: number;
20
+ };
@@ -0,0 +1,20 @@
1
+ /** Framework-free helpers behind the Import and Export PNG buttons of the React and Svelte Channels panels. */
2
+ import type { ImageEditorController, MaskImageSource } from '../controller.js';
3
+ import type { AlphaChannel } from './channels.js';
4
+ /** Types the mask file pickers accept. */
5
+ export declare const MASK_FILE_ACCEPT = "image/png,image/jpeg,image/webp,image/gif,image/bmp";
6
+ /** A channel name from a file name: without its extension, or `Alpha n`. */
7
+ export declare function maskNameFromFile(file: Blob): string | undefined;
8
+ /** Reads a picked mask image (white = selected) into a new alpha channel named after the file (one undo step). */
9
+ export declare function openMaskFile(controller: ImageEditorController, file: Blob): Promise<AlphaChannel>;
10
+ /** A file name for an exported mask: `name` with a `.png` extension. */
11
+ export declare function maskFileName(name: string): string;
12
+ /**
13
+ * Writes the selection, a channel or a layer mask as a full-size greyscale PNG and offers it as a
14
+ * download (in a browser). Returns the file name and size.
15
+ */
16
+ export declare function downloadMaskImage(controller: ImageEditorController, source: MaskImageSource, name?: string): {
17
+ fileName: string;
18
+ width: number;
19
+ height: number;
20
+ };
@@ -10,6 +10,8 @@ export interface QuickMaskStyle {
10
10
  color?: readonly [number, number, number];
11
11
  /** 0..1 (default 0.5): opacity over fully unselected pixels. */
12
12
  opacity?: number;
13
+ /** Tint the unselected area (`masked`, default) or the selected area (`selected`). */
14
+ indicates?: 'masked' | 'selected';
13
15
  }
14
16
  /**
15
17
  * Quick Mask view: RGBA pixels (natural image size) tinting the *unselected* area, so the
@@ -10,6 +10,8 @@ export interface QuickMaskStyle {
10
10
  color?: readonly [number, number, number];
11
11
  /** 0..1 (default 0.5): opacity over fully unselected pixels. */
12
12
  opacity?: number;
13
+ /** Tint the unselected area (`masked`, default) or the selected area (`selected`). */
14
+ indicates?: 'masked' | 'selected';
13
15
  }
14
16
  /**
15
17
  * Quick Mask view: RGBA pixels (natural image size) tinting the *unselected* area, so the
@@ -27,7 +27,9 @@ export interface ImageEditorToolProviderOptions {
27
27
  * `select_rect`, `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`,
28
28
  * `select_color_range`, `grow_selection`, `select_similar`, `reselect`,
29
29
  * `select_layer_transparency`, `stroke_selection`, `crop_to_selection`, `content_aware_fill`,
30
- * `copy_pixels`, `cut_pixels`, `paste_pixels`,
30
+ * `copy_pixels`, `cut_pixels`, `paste_pixels`, alpha channels (`list_channels`, `save_selection`,
31
+ * `load_selection_from_channel`, `set_channel_properties`, `duplicate_channel`,
32
+ * `delete_channel`), `set_quick_mask`,
31
33
  * `load_selection_from_image`, `load_selection_from_mask`, `set_selection_display`,
32
34
  * `modify_selection`, `refine_selection`, `apply_selection_as_mask` and the deprecated
33
35
  * `select_region` / `select_by_color` (see `createImageSelectionTools`).
@@ -27,7 +27,9 @@ export interface ImageEditorToolProviderOptions {
27
27
  * `select_rect`, `select_ellipse`, `select_polygon`, `select_line`, `magic_wand`,
28
28
  * `select_color_range`, `grow_selection`, `select_similar`, `reselect`,
29
29
  * `select_layer_transparency`, `stroke_selection`, `crop_to_selection`, `content_aware_fill`,
30
- * `copy_pixels`, `cut_pixels`, `paste_pixels`,
30
+ * `copy_pixels`, `cut_pixels`, `paste_pixels`, alpha channels (`list_channels`, `save_selection`,
31
+ * `load_selection_from_channel`, `set_channel_properties`, `duplicate_channel`,
32
+ * `delete_channel`), `set_quick_mask`,
31
33
  * `load_selection_from_image`, `load_selection_from_mask`, `set_selection_display`,
32
34
  * `modify_selection`, `refine_selection`, `apply_selection_as_mask` and the deprecated
33
35
  * `select_region` / `select_by_color` (see `createImageSelectionTools`).
@@ -2,6 +2,7 @@ import type { GlobalLight } from '../raster/effects/model.cjs';
2
2
  import type { EffectPattern } from '../raster/effects/patterns.cjs';
3
3
  import type { BlendMode } from './blend.cjs';
4
4
  import type { SelectionMask, SerializedSelection } from './selection/mask.cjs';
5
+ import type { AlphaChannel, SerializedAlphaChannel } from './selection/channels.cjs';
5
6
  import type { ImageLayer, LayerTarget } from './layers/model.cjs';
6
7
  import type { SerializedLayeredImageEditorState } from './layers/serialize.cjs';
7
8
  import type { PaintOptions } from './controller.cjs';
@@ -313,6 +314,13 @@ export interface ImageEditorState {
313
314
  quickMask?: boolean;
314
315
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
315
316
  selectionDisplay?: 'ants' | 'quickMask' | 'none';
317
+ /**
318
+ * Quick Mask mode: painting and fills without a layer edit the selection itself (white
319
+ * selects, black deselects), shown as a tint. View state; the edits are undo steps.
320
+ */
321
+ quickMaskEditing?: boolean;
322
+ /** Alpha channels: saved selections kept with the document, recorded in undo history. */
323
+ channels?: AlphaChannel[];
316
324
  /**
317
325
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
318
326
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -380,6 +388,8 @@ export interface LegacySerializedImageEditorState {
380
388
  annotations: Annotation[];
381
389
  /** The active selection, run-length encoded. Missing when nothing is selected. */
382
390
  selection?: SerializedSelection;
391
+ /** Alpha channels (saved selections), run-length encoded. */
392
+ channels?: SerializedAlphaChannel[];
383
393
  }
384
394
  /**
385
395
  * A stored editor state: the document-level schema (v1 / v2) or the layered schema (v3, see
@@ -2,6 +2,7 @@ import type { GlobalLight } from '../raster/effects/model.js';
2
2
  import type { EffectPattern } from '../raster/effects/patterns.js';
3
3
  import type { BlendMode } from './blend.js';
4
4
  import type { SelectionMask, SerializedSelection } from './selection/mask.js';
5
+ import type { AlphaChannel, SerializedAlphaChannel } from './selection/channels.js';
5
6
  import type { ImageLayer, LayerTarget } from './layers/model.js';
6
7
  import type { SerializedLayeredImageEditorState } from './layers/serialize.js';
7
8
  import type { PaintOptions } from './controller.js';
@@ -313,6 +314,13 @@ export interface ImageEditorState {
313
314
  quickMask?: boolean;
314
315
  /** How the canvas shows the selection (view state; `quickMask` mirrors `'quickMask'`). */
315
316
  selectionDisplay?: 'ants' | 'quickMask' | 'none';
317
+ /**
318
+ * Quick Mask mode: painting and fills without a layer edit the selection itself (white
319
+ * selects, black deselects), shown as a tint. View state; the edits are undo steps.
320
+ */
321
+ quickMaskEditing?: boolean;
322
+ /** Alpha channels: saved selections kept with the document, recorded in undo history. */
323
+ channels?: AlphaChannel[];
316
324
  /**
317
325
  * The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
318
326
  * pixels are the source image. Layers are immutable: compare them by identity.
@@ -380,6 +388,8 @@ export interface LegacySerializedImageEditorState {
380
388
  annotations: Annotation[];
381
389
  /** The active selection, run-length encoded. Missing when nothing is selected. */
382
390
  selection?: SerializedSelection;
391
+ /** Alpha channels (saved selections), run-length encoded. */
392
+ channels?: SerializedAlphaChannel[];
383
393
  }
384
394
  /**
385
395
  * A stored editor state: the document-level schema (v1 / v2) or the layered schema (v3, see
@@ -7,7 +7,7 @@ var _chunkZ64NRDEHcjs = require('../chunk-Z64NRDEH.cjs');
7
7
 
8
8
 
9
9
 
10
- var _chunkC6TRAAG4cjs = require('../chunk-C6TRAAG4.cjs');
10
+ var _chunkX2KQQZBTcjs = require('../chunk-X2KQQZBT.cjs');
11
11
  require('../chunk-A2IS7EHE.cjs');
12
12
 
13
13
 
@@ -1653,11 +1653,11 @@ function header(state, options) {
1653
1653
  return out;
1654
1654
  }
1655
1655
  function serializePaintDocument(state, options = {}) {
1656
- const { layers, assets } = _chunkC6TRAAG4cjs.serializeLayers.call(void 0, state.layers);
1656
+ const { layers, assets } = _chunkX2KQQZBTcjs.serializeLayers.call(void 0, state.layers);
1657
1657
  return { ...header(state, options), layers, assets };
1658
1658
  }
1659
1659
  async function serializePaintDocumentExternal(state, store, options = {}) {
1660
- const { layers, assets } = await _chunkC6TRAAG4cjs.serializeLayersExternal.call(void 0, state.layers, store);
1660
+ const { layers, assets } = await _chunkX2KQQZBTcjs.serializeLayersExternal.call(void 0, state.layers, store);
1661
1661
  return { ...header(state, options), layers, assets };
1662
1662
  }
1663
1663
  function paintLayersOnly(layers, problems) {
@@ -1694,7 +1694,7 @@ function deserializePaintDocument(raw) {
1694
1694
  const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
1695
1695
  const paper = _chunkYQ5C5BVKcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
1696
1696
  const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
1697
- const layers = paintLayersOnly(_chunkC6TRAAG4cjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1697
+ const layers = paintLayersOnly(_chunkX2KQQZBTcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
1698
1698
  const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
1699
1699
  const activeLayerId = wanted && _chunkHGTDMKNEcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHGTDMKNEcjs.flattenLayers.call(void 0, layers), 'access', _70 => _70.filter, 'call', _71 => _71((l) => l.type === "pixel"), 'access', _72 => _72.pop, 'call', _73 => _73(), 'optionalAccess', _74 => _74.id]), () => ( null));
1700
1700
  const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
@@ -1710,7 +1710,7 @@ async function deserializePaintDocumentAsync(raw, store) {
1710
1710
  if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
1711
1711
  const r = raw;
1712
1712
  const problems = [];
1713
- const assets = await _chunkC6TRAAG4cjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1713
+ const assets = await _chunkX2KQQZBTcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
1714
1714
  const loaded = deserializePaintDocument({ ...r, assets });
1715
1715
  return { ...loaded, problems: [...problems, ...loaded.problems] };
1716
1716
  }
@@ -5409,7 +5409,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
5409
5409
  return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
5410
5410
  });
5411
5411
  const layers = toStandard(dried);
5412
- const result = _chunkC6TRAAG4cjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5412
+ const result = _chunkX2KQQZBTcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
5413
5413
  for (const [mode, names] of changed) {
5414
5414
  const label = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _271 => _271.find, 'call', _272 => _272((m) => m.id === mode), 'optionalAccess', _273 => _273.label]), () => ( mode));
5415
5415
  const std = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _274 => _274.find, 'call', _275 => _275((m) => m.id === _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _276 => _276.label]), () => ( _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)));
@@ -7,7 +7,7 @@ import {
7
7
  resolveExternalAssets,
8
8
  serializeLayers,
9
9
  serializeLayersExternal
10
- } from "../chunk-GYYSPMVU.js";
10
+ } from "../chunk-FW7N64XK.js";
11
11
  import "../chunk-3CI7FRMK.js";
12
12
  import {
13
13
  EffectRendererPool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.185.0",
3
+ "version": "0.187.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",