@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.
- package/dist/{chunk-GYYSPMVU.js → chunk-FW7N64XK.js} +295 -188
- package/dist/{chunk-C6TRAAG4.cjs → chunk-X2KQQZBT.cjs} +355 -248
- package/dist/image-editor/controller.d.cts +89 -0
- package/dist/image-editor/controller.d.ts +89 -0
- package/dist/image-editor/index.cjs +1602 -1030
- package/dist/image-editor/index.js +591 -19
- package/dist/image-editor/layers/model.d.cts +5 -1
- package/dist/image-editor/layers/model.d.ts +5 -1
- package/dist/image-editor/layers/paint-ui.d.cts +2 -1
- package/dist/image-editor/layers/paint-ui.d.ts +2 -1
- package/dist/image-editor/layers/serialize.d.cts +3 -0
- package/dist/image-editor/layers/serialize.d.ts +3 -0
- package/dist/image-editor/psd/channels.d.cts +24 -0
- package/dist/image-editor/psd/channels.d.ts +24 -0
- package/dist/image-editor/psd/export.d.cts +3 -0
- package/dist/image-editor/psd/export.d.ts +3 -0
- package/dist/image-editor/psd/import.d.cts +10 -0
- package/dist/image-editor/psd/import.d.ts +10 -0
- package/dist/image-editor/renderer.d.cts +6 -0
- package/dist/image-editor/renderer.d.ts +6 -0
- package/dist/image-editor/selection/channels.d.cts +52 -0
- package/dist/image-editor/selection/channels.d.ts +52 -0
- package/dist/image-editor/selection/gesture.d.cts +7 -0
- package/dist/image-editor/selection/gesture.d.ts +7 -0
- package/dist/image-editor/selection/index.d.cts +2 -0
- package/dist/image-editor/selection/index.d.ts +2 -0
- package/dist/image-editor/selection/mask-files.d.cts +20 -0
- package/dist/image-editor/selection/mask-files.d.ts +20 -0
- package/dist/image-editor/selection/overlay.d.cts +2 -0
- package/dist/image-editor/selection/overlay.d.ts +2 -0
- package/dist/image-editor/tools.d.cts +3 -1
- package/dist/image-editor/tools.d.ts +3 -1
- package/dist/image-editor/types.d.cts +10 -0
- package/dist/image-editor/types.d.ts +10 -0
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +12 -24
- package/skills/pixerate-image-editor/references/painting.md +29 -0
- 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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -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
|
|
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 } =
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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)));
|