@pixerate/editor 0.88.0 → 0.89.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/THIRD_PARTY_NOTICES.md +8 -2
- package/dist/agent/index.cjs +28 -28
- package/dist/agent/index.js +3 -3
- package/dist/canvas/index.cjs +3 -3
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.js +16 -16
- package/dist/{chunk-TYOAJDFD.cjs → chunk-66IMF6OD.cjs} +3 -3
- package/dist/{chunk-TYOAJDFD.cjs.map → chunk-66IMF6OD.cjs.map} +1 -1
- package/dist/chunk-D4ZCU72J.js +604 -0
- package/dist/chunk-D4ZCU72J.js.map +1 -0
- package/dist/{chunk-IMSX4IVG.js → chunk-FWEO3HSL.js} +4 -4
- package/dist/chunk-H543GD6T.cjs +1696 -0
- package/dist/chunk-H543GD6T.cjs.map +1 -0
- package/dist/{chunk-ROXFP2LQ.cjs → chunk-HNDSPZ5T.cjs} +4 -4
- package/dist/{chunk-ROXFP2LQ.cjs.map → chunk-HNDSPZ5T.cjs.map} +1 -1
- package/dist/{chunk-MXF4DP2C.cjs → chunk-J3B45HTA.cjs} +74 -74
- package/dist/{chunk-MXF4DP2C.cjs.map → chunk-J3B45HTA.cjs.map} +1 -1
- package/dist/{chunk-GNO5PEMH.js → chunk-OK7T2LHK.js} +2 -2
- package/dist/chunk-P5TPUNBZ.js +1696 -0
- package/dist/chunk-P5TPUNBZ.js.map +1 -0
- package/dist/chunk-PDCITYBT.cjs +416 -0
- package/dist/chunk-PDCITYBT.cjs.map +1 -0
- package/dist/{chunk-RKJDBXTY.cjs → chunk-T4XWVPJK.cjs} +3 -3
- package/dist/{chunk-RKJDBXTY.cjs.map → chunk-T4XWVPJK.cjs.map} +1 -1
- package/dist/{chunk-ZQNDSUZO.js → chunk-UKI64KUD.js} +6 -6
- package/dist/{chunk-SVW2UNUC.js → chunk-WON34HKM.js} +2 -2
- package/dist/chunk-YLB2WVNA.js +416 -0
- package/dist/chunk-YLB2WVNA.js.map +1 -0
- package/dist/chunk-ZOOEX3WT.cjs +604 -0
- package/dist/chunk-ZOOEX3WT.cjs.map +1 -0
- package/dist/extensions/index.cjs +6 -6
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.js +5 -5
- package/dist/image-editor/index.cjs +4387 -690
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +1677 -590
- package/dist/image-editor/index.d.ts +1677 -590
- package/dist/image-editor/index.js +4273 -576
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +27 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -10
- package/dist/paint/index.cjs +38 -0
- package/dist/paint/index.cjs.map +1 -0
- package/dist/paint/index.d.cts +167 -0
- package/dist/paint/index.d.ts +167 -0
- package/dist/paint/index.js +38 -0
- package/dist/paint/index.js.map +1 -0
- package/dist/raster/index.cjs +121 -0
- package/dist/raster/index.cjs.map +1 -0
- package/dist/raster/index.d.cts +365 -0
- package/dist/raster/index.d.ts +365 -0
- package/dist/raster/index.js +121 -0
- package/dist/raster/index.js.map +1 -0
- package/dist/serializers/index.cjs +4 -4
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.js +3 -3
- package/dist/surface-fJhkmNQn.d.cts +181 -0
- package/dist/surface-fJhkmNQn.d.ts +181 -0
- package/package.json +13 -2
- package/skills/pixerate-image-editor/SKILL.md +111 -11
- /package/dist/{chunk-IMSX4IVG.js.map → chunk-FWEO3HSL.js.map} +0 -0
- /package/dist/{chunk-GNO5PEMH.js.map → chunk-OK7T2LHK.js.map} +0 -0
- /package/dist/{chunk-ZQNDSUZO.js.map → chunk-UKI64KUD.js.map} +0 -0
- /package/dist/{chunk-SVW2UNUC.js.map → chunk-WON34HKM.js.map} +0 -0
|
@@ -1,56 +1,14 @@
|
|
|
1
|
+
import { P as PixelSurface, T as TiledSurface, B as BlendMode } from '../surface-fJhkmNQn.js';
|
|
2
|
+
export { a as BLEND_MODES, b as BlendModeInfo, M as MaskSurface, R as RasterRect, c as Rgb, d as Rgba, S as SurfaceDraft, e as TILE, f as TILE_SHIFT, g as Tile, h as TileKey, i as blendChannel, j as blendImageData, k as blendLum, l as blendPixel, m as blendRgb, n as canvasCompositeOperation, o as collectTiles, p as contentBounds, q as emptySurface, r as fillRect, s as finishTile, t as isBlendMode, u as isSeparableBlendMode, v as normalizeBlendMode, w as packRgba, x as readPixel, y as readRegion, z as setLum, A as solidSurface, C as surfaceBytes, D as surfaceFromPixels, E as surfacesEqual, F as tileCoord, G as tileKey, H as tileRect, I as tilesInRect, J as translateSurface, K as uniformTile, L as writeRegion } from '../surface-fJhkmNQn.js';
|
|
3
|
+
import { RasterLayerBase, RasterMask as RasterMask$1, RasterPixelLayer, GroupBlendMode, LayerLocation as LayerLocation$1, LayerLocks, RasterSources, RasterCompositor, CompositorOptions } from '../raster/index.js';
|
|
4
|
+
export { CompositeCallOptions, CompositeStats, DIRECT_GAUSSIAN_MAX_SIGMA, DecodedPng, ZlibError, adler32, base64ToBytes, blendTile, bytesToBase64, changedTiles, decodePng, deflate, deflateRaw, encodePng, findLayer, flattenLayers, gaussianBlur, inflate, inflateRaw, insertLayer, isLayerLocked, isPng, mapLayer, parseDataUrl, pngDataUrl } from '../raster/index.js';
|
|
5
|
+
import { BrushSettings, StrokeCoverage, StrokeApply, StrokePoint } from '../paint/index.js';
|
|
6
|
+
export { CoverageMap, DEFAULT_BRUSH, Dab, DabWalker, MAX_BRUSH_SIZE, applyStrokeToTile, coverageTileCoord, dabCoverage, dabRect, normalizeBrush, rasterizeDab, smoothPoints, tipFalloff, tipReach, tipShape, walkDabs } from '../paint/index.js';
|
|
1
7
|
import { b as LoadReport, J as JsonObject, f as MigrationStep } from '../migrate-iTlm3a8h.js';
|
|
2
8
|
import { a as AgentToolProvider, A as AgentTool } from '../registry-D-4fit9C.js';
|
|
3
9
|
import { b as CaptureSurface } from '../capture-wwNGaW05.js';
|
|
4
10
|
import '../schema-Di0CS6Pe.js';
|
|
5
11
|
|
|
6
|
-
/**
|
|
7
|
-
* Photoshop blend modes on straight (non-premultiplied) 0..1 colours.
|
|
8
|
-
*
|
|
9
|
-
* Formulas follow the W3C Compositing / ISO 32000 definitions, with Photoshop's variants where
|
|
10
|
-
* they differ (Soft Light, Vivid / Linear / Pin Light, Hard Mix, Linear Burn / Dodge, Subtract,
|
|
11
|
-
* Divide, Darker / Lighter Color), and the hardened `ClipColor` for the non-separable modes.
|
|
12
|
-
*/
|
|
13
|
-
type BlendMode = 'normal' | 'darken' | 'multiply' | 'color-burn' | 'linear-burn' | 'darker-color' | 'lighten' | 'screen' | 'color-dodge' | 'linear-dodge' | 'lighter-color' | 'overlay' | 'soft-light' | 'hard-light' | 'vivid-light' | 'linear-light' | 'pin-light' | 'hard-mix' | 'difference' | 'exclusion' | 'subtract' | 'divide' | 'hue' | 'saturation' | 'color' | 'luminosity';
|
|
14
|
-
interface BlendModeInfo {
|
|
15
|
-
id: BlendMode;
|
|
16
|
-
label: string;
|
|
17
|
-
/** Canvas `globalCompositeOperation` with the same maths, when there is one. */
|
|
18
|
-
canvas: GlobalCompositeOperation | null;
|
|
19
|
-
}
|
|
20
|
-
/** Every blend mode, in Photoshop's menu order. */
|
|
21
|
-
declare const BLEND_MODES: readonly BlendModeInfo[];
|
|
22
|
-
declare function isBlendMode(value: unknown): value is BlendMode;
|
|
23
|
-
/** A stored blend mode, or `normal` for a missing / unknown value. */
|
|
24
|
-
declare function normalizeBlendMode(value: unknown): BlendMode;
|
|
25
|
-
/**
|
|
26
|
-
* The canvas composite operation that implements `mode` exactly, or `null` when the canvas has
|
|
27
|
-
* none (draw through {@link blendImageData} instead).
|
|
28
|
-
*/
|
|
29
|
-
declare function canvasCompositeOperation(mode: BlendMode | undefined): GlobalCompositeOperation | null;
|
|
30
|
-
/** Whether a mode works on whole colours (hue, saturation, colour, luminosity, darker / lighter colour). */
|
|
31
|
-
declare function isSeparableBlendMode(mode: BlendMode): boolean;
|
|
32
|
-
/** Separable blend function `B(cb, cs)` of one channel. Non-separable modes return `cs`. */
|
|
33
|
-
declare function blendChannel(mode: BlendMode, cb: number, cs: number): number;
|
|
34
|
-
type Rgb$1 = [number, number, number];
|
|
35
|
-
type Rgba = [number, number, number, number];
|
|
36
|
-
/** Luminosity of the non-separable modes (W3C / ISO 32000 weights). */
|
|
37
|
-
declare function blendLum(c: readonly number[]): number;
|
|
38
|
-
/** `c` with its luminosity moved to `l`, clipped back into gamut towards grey (SetLum + ClipColor). */
|
|
39
|
-
declare function setLum(c: readonly number[], l: number): Rgb$1;
|
|
40
|
-
/** `B(Cb, Cs)` of a whole colour, including the non-separable modes. */
|
|
41
|
-
declare function blendRgb(mode: BlendMode, cb: readonly number[], cs: readonly number[]): Rgb$1;
|
|
42
|
-
/**
|
|
43
|
-
* Composites a straight-alpha `source` over a straight-alpha `backdrop` (both RGBA in 0..1) with a
|
|
44
|
-
* blend mode and an extra `alpha` (opacity), using the W3C general formula:
|
|
45
|
-
* `αo = αs + αb(1 − αs)`, `αo·Co = (1 − αs)·αb·Cb + (1 − αb)·αs·Cs + αs·αb·B(Cb, Cs)`.
|
|
46
|
-
*/
|
|
47
|
-
declare function blendPixel(mode: BlendMode, backdrop: readonly number[], source: readonly number[], alpha?: number): Rgba;
|
|
48
|
-
/**
|
|
49
|
-
* Blends `source` into `backdrop` in place (8-bit straight RGBA of the same size) with
|
|
50
|
-
* {@link blendPixel}. The scalar fallback for modes the canvas cannot composite.
|
|
51
|
-
*/
|
|
52
|
-
declare function blendImageData(backdrop: ImageData, source: ImageData, mode: BlendMode, alpha?: number): void;
|
|
53
|
-
|
|
54
12
|
/**
|
|
55
13
|
* A selection: one 8-bit coverage value per image pixel (0 = not selected, 255 = fully
|
|
56
14
|
* selected), row-major over the whole source image in natural pixels — the same space as the
|
|
@@ -139,551 +97,340 @@ declare function deserializeSelection(value: unknown): SelectionMask;
|
|
|
139
97
|
/** A short, stable hash of a string or bytes (FNV-1a, 32-bit, hex) for cache keys. */
|
|
140
98
|
declare function hashMaskContent(content: string | Uint8Array): string;
|
|
141
99
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
100
|
+
/**
|
|
101
|
+
* The image editor's layer stack: pixel, adjustment, group and annotation layers in one ordered
|
|
102
|
+
* tree (bottom to top), all in document space (natural pixels of the document).
|
|
103
|
+
*
|
|
104
|
+
* Layer objects are immutable. Every change builds new objects along the path from the root to
|
|
105
|
+
* the changed layer and shares everything else, so undo history, the compositor's caches and
|
|
106
|
+
* serialization can compare layers by identity.
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/** Blend modes of a layer; groups also accept `pass-through`. */
|
|
110
|
+
type LayerBlendMode = GroupBlendMode;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A layer mask (see the raster module's `RasterMask`) whose parametric `source` is a depth map:
|
|
114
|
+
* a depth mask is generated from it instead of painted, and its surface is unused.
|
|
115
|
+
*/
|
|
116
|
+
type RasterMask = RasterMask$1<DepthMaskOptions>;
|
|
117
|
+
interface LayerBase extends RasterLayerBase {
|
|
118
|
+
mask?: RasterMask;
|
|
161
119
|
}
|
|
162
|
-
|
|
120
|
+
/** The base sliders of the old document-level adjustments, as a filter on one layer. */
|
|
121
|
+
interface DevelopSettings {
|
|
163
122
|
brightness: number;
|
|
164
123
|
contrast: number;
|
|
165
124
|
saturation: number;
|
|
166
125
|
exposure: number;
|
|
167
126
|
temperature: number;
|
|
168
|
-
/**
|
|
169
|
-
* -100 (green) to 100 (magenta), 0 is default. White-balance tint correction in Duv × 3000
|
|
170
|
-
* (process 2 only; the legacy process ignores it).
|
|
171
|
-
*/
|
|
172
127
|
tint?: number;
|
|
173
|
-
|
|
174
|
-
opacity: number;
|
|
175
|
-
/**
|
|
176
|
-
* Rendering process the values are interpreted by. `2` (the latest; new edits and Reset get
|
|
177
|
-
* it): linear-light exposure, Bradford white balance, LUT tone curve without intermediate
|
|
178
|
-
* clipping. `1` or missing: the legacy 8-bit rendering, so edits saved before process
|
|
179
|
-
* versions existed look exactly as they did. See `normalizeProcessVersion`.
|
|
180
|
-
*/
|
|
128
|
+
/** Rendering process (see `ImageAdjustments.process`). */
|
|
181
129
|
process?: 1 | 2;
|
|
182
|
-
/**
|
|
183
|
-
* Non-destructive adjustment layers, evaluated bottom (first) to top (last) after the base
|
|
184
|
-
* adjustments above, on the encoded sRGB result. Missing or empty: no layers (edits saved
|
|
185
|
-
* before layers existed render exactly as before).
|
|
186
|
-
*/
|
|
187
|
-
layers?: AdjustmentLayer[];
|
|
188
|
-
}
|
|
189
|
-
type AdjustmentKind = 'curves' | 'levels' | 'hueSaturation' | 'vibrance' | 'colorBalance' | 'blackWhite' | 'invert' | 'posterize' | 'threshold' | 'photoFilter';
|
|
190
|
-
/** A Curves point; `input` and `output` are levels, 0..255. */
|
|
191
|
-
interface CurvePoint {
|
|
192
|
-
input: number;
|
|
193
|
-
output: number;
|
|
194
|
-
}
|
|
195
|
-
/** Curves: each channel's curve first, then the master (composite) curve, as in Photoshop. */
|
|
196
|
-
interface CurvesParams {
|
|
197
|
-
master: CurvePoint[];
|
|
198
|
-
red: CurvePoint[];
|
|
199
|
-
green: CurvePoint[];
|
|
200
|
-
blue: CurvePoint[];
|
|
201
|
-
}
|
|
202
|
-
/** One Levels record. Black / white points are levels (0..255); `gamma` is the midtone slider (0.1..9.99). */
|
|
203
|
-
interface LevelsChannel {
|
|
204
|
-
inBlack: number;
|
|
205
|
-
inWhite: number;
|
|
206
|
-
gamma: number;
|
|
207
|
-
outBlack: number;
|
|
208
|
-
outWhite: number;
|
|
209
|
-
}
|
|
210
|
-
/** Levels: each channel's record first, then the master record, as in Photoshop. */
|
|
211
|
-
interface LevelsParams {
|
|
212
|
-
master: LevelsChannel;
|
|
213
|
-
red: LevelsChannel;
|
|
214
|
-
green: LevelsChannel;
|
|
215
|
-
blue: LevelsChannel;
|
|
216
|
-
}
|
|
217
|
-
/** One of Hue/Saturation's six colour ranges (reds, yellows, greens, cyans, blues, magentas). */
|
|
218
|
-
interface HueRange {
|
|
219
|
-
/** Hue shift in degrees (-180..180). */
|
|
220
|
-
hue: number;
|
|
221
|
-
/** Saturation change in percent (-100..100). */
|
|
222
|
-
saturation: number;
|
|
223
|
-
/** Lightness change in percent (-100..100). */
|
|
224
|
-
lightness: number;
|
|
225
|
-
/** Hue degrees where the range starts fading in, is fully on, starts fading out and ends (may wrap). */
|
|
226
|
-
bounds: [number, number, number, number];
|
|
227
|
-
}
|
|
228
|
-
interface HueSaturationParams {
|
|
229
|
-
/** Master hue shift in degrees (-180..180), or the hue when colorizing (0..360). */
|
|
230
|
-
hue: number;
|
|
231
|
-
/** Percent, -100..100 (0..100 when colorizing). */
|
|
232
|
-
saturation: number;
|
|
233
|
-
/** Percent, -100..100. */
|
|
234
|
-
lightness: number;
|
|
235
|
-
colorize: boolean;
|
|
236
|
-
/** Six ranges: reds, yellows, greens, cyans, blues, magentas. */
|
|
237
|
-
ranges: HueRange[];
|
|
238
|
-
}
|
|
239
|
-
interface VibranceParams {
|
|
240
|
-
/** -100..100 */
|
|
241
|
-
vibrance: number;
|
|
242
|
-
/** -100..100 */
|
|
243
|
-
saturation: number;
|
|
244
|
-
}
|
|
245
|
-
/** Cyan–red, magenta–green, yellow–blue sliders, -100..100 each. */
|
|
246
|
-
type ColorBalanceTone = [number, number, number];
|
|
247
|
-
interface ColorBalanceParams {
|
|
248
|
-
shadows: ColorBalanceTone;
|
|
249
|
-
midtones: ColorBalanceTone;
|
|
250
|
-
highlights: ColorBalanceTone;
|
|
251
|
-
preserveLuminosity: boolean;
|
|
252
|
-
}
|
|
253
|
-
/** Black & White: percent weights of the six colours (Photoshop defaults 40 60 40 60 20 80). */
|
|
254
|
-
interface BlackWhiteParams {
|
|
255
|
-
reds: number;
|
|
256
|
-
yellows: number;
|
|
257
|
-
greens: number;
|
|
258
|
-
cyans: number;
|
|
259
|
-
blues: number;
|
|
260
|
-
magentas: number;
|
|
261
|
-
/** Tint colour (`#rrggbb`), applied like the Color blend mode, or `null` for none. */
|
|
262
|
-
tint: string | null;
|
|
263
|
-
}
|
|
264
|
-
interface PhotoFilterParams {
|
|
265
|
-
/** Filter colour, `#rrggbb`. */
|
|
266
|
-
color: string;
|
|
267
|
-
/** Percent, 0..100. */
|
|
268
|
-
density: number;
|
|
269
|
-
preserveLuminosity: boolean;
|
|
270
|
-
}
|
|
271
|
-
interface PosterizeParams {
|
|
272
|
-
/** 2..255 */
|
|
273
|
-
levels: number;
|
|
274
|
-
}
|
|
275
|
-
interface ThresholdParams {
|
|
276
|
-
/** 1..255: luma at or above it becomes white. */
|
|
277
|
-
level: number;
|
|
278
|
-
}
|
|
279
|
-
type InvertParams = Record<string, never>;
|
|
280
|
-
interface AdjustmentParamsMap {
|
|
281
|
-
curves: CurvesParams;
|
|
282
|
-
levels: LevelsParams;
|
|
283
|
-
hueSaturation: HueSaturationParams;
|
|
284
|
-
vibrance: VibranceParams;
|
|
285
|
-
colorBalance: ColorBalanceParams;
|
|
286
|
-
blackWhite: BlackWhiteParams;
|
|
287
|
-
invert: InvertParams;
|
|
288
|
-
posterize: PosterizeParams;
|
|
289
|
-
threshold: ThresholdParams;
|
|
290
|
-
photoFilter: PhotoFilterParams;
|
|
291
130
|
}
|
|
292
|
-
|
|
131
|
+
type DevelopFilter = {
|
|
293
132
|
id: string;
|
|
294
|
-
|
|
295
|
-
name?: string;
|
|
133
|
+
kind: 'develop';
|
|
296
134
|
enabled: boolean;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
135
|
+
} & DevelopSettings;
|
|
136
|
+
/** Box blur of `radius` pixels (the old `adjustments.blur`), clamped at the canvas edges. */
|
|
137
|
+
interface BlurFilter {
|
|
138
|
+
id: string;
|
|
139
|
+
kind: 'blur';
|
|
140
|
+
enabled: boolean;
|
|
141
|
+
radius: number;
|
|
142
|
+
}
|
|
143
|
+
type LayerFilter = DevelopFilter | BlurFilter;
|
|
144
|
+
type LayerFilterKind = LayerFilter['kind'];
|
|
145
|
+
interface PixelLayer extends LayerBase, Omit<RasterPixelLayer, keyof RasterLayerBase> {
|
|
146
|
+
/** Live filters, applied bottom (first) to top before the mask and blend. */
|
|
147
|
+
filters?: LayerFilter[];
|
|
301
148
|
/**
|
|
302
|
-
*
|
|
303
|
-
*
|
|
149
|
+
* `'document'`: the pixels are the document's source image, unmodified (the Background of an
|
|
150
|
+
* opened image). Such a layer's `surface` is a placeholder; read its pixels through the
|
|
151
|
+
* controller. Painting it drops the flag.
|
|
304
152
|
*/
|
|
305
|
-
|
|
153
|
+
source?: 'document';
|
|
306
154
|
}
|
|
155
|
+
type AdjustmentLayerNode<K extends AdjustmentKind = AdjustmentKind> = {
|
|
156
|
+
[P in K]: LayerBase & {
|
|
157
|
+
type: 'adjustment';
|
|
158
|
+
kind: P;
|
|
159
|
+
params: AdjustmentParamsMap[P];
|
|
160
|
+
};
|
|
161
|
+
}[K];
|
|
162
|
+
interface GroupLayer extends Omit<LayerBase, 'blend'> {
|
|
163
|
+
type: 'group';
|
|
164
|
+
blend: LayerBlendMode;
|
|
165
|
+
/** Bottom to top. */
|
|
166
|
+
children: ImageLayer[];
|
|
167
|
+
/** UI only. */
|
|
168
|
+
collapsed?: boolean;
|
|
169
|
+
}
|
|
170
|
+
/** One annotation (pen, shape, arrow, text, image) as a layer, drawn by the annotation renderer. */
|
|
171
|
+
interface AnnotationLayer extends LayerBase {
|
|
172
|
+
type: 'annotation';
|
|
173
|
+
annotation: Annotation;
|
|
174
|
+
}
|
|
175
|
+
type ImageLayer = PixelLayer | AdjustmentLayerNode | GroupLayer | AnnotationLayer;
|
|
176
|
+
type ImageLayerType = ImageLayer['type'];
|
|
177
|
+
/** Which part of the active layer painting targets. */
|
|
178
|
+
type LayerTarget = 'pixels' | 'mask';
|
|
179
|
+
/** A fresh id with `prefix` (`layer`, `flt`, …). */
|
|
180
|
+
declare function newLayerId(prefix?: string): string;
|
|
181
|
+
type LayerLocation = LayerLocation$1<ImageLayer>;
|
|
182
|
+
|
|
183
|
+
/** The top-level and nested pixel layers. */
|
|
184
|
+
declare function pixelLayers(layers: readonly ImageLayer[]): PixelLayer[];
|
|
185
|
+
/** The develop filter of a pixel layer, if any. */
|
|
186
|
+
declare function developFilter(layer: PixelLayer): DevelopFilter | undefined;
|
|
187
|
+
declare function blurFilter(layer: PixelLayer): BlurFilter | undefined;
|
|
188
|
+
/** True for filters that change pixels (enabled, non-neutral). */
|
|
189
|
+
declare function isActiveFilter(f: LayerFilter): boolean;
|
|
190
|
+
/** True when a filter needs neighbouring pixels (it can't run tile by tile). */
|
|
191
|
+
declare function isSpatialFilter(f: LayerFilter): boolean;
|
|
192
|
+
/** Document-space bounds of a pixel layer's stored tiles, or `null`. */
|
|
193
|
+
declare function pixelLayerBounds(layer: PixelLayer, surface?: PixelSurface): CropBox | null;
|
|
194
|
+
/** Human label of a layer kind. */
|
|
195
|
+
declare function layerTypeLabel(type: ImageLayerType): string;
|
|
196
|
+
|
|
307
197
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
198
|
+
* Schema version 3 of the image editor document: the layer tree, with pixel layers and painted
|
|
199
|
+
* masks stored as PNG assets (cropped to their content and placed by position), plus the
|
|
200
|
+
* document-level crop, transform, output opacity, migrated blur and selection.
|
|
201
|
+
*
|
|
202
|
+
* Encoding is synchronous and exact (see `png.ts`). Each surface's encoding is memoised, so
|
|
203
|
+
* saving an unchanged layer again costs nothing.
|
|
310
204
|
*/
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
205
|
+
|
|
206
|
+
declare const LAYERED_SCHEMA_VERSION: 3;
|
|
207
|
+
/** A stored raster mask. Pixels: `asset` (grey PNG) placed at `x`, `y`; elsewhere `defaultValue`. */
|
|
208
|
+
interface SerializedRasterMask {
|
|
209
|
+
defaultValue: 0 | 255;
|
|
210
|
+
asset?: string;
|
|
211
|
+
x?: number;
|
|
212
|
+
y?: number;
|
|
317
213
|
density?: number;
|
|
318
|
-
/** Gaussian σ in pixels (missing = 0). */
|
|
319
214
|
feather?: number;
|
|
320
|
-
/** `false` keeps the mask but ignores it. */
|
|
321
215
|
enabled?: boolean;
|
|
216
|
+
source?: DepthMaskOptions;
|
|
322
217
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
218
|
+
interface SerializedLayerBase {
|
|
219
|
+
id: string;
|
|
220
|
+
name: string;
|
|
221
|
+
visible: boolean;
|
|
222
|
+
opacity: number;
|
|
223
|
+
blend: string;
|
|
224
|
+
clipped?: boolean;
|
|
225
|
+
mask?: SerializedRasterMask;
|
|
226
|
+
locks?: LayerLocks;
|
|
227
|
+
}
|
|
228
|
+
interface SerializedPixelLayer extends SerializedLayerBase {
|
|
229
|
+
type: 'pixel';
|
|
230
|
+
/** Asset id of the pixels (RGBA PNG) placed at `x`, `y` in layer space; missing when empty. */
|
|
231
|
+
asset?: string;
|
|
232
|
+
x?: number;
|
|
233
|
+
y?: number;
|
|
234
|
+
offset: {
|
|
235
|
+
x: number;
|
|
236
|
+
y: number;
|
|
328
237
|
};
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
238
|
+
fillOpacity?: number;
|
|
239
|
+
filters?: LayerFilter[];
|
|
240
|
+
/** `'document'`: the pixels are the document's source image (no asset is stored). */
|
|
241
|
+
source?: 'document';
|
|
242
|
+
}
|
|
243
|
+
interface SerializedAdjustmentLayer extends SerializedLayerBase {
|
|
244
|
+
type: 'adjustment';
|
|
245
|
+
kind: string;
|
|
246
|
+
params: unknown;
|
|
247
|
+
}
|
|
248
|
+
interface SerializedGroupLayer extends SerializedLayerBase {
|
|
249
|
+
type: 'group';
|
|
250
|
+
children: SerializedLayer[];
|
|
251
|
+
collapsed?: boolean;
|
|
252
|
+
}
|
|
253
|
+
interface SerializedAnnotationLayer extends SerializedLayerBase {
|
|
254
|
+
type: 'annotation';
|
|
255
|
+
annotation: Annotation;
|
|
256
|
+
}
|
|
257
|
+
type SerializedLayer = SerializedPixelLayer | SerializedAdjustmentLayer | SerializedGroupLayer | SerializedAnnotationLayer;
|
|
258
|
+
/** A version 3 document (layers). */
|
|
259
|
+
interface SerializedLayeredImageEditorState {
|
|
260
|
+
version: 3;
|
|
261
|
+
/** Canvas size in pixels. */
|
|
262
|
+
width: number;
|
|
263
|
+
height: number;
|
|
264
|
+
/** Bottom to top. */
|
|
265
|
+
layers: SerializedLayer[];
|
|
266
|
+
/** Asset id → PNG data URL (or an external reference, see `ImageEditorAssetStore`). */
|
|
267
|
+
assets: Record<string, string>;
|
|
268
|
+
activeLayerId: string | null;
|
|
269
|
+
crop: CropBox | null;
|
|
270
|
+
transform: ImageTransform;
|
|
271
|
+
/** Export alpha, 0..1. */
|
|
272
|
+
opacity: number;
|
|
273
|
+
/** Blur migrated from a v1 / v2 document with adjustment layers (runs after the layers). */
|
|
274
|
+
legacyOutputBlur?: number;
|
|
275
|
+
selection?: SerializedSelection;
|
|
340
276
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
id: string;
|
|
344
|
-
type: AnnotationType;
|
|
277
|
+
interface EncodedSurface {
|
|
278
|
+
url: string;
|
|
345
279
|
x: number;
|
|
346
280
|
y: number;
|
|
347
|
-
rotation?: number;
|
|
348
|
-
opacity?: number;
|
|
349
|
-
/** Blend mode the annotation is drawn with (default `normal`). */
|
|
350
|
-
blend?: BlendMode;
|
|
351
281
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
282
|
+
/** The surface's content (non-default pixels) as a PNG data URL and its position, or `null`. */
|
|
283
|
+
declare function encodeSurface(surface: TiledSurface): EncodedSurface | null;
|
|
284
|
+
interface SerializeContext {
|
|
285
|
+
/** Adds an asset and returns its id. */
|
|
286
|
+
addAsset(url: string, hint: string): string;
|
|
287
|
+
}
|
|
288
|
+
declare function serializeLayer(layer: ImageLayer, ctx: SerializeContext): SerializedLayer;
|
|
289
|
+
/** Serializes a layer tree with inline assets (asset ids are derived from layer ids). */
|
|
290
|
+
declare function serializeLayers(layers: readonly ImageLayer[]): {
|
|
291
|
+
layers: SerializedLayer[];
|
|
292
|
+
assets: Record<string, string>;
|
|
293
|
+
};
|
|
294
|
+
interface DeserializeContext {
|
|
295
|
+
assets: Record<string, string>;
|
|
296
|
+
/** Decodes an asset (PNG data URL by default). Throw for an unusable asset. */
|
|
297
|
+
decodeAsset?(ref: string, channels: 1 | 4): {
|
|
298
|
+
width: number;
|
|
299
|
+
height: number;
|
|
300
|
+
data: ArrayLike<number>;
|
|
301
|
+
};
|
|
302
|
+
/** Problems found while reading (unknown kinds, broken assets); the rest still loads. */
|
|
303
|
+
problems: string[];
|
|
357
304
|
}
|
|
358
|
-
|
|
359
|
-
|
|
305
|
+
/** Decodes a PNG data URL into pixels of `channels` bytes each. */
|
|
306
|
+
declare function decodePngDataUrl(url: string, channels: 1 | 4): {
|
|
360
307
|
width: number;
|
|
361
308
|
height: number;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
309
|
+
data: Uint8ClampedArray;
|
|
310
|
+
};
|
|
311
|
+
declare function deserializeLayer(raw: unknown, ctx: DeserializeContext): ImageLayer | null;
|
|
312
|
+
/** Reads a stored layer tree (layers that cannot be read are dropped and reported). */
|
|
313
|
+
declare function deserializeLayers(raw: unknown, ctx: DeserializeContext): ImageLayer[];
|
|
314
|
+
|
|
315
|
+
/** Display bins of a histogram. */
|
|
316
|
+
declare const HISTOGRAM_BINS = 256;
|
|
317
|
+
interface ImageHistogram {
|
|
318
|
+
/** 256-bin counts per channel. */
|
|
319
|
+
red: Uint32Array;
|
|
320
|
+
green: Uint32Array;
|
|
321
|
+
blue: Uint32Array;
|
|
322
|
+
/** 256-bin counts of Rec.709 luma `round(0.2126 R + 0.7152 G + 0.0722 B)` of the encoded values. */
|
|
323
|
+
luminance: Uint32Array;
|
|
324
|
+
/** Visible pixels counted (alpha > 0). Each counts once, partially transparent ones included. */
|
|
325
|
+
samples: number;
|
|
326
|
+
/** Fully transparent pixels, excluded from every bin. */
|
|
327
|
+
transparent: number;
|
|
328
|
+
/** Per channel (R, G, B): visible pixels at exactly 0. */
|
|
329
|
+
shadows: [number, number, number];
|
|
330
|
+
/** Per channel (R, G, B): visible pixels at exactly 255. */
|
|
331
|
+
highlights: [number, number, number];
|
|
332
|
+
/** Largest bin count over R, G, B and luminance (for scaling a plot). */
|
|
333
|
+
max: number;
|
|
366
334
|
}
|
|
367
|
-
interface
|
|
368
|
-
|
|
369
|
-
radiusX: number;
|
|
370
|
-
radiusY: number;
|
|
371
|
-
strokeColor: string;
|
|
372
|
-
strokeWidth: number;
|
|
373
|
-
fillColor?: string;
|
|
374
|
-
}
|
|
375
|
-
interface ArrowAnnotation extends BaseAnnotation {
|
|
376
|
-
type: 'arrow';
|
|
377
|
-
endX: number;
|
|
378
|
-
endY: number;
|
|
379
|
-
strokeColor: string;
|
|
380
|
-
strokeWidth: number;
|
|
381
|
-
}
|
|
382
|
-
interface LineAnnotation extends BaseAnnotation {
|
|
383
|
-
type: 'line';
|
|
384
|
-
endX: number;
|
|
385
|
-
endY: number;
|
|
386
|
-
strokeColor: string;
|
|
387
|
-
strokeWidth: number;
|
|
388
|
-
}
|
|
389
|
-
interface TextAnnotation extends BaseAnnotation {
|
|
390
|
-
type: 'text';
|
|
391
|
-
text: string;
|
|
392
|
-
fontSize: number;
|
|
393
|
-
fontFamily?: string;
|
|
394
|
-
color: string;
|
|
395
|
-
fontWeight?: string | number;
|
|
396
|
-
}
|
|
397
|
-
interface ImageAnnotation extends BaseAnnotation {
|
|
398
|
-
type: 'image';
|
|
399
|
-
src: string;
|
|
400
|
-
width: number;
|
|
401
|
-
height: number;
|
|
402
|
-
}
|
|
403
|
-
type Annotation = PenAnnotation | RectAnnotation | CircleAnnotation | ArrowAnnotation | LineAnnotation | TextAnnotation | ImageAnnotation;
|
|
404
|
-
type CreateAnnotationPayload = Omit<PenAnnotation, 'id'> | Omit<RectAnnotation, 'id'> | Omit<CircleAnnotation, 'id'> | Omit<ArrowAnnotation, 'id'> | Omit<LineAnnotation, 'id'> | Omit<TextAnnotation, 'id'> | Omit<ImageAnnotation, 'id'>;
|
|
405
|
-
type ImageEditorTool = 'select' | 'crop' | 'pen' | 'rect' | 'circle' | 'arrow' | 'line' | 'text' | 'watermark';
|
|
406
|
-
interface ImageEditorState {
|
|
407
|
-
sourceUrl: string | null;
|
|
408
|
-
imageDimensions: ImageDimensions;
|
|
409
|
-
crop: CropBox | null;
|
|
410
|
-
transform: ImageTransform;
|
|
411
|
-
adjustments: ImageAdjustments;
|
|
412
|
-
depthMask: DepthMaskOptions;
|
|
413
|
-
annotations: Annotation[];
|
|
414
|
-
selectedAnnotationId: string | null;
|
|
415
|
-
activeTool: ImageEditorTool;
|
|
416
|
-
zoom: number;
|
|
417
|
-
pan: ImagePoint;
|
|
418
|
-
isOriginalCompared: boolean;
|
|
419
|
-
/**
|
|
420
|
-
* The active selection (8-bit coverage over the source image), or null/missing when nothing is
|
|
421
|
-
* selected. Recorded in undo history and saved as `selection` in `toJSON()`.
|
|
422
|
-
*/
|
|
423
|
-
selection?: SelectionMask | null;
|
|
424
|
-
/** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
|
|
425
|
-
quickMask?: boolean;
|
|
426
|
-
}
|
|
427
|
-
interface SerializedImageEditorState {
|
|
428
|
-
/**
|
|
429
|
-
* Schema version. `2` adds `adjustments.layers`; states without layers are still written as
|
|
430
|
-
* `1` so they round-trip unchanged. See `migrateSerializedImageEditorState`.
|
|
431
|
-
*/
|
|
432
|
-
version: 1 | 2;
|
|
433
|
-
crop: CropBox | null;
|
|
434
|
-
transform: ImageTransform;
|
|
435
|
-
adjustments: ImageAdjustments;
|
|
436
|
-
depthMask: DepthMaskOptions;
|
|
437
|
-
annotations: Annotation[];
|
|
438
|
-
/** The active selection, run-length encoded. Missing when nothing is selected. */
|
|
439
|
-
selection?: SerializedSelection;
|
|
440
|
-
}
|
|
441
|
-
interface ExportOptions {
|
|
442
|
-
format?: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
443
|
-
quality?: number;
|
|
335
|
+
interface PixelSource {
|
|
336
|
+
data: ArrayLike<number>;
|
|
444
337
|
width?: number;
|
|
445
338
|
height?: number;
|
|
446
|
-
includeAnnotations?: boolean;
|
|
447
|
-
}
|
|
448
|
-
interface ImageEditorOptions {
|
|
449
|
-
image?: string | HTMLImageElement;
|
|
450
|
-
initialState?: Partial<SerializedImageEditorState>;
|
|
451
|
-
onStateChange?: (state: ImageEditorState) => void;
|
|
452
|
-
maxHistoryDepth?: number;
|
|
453
339
|
}
|
|
454
|
-
interface InpaintOptions {
|
|
455
|
-
prompt: string;
|
|
456
|
-
imageDataUrl: string;
|
|
457
|
-
maskDataUrl?: string;
|
|
458
|
-
cropBox?: CropBox | null;
|
|
459
|
-
}
|
|
460
|
-
interface RemoveBackgroundOptions {
|
|
461
|
-
imageDataUrl: string;
|
|
462
|
-
}
|
|
463
|
-
type InpaintHook = (options: InpaintOptions) => Promise<string | void> | string | void;
|
|
464
|
-
type RemoveBackgroundHook = (options: RemoveBackgroundOptions) => Promise<string | void> | string | void;
|
|
465
|
-
interface ImageEditorAIHooks {
|
|
466
|
-
onInpaint?: InpaintHook;
|
|
467
|
-
onRemoveBackground?: RemoveBackgroundHook;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
340
|
/**
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
* `adjustments.process` selects the rendering: `2` is the linear-light pipeline
|
|
475
|
-
* ({@link applyProcess2Adjustments}); anything else (including a missing value, as in edits saved
|
|
476
|
-
* before process versions existed) is the frozen legacy rendering ({@link applyLegacyAdjustments}).
|
|
477
|
-
*/
|
|
478
|
-
declare function applyAdjustments(imageData: ImageData, adjustments: ImageAdjustments, options?: {
|
|
479
|
-
layerMasks?: ReadonlyMap<string, ArrayLike<number>>;
|
|
480
|
-
}): void;
|
|
481
|
-
/**
|
|
482
|
-
* Process 1: the original 8-bit gamma-space rendering, clamping after every step. Frozen so
|
|
483
|
-
* that edits saved without a `process` look exactly as they always have. `tint` is ignored.
|
|
484
|
-
*/
|
|
485
|
-
declare function applyLegacyAdjustments(imageData: ImageData, adjustments: ImageAdjustments): void;
|
|
486
|
-
/**
|
|
487
|
-
* Process 2: decode sRGB to linear float once; apply exposure (gain) and white balance (a
|
|
488
|
-
* Bradford matrix relative to as-shot) in linear light; a per-channel tone LUT for the
|
|
489
|
-
* highlight shoulder, contrast and brightness; luminance-preserving saturation in linear light;
|
|
490
|
-
* then encode back to sRGB through a LUT. Nothing is clamped between stages, only at the final
|
|
491
|
-
* encode. Neutral settings are the identity.
|
|
492
|
-
*/
|
|
493
|
-
declare function applyProcess2Adjustments(imageData: ImageData, adjustments: ImageAdjustments): void;
|
|
494
|
-
/**
|
|
495
|
-
* Blends a depth/alpha mask into the main image data based on Gleamforge depth masking.
|
|
496
|
-
* Supports threshold range with softness gradation, brightness mode, and optional inversion.
|
|
341
|
+
* Per-channel and luminance histograms of straight 8-bit RGBA pixels (an `ImageData` or anything
|
|
342
|
+
* with `data`), with clipping counts at the exact endpoints. Transparent pixels cannot add
|
|
343
|
+
* phantom peaks: they are counted separately and excluded.
|
|
497
344
|
*/
|
|
498
|
-
declare function
|
|
345
|
+
declare function computeHistogram(imageData: PixelSource): ImageHistogram;
|
|
346
|
+
type HistogramChannel = 'red' | 'green' | 'blue' | 'luminance';
|
|
499
347
|
/**
|
|
500
|
-
*
|
|
501
|
-
*
|
|
348
|
+
* An SVG path (`M … Z`) of one channel scaled into a `width` × `height` box, bins left to right,
|
|
349
|
+
* counts up from the bottom. `scale: 'sqrt'` (default) keeps small populations visible.
|
|
502
350
|
*/
|
|
503
|
-
declare function
|
|
351
|
+
declare function histogramPath(histogram: ImageHistogram, channel: HistogramChannel, width: number, height: number, options?: {
|
|
352
|
+
scale?: 'linear' | 'sqrt';
|
|
353
|
+
max?: number;
|
|
354
|
+
}): string;
|
|
504
355
|
|
|
505
356
|
/**
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
357
|
+
* The image editor's compositor: the raster engine (`@pixerate/editor/raster`) with the photo
|
|
358
|
+
* layer kinds plugged in. Adjustment layers filter what is below them (a run of adjacent ones is
|
|
359
|
+
* one float pass with one rounding at the end, exactly as `applyAdjustmentLayers` does, so a
|
|
360
|
+
* document migrated from adjustment layers renders identically); annotation layers are drawn by
|
|
361
|
+
* the host; pixel layers can carry develop and blur filters; masks can be depth masks.
|
|
509
362
|
*/
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
363
|
+
|
|
364
|
+
/** What the compositor needs from its host besides the layers. */
|
|
365
|
+
interface CompositorSources extends RasterSources {
|
|
366
|
+
/** The pixels of a pixel layer (resolves layers whose pixels are the document source). */
|
|
367
|
+
surfaceOf?(layer: PixelLayer): PixelSurface;
|
|
368
|
+
/**
|
|
369
|
+
* A parametric mask's depth map as RGBA at canvas size (the red channel is the depth), or
|
|
370
|
+
* `null` while it is unavailable (the mask then reveals everything).
|
|
371
|
+
*/
|
|
372
|
+
depthMap?(source: DepthMaskOptions): {
|
|
373
|
+
width: number;
|
|
374
|
+
height: number;
|
|
375
|
+
data: ArrayLike<number>;
|
|
376
|
+
} | null;
|
|
377
|
+
/** Draws one annotation into RGBA for `rect` (canvas hosts only); `null` when unavailable. */
|
|
378
|
+
rasterizeAnnotation?(annotation: Annotation, rect: CropBox): Uint8ClampedArray | null;
|
|
379
|
+
}
|
|
380
|
+
/** The `AdjustmentLayer` shape `applyAdjustmentLayers` evaluates, for a node (memoised). */
|
|
381
|
+
declare function adjustmentNodeAsLayer(node: AdjustmentLayerNode): AdjustmentLayer;
|
|
382
|
+
/** Evaluates a depth mask (see `applyDepthMask`) into one coverage byte per depth sample. */
|
|
383
|
+
declare function depthMaskAlpha(depth: number, options: DepthMaskOptions): number;
|
|
384
|
+
/** The per-tile compositor for image editor layer stacks (see the raster module for the caches). */
|
|
385
|
+
declare class LayerCompositor extends RasterCompositor<ImageLayer, CompositorSources> {
|
|
386
|
+
constructor(options?: CompositorOptions);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
interface RenderOptions {
|
|
390
|
+
viewportWidth?: number;
|
|
391
|
+
viewportHeight?: number;
|
|
392
|
+
showCropOverlay?: boolean;
|
|
393
|
+
showSelectionOverlay?: boolean;
|
|
394
|
+
interactive?: boolean;
|
|
395
|
+
draftAnnotation?: Annotation | null;
|
|
396
|
+
draftCrop?: CropBox | null;
|
|
397
|
+
/** Viewport fit mode: 'contain' scales to full viewport bounds; 'margin' scales to 85% with 1.0 cap (default). */
|
|
398
|
+
fit?: ImageEditorFit;
|
|
399
|
+
/**
|
|
400
|
+
* How the active selection is shown: marching ants (default when there is a selection),
|
|
401
|
+
* a Quick Mask tint over the unselected area (default when `state.quickMask`), or not at all.
|
|
402
|
+
*/
|
|
403
|
+
selectionDisplay?: 'ants' | 'quickMask' | 'none';
|
|
404
|
+
/** Dash offset of the marching ants in screen pixels (animate it to make them march). */
|
|
405
|
+
antsOffset?: number;
|
|
406
|
+
/** A selection being drawn (e.g. a lasso), shown as a dashed outline in natural pixels. */
|
|
407
|
+
draftSelectionPath?: ImagePoint[] | null;
|
|
408
|
+
/** Document rectangles that are the only change since the last render (strokes); recomposites only there. */
|
|
409
|
+
dirty?: CropBox[];
|
|
410
|
+
/** The layer being edited: tiles keep a checkpoint below it so strokes and drags on it start there. */
|
|
411
|
+
checkpointLayerId?: string | null;
|
|
412
|
+
/** The paint tools' cursor: a circle of `diameter` px at (`x`, `y`) in natural pixels. */
|
|
413
|
+
brushCursor?: {
|
|
414
|
+
x: number;
|
|
415
|
+
y: number;
|
|
416
|
+
diameter: number;
|
|
417
|
+
} | null;
|
|
514
418
|
}
|
|
515
|
-
/** A row-major 3×3 matrix (`[m00, m01, m02, m10, …, m22]`). */
|
|
516
|
-
type Matrix3 = [number, number, number, number, number, number, number, number, number];
|
|
517
|
-
/** The rendering of adjustments from before process versions existed. Frozen. */
|
|
518
|
-
declare const LEGACY_PROCESS_VERSION: 1;
|
|
519
|
-
/** The process new edits and Reset get. */
|
|
520
|
-
declare const LATEST_PROCESS_VERSION: 2;
|
|
521
|
-
type ImageProcessVersion = 1 | 2;
|
|
522
|
-
/**
|
|
523
|
-
* Reads a stored process number leniently: a missing or damaged value (not a whole number) is
|
|
524
|
-
* the legacy process, so a saved edit from before process versions renders exactly as it did. A
|
|
525
|
-
* whole number newer than this build knows renders with the latest process.
|
|
526
|
-
*/
|
|
527
|
-
declare function normalizeProcessVersion(value: unknown): ImageProcessVersion;
|
|
528
|
-
declare function srgbToLinear(v: number): number;
|
|
529
|
-
declare function linearToSrgb(v: number): number;
|
|
530
|
-
/** Rec.709 / sRGB luminance weights (linear light). */
|
|
531
|
-
declare const LUMA_709: readonly [number, number, number];
|
|
532
|
-
declare const IDENTITY_MATRIX3: Matrix3;
|
|
533
|
-
declare function mulMatrix3(a: Matrix3, b: Matrix3): Matrix3;
|
|
534
|
-
declare function applyMatrix3(m: Matrix3, v: readonly [number, number, number]): [number, number, number];
|
|
535
|
-
declare function invertMatrix3(m: Matrix3): Matrix3 | null;
|
|
536
|
-
declare const D65: Chromaticity;
|
|
537
|
-
/** Bradford chromatic adaptation (XYZ → XYZ) from white `src` to white `dst`. */
|
|
538
|
-
declare function bradfordAdaptation(src: Chromaticity, dst: Chromaticity): Matrix3;
|
|
539
|
-
/**
|
|
540
|
-
* Matrix (linear sRGB → linear sRGB) that white-balances a scene lit by `src` so that it
|
|
541
|
-
* renders as if lit by D65.
|
|
542
|
-
*/
|
|
543
|
-
declare function wbMatrix(src: Chromaticity): Matrix3;
|
|
544
|
-
/** The chromaticity of a linear sRGB colour. */
|
|
545
|
-
declare function linearSrgbToXy(rgb: readonly [number, number, number]): Chromaticity;
|
|
546
|
-
/** Tint units per unit of Duv. */
|
|
547
|
-
declare const TINT_SCALE = 3000;
|
|
548
|
-
declare const MIN_KELVIN = 1667;
|
|
549
|
-
declare const MAX_KELVIN = 25000;
|
|
550
|
-
/** CIE 1931 xy → CIE 1960 uv. */
|
|
551
|
-
declare function xyToUv(p: Chromaticity): [number, number];
|
|
552
|
-
/** CIE 1960 uv → CIE 1931 xy. */
|
|
553
|
-
declare function uvToXy(u: number, v: number): Chromaticity;
|
|
554
|
-
/**
|
|
555
|
-
* Source illuminant chromaticity for temperature `kelvin` and correction `tint`.
|
|
556
|
-
* Positive tint means a green source white, whose correction adds magenta to the image.
|
|
557
|
-
*/
|
|
558
|
-
declare function tempTintToXy(kelvin: number, tint: number): Chromaticity;
|
|
559
|
-
/** Inverse of {@link tempTintToXy}: nearest locus temperature (searched in mired space) and tint. */
|
|
560
|
-
declare function xyToTempTint(p: Chromaticity): {
|
|
561
|
-
kelvin: number;
|
|
562
|
-
tint: number;
|
|
563
|
-
};
|
|
564
|
-
/** Rendered images carry no as-shot white: "as shot" is 6500 K / tint 0 and maps to the identity. */
|
|
565
|
-
declare const AS_SHOT_KELVIN = 6500;
|
|
566
|
-
/** Mireds per unit of the `temperature` slider (−100…100). */
|
|
567
|
-
declare const MIRED_PER_TEMPERATURE_UNIT = 1;
|
|
568
|
-
/**
|
|
569
|
-
* Maps the `temperature` slider (−100 cool … +100 warm) to the Kelvin white-balance setting:
|
|
570
|
-
* one mired per unit around 6500 K, so 0 → 6500 K, +100 → ~18 570 K (a strong warming
|
|
571
|
-
* correction), −100 → ~3 940 K (a strong cooling correction). Mireds are perceptually even,
|
|
572
|
-
* so equal slider steps look like equal changes.
|
|
573
|
-
*/
|
|
574
|
-
declare function temperatureToKelvin(temperature: number): number;
|
|
575
|
-
/** Inverse of {@link temperatureToKelvin}. */
|
|
576
|
-
declare function kelvinToTemperature(kelvin: number): number;
|
|
577
419
|
/**
|
|
578
|
-
*
|
|
579
|
-
* "as shot": the identity at 0 / 0. Normalised so neutral luminance is preserved (white
|
|
580
|
-
* balance doesn't change exposure).
|
|
420
|
+
* Image Cache to avoid refetching HTMLImageElement objects repeatedly during re-renders.
|
|
581
421
|
*/
|
|
582
|
-
declare
|
|
422
|
+
declare class ImageCache {
|
|
423
|
+
private cache;
|
|
424
|
+
get(src: string): Promise<HTMLImageElement>;
|
|
425
|
+
set(src: string, img: HTMLImageElement): void;
|
|
426
|
+
/** The loaded image for `src`, or `undefined` while it is not loaded yet. */
|
|
427
|
+
peek(src: string): HTMLImageElement | undefined;
|
|
428
|
+
clear(): void;
|
|
429
|
+
}
|
|
430
|
+
declare const globalImageCache: ImageCache;
|
|
583
431
|
/**
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
* the slider range −100…100.
|
|
587
|
-
*/
|
|
588
|
-
declare function whiteBalanceFromSample(rgb: readonly [number, number, number] | {
|
|
589
|
-
r: number;
|
|
590
|
-
g: number;
|
|
591
|
-
b: number;
|
|
592
|
-
}): {
|
|
593
|
-
temperature: number;
|
|
594
|
-
tint: number;
|
|
595
|
-
};
|
|
596
|
-
/** Number of intervals in a tone LUT (the table has `TONE_LUT_SIZE + 1` entries). */
|
|
597
|
-
declare const TONE_LUT_SIZE = 4096;
|
|
598
|
-
/**
|
|
599
|
-
* The process 2 tone curve for one linear input value in `[0, headroom]`:
|
|
600
|
-
*
|
|
601
|
-
* 1. A highlight shoulder (extended Reinhard with white point `headroom`) above a knee of 0.6
|
|
602
|
-
* rolls values above 1 (after exposure / white balance) back into range instead of clipping.
|
|
603
|
-
* With no headroom (`headroom = 1`) it is exactly the identity.
|
|
604
|
-
* 2. In a gamma-2.2 perceptual domain, contrast is an S-curve anchored at 0, middle grey and 1
|
|
605
|
-
* (as `ToneMap::display`), and brightness a midtone lift anchored at 0 and 1.
|
|
606
|
-
*
|
|
607
|
-
* `contrast` and `brightness` are −100…100; both 0 with `headroom = 1` is the identity.
|
|
608
|
-
*/
|
|
609
|
-
declare function toneCurve(y: number, contrast: number, brightness: number, headroom?: number): number;
|
|
610
|
-
/** Tabulates {@link toneCurve} over `[0, headroom]` in {@link TONE_LUT_SIZE} steps. */
|
|
611
|
-
declare function buildToneLut(contrast: number, brightness: number, headroom?: number): Float32Array;
|
|
612
|
-
/** Linearly interpolated lookup into a LUT from {@link buildToneLut}. */
|
|
613
|
-
declare function sampleToneLut(lut: Float32Array, headroom: number, y: number): number;
|
|
614
|
-
|
|
615
|
-
/** Display bins of a histogram. */
|
|
616
|
-
declare const HISTOGRAM_BINS = 256;
|
|
617
|
-
interface ImageHistogram {
|
|
618
|
-
/** 256-bin counts per channel. */
|
|
619
|
-
red: Uint32Array;
|
|
620
|
-
green: Uint32Array;
|
|
621
|
-
blue: Uint32Array;
|
|
622
|
-
/** 256-bin counts of Rec.709 luma `round(0.2126 R + 0.7152 G + 0.0722 B)` of the encoded values. */
|
|
623
|
-
luminance: Uint32Array;
|
|
624
|
-
/** Visible pixels counted (alpha > 0). Each counts once, partially transparent ones included. */
|
|
625
|
-
samples: number;
|
|
626
|
-
/** Fully transparent pixels, excluded from every bin. */
|
|
627
|
-
transparent: number;
|
|
628
|
-
/** Per channel (R, G, B): visible pixels at exactly 0. */
|
|
629
|
-
shadows: [number, number, number];
|
|
630
|
-
/** Per channel (R, G, B): visible pixels at exactly 255. */
|
|
631
|
-
highlights: [number, number, number];
|
|
632
|
-
/** Largest bin count over R, G, B and luminance (for scaling a plot). */
|
|
633
|
-
max: number;
|
|
634
|
-
}
|
|
635
|
-
interface PixelSource {
|
|
636
|
-
data: ArrayLike<number>;
|
|
637
|
-
width?: number;
|
|
638
|
-
height?: number;
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Per-channel and luminance histograms of straight 8-bit RGBA pixels (an `ImageData` or anything
|
|
642
|
-
* with `data`), with clipping counts at the exact endpoints. Transparent pixels cannot add
|
|
643
|
-
* phantom peaks: they are counted separately and excluded.
|
|
644
|
-
*/
|
|
645
|
-
declare function computeHistogram(imageData: PixelSource): ImageHistogram;
|
|
646
|
-
type HistogramChannel = 'red' | 'green' | 'blue' | 'luminance';
|
|
647
|
-
/**
|
|
648
|
-
* An SVG path (`M … Z`) of one channel scaled into a `width` × `height` box, bins left to right,
|
|
649
|
-
* counts up from the bottom. `scale: 'sqrt'` (default) keeps small populations visible.
|
|
650
|
-
*/
|
|
651
|
-
declare function histogramPath(histogram: ImageHistogram, channel: HistogramChannel, width: number, height: number, options?: {
|
|
652
|
-
scale?: 'linear' | 'sqrt';
|
|
653
|
-
max?: number;
|
|
654
|
-
}): string;
|
|
655
|
-
|
|
656
|
-
interface RenderOptions {
|
|
657
|
-
viewportWidth?: number;
|
|
658
|
-
viewportHeight?: number;
|
|
659
|
-
showCropOverlay?: boolean;
|
|
660
|
-
showSelectionOverlay?: boolean;
|
|
661
|
-
interactive?: boolean;
|
|
662
|
-
draftAnnotation?: Annotation | null;
|
|
663
|
-
draftCrop?: CropBox | null;
|
|
664
|
-
/**
|
|
665
|
-
* How the active selection is shown: marching ants (default when there is a selection),
|
|
666
|
-
* a Quick Mask tint over the unselected area (default when `state.quickMask`), or not at all.
|
|
667
|
-
*/
|
|
668
|
-
selectionDisplay?: 'ants' | 'quickMask' | 'none';
|
|
669
|
-
/** Dash offset of the marching ants in screen pixels (animate it to make them march). */
|
|
670
|
-
antsOffset?: number;
|
|
671
|
-
/** A selection being drawn (e.g. a lasso), shown as a dashed outline in natural pixels. */
|
|
672
|
-
draftSelectionPath?: ImagePoint[] | null;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Image Cache to avoid refetching HTMLImageElement objects repeatedly during re-renders.
|
|
676
|
-
*/
|
|
677
|
-
declare class ImageCache {
|
|
678
|
-
private cache;
|
|
679
|
-
get(src: string): Promise<HTMLImageElement>;
|
|
680
|
-
set(src: string, img: HTMLImageElement): void;
|
|
681
|
-
clear(): void;
|
|
682
|
-
}
|
|
683
|
-
declare const globalImageCache: ImageCache;
|
|
684
|
-
/**
|
|
685
|
-
* Renders an image with all its transformations, filters, depth masks, and annotations
|
|
686
|
-
* to a target HTMLCanvasElement.
|
|
432
|
+
* Renders an image with all its transformations, filters, depth masks, and annotations
|
|
433
|
+
* to a target HTMLCanvasElement.
|
|
687
434
|
*/
|
|
688
435
|
declare class ImageEditorRenderer {
|
|
689
436
|
imageCache: ImageCache;
|
|
@@ -698,6 +445,28 @@ declare class ImageEditorRenderer {
|
|
|
698
445
|
onPreviewHistogram?: (histogram: ImageHistogram | null) => void;
|
|
699
446
|
private sourceIds;
|
|
700
447
|
private nextSourceId;
|
|
448
|
+
/**
|
|
449
|
+
* The viewport's compositor. It only ever composites the viewport's stack, so its tile cache can
|
|
450
|
+
* trust dirty rectangles; exports use `exportCompositor`.
|
|
451
|
+
*/
|
|
452
|
+
compositor: LayerCompositor;
|
|
453
|
+
private exportCompositor;
|
|
454
|
+
/** How the host resolves layer pixels (set by the controller). */
|
|
455
|
+
layerSources?: LayerSourcesHost;
|
|
456
|
+
/**
|
|
457
|
+
* Debug / test switch: `'legacy'` forces the old base path for documents that still have the
|
|
458
|
+
* v1 / v2 shape, `'layers'` forces the compositor. Default: chosen per document.
|
|
459
|
+
*/
|
|
460
|
+
baseRoute: 'auto' | 'legacy' | 'layers';
|
|
461
|
+
/** Which path the last base render took. */
|
|
462
|
+
lastBaseRoute: 'legacy' | 'layers' | null;
|
|
463
|
+
private comp;
|
|
464
|
+
private depthMaps;
|
|
465
|
+
private assetVersion;
|
|
466
|
+
private scratch;
|
|
467
|
+
private cachedPostCanvas;
|
|
468
|
+
private cachedPostKey;
|
|
469
|
+
private cachedPostHistogram;
|
|
701
470
|
/**
|
|
702
471
|
* Helper to create a canvas element safely in browser/JSDOM.
|
|
703
472
|
*/
|
|
@@ -711,6 +480,32 @@ declare class ImageEditorRenderer {
|
|
|
711
480
|
* and the depth mask (which receives the identical transform so it stays aligned).
|
|
712
481
|
*/
|
|
713
482
|
private renderBaseImage;
|
|
483
|
+
/** Which base path renders `state` (see `needsLegacyBase`). */
|
|
484
|
+
private chooseRoute;
|
|
485
|
+
/** Compositor sources for a `width × height` canvas: layer pixels, depth maps and annotation rasterizing. */
|
|
486
|
+
compositorSources(width: number, height: number): CompositorSources;
|
|
487
|
+
/** Loads what the compositor reads synchronously: depth maps (at canvas size) and annotation images. */
|
|
488
|
+
/** Loads depth maps and annotation images the compositor reads synchronously. */
|
|
489
|
+
prepareLayerAssets(layers: readonly ImageLayer[], width: number, height: number): Promise<void>;
|
|
490
|
+
/** Whether annotation layers can be rasterized here (a 2D canvas with pixel access). */
|
|
491
|
+
canRasterize(): boolean;
|
|
492
|
+
/** One annotation drawn into a tile-sized RGBA buffer at `rect` (document space), or `null` without a canvas. */
|
|
493
|
+
private rasterizeAnnotation;
|
|
494
|
+
private putTile;
|
|
495
|
+
/**
|
|
496
|
+
* Brings the viewport's composite canvas (document space, covering `region`) up to date,
|
|
497
|
+
* uploading only the tiles that changed since the last render.
|
|
498
|
+
*/
|
|
499
|
+
private updateComposite;
|
|
500
|
+
/**
|
|
501
|
+
* The base canvas of a layered document: the composite drawn through the base projection (crop,
|
|
502
|
+
* rotation, flips at scale 1), then output opacity and the migrated blur, which run in the output
|
|
503
|
+
* frame. Cached until the composite or those settings change.
|
|
504
|
+
*/
|
|
505
|
+
private layeredBase;
|
|
506
|
+
/** Output opacity then the migrated blur, in place on a base canvas; returns its histogram. */
|
|
507
|
+
private applyPost;
|
|
508
|
+
private publishHistogram;
|
|
714
509
|
private quickMaskCache;
|
|
715
510
|
private outlineCache;
|
|
716
511
|
/** Rubylith over the unselected area, drawn in natural image space. */
|
|
@@ -731,6 +526,8 @@ declare class ImageEditorRenderer {
|
|
|
731
526
|
*/
|
|
732
527
|
private drawAnnotationBlended;
|
|
733
528
|
private drawAnnotationContent;
|
|
529
|
+
/** Draws an annotation synchronously; an image annotation draws `img` (skipped when `null`). */
|
|
530
|
+
drawAnnotationShape(ctx: CanvasRenderingContext2D, ann: Annotation, img: CanvasImageSource | null): void;
|
|
734
531
|
/**
|
|
735
532
|
* Draws selection box around active annotation.
|
|
736
533
|
*/
|
|
@@ -764,6 +561,12 @@ declare class ImageEditorRenderer {
|
|
|
764
561
|
}): Promise<HTMLCanvasElement>;
|
|
765
562
|
private drawAnnotationMask;
|
|
766
563
|
}
|
|
564
|
+
/** What the renderer asks its host (the controller) about layer pixels. */
|
|
565
|
+
interface LayerSourcesHost {
|
|
566
|
+
surfaceOf(layer: PixelLayer): PixelSurface;
|
|
567
|
+
sourceIsOpaque(): boolean;
|
|
568
|
+
version(): string;
|
|
569
|
+
}
|
|
767
570
|
|
|
768
571
|
interface ShapeSelectionOptions {
|
|
769
572
|
/** Partial coverage along the edge (default true). */
|
|
@@ -866,16 +669,6 @@ declare function borderCoverage(m: ArrayLike<number>, w: number, h: number, r: n
|
|
|
866
669
|
* re-thresholded at ½ — specks drop, corners round, straight edges stay hard.
|
|
867
670
|
*/
|
|
868
671
|
declare function smoothCoverage(m: ArrayLike<number>, w: number, h: number, r: number): Float32Array;
|
|
869
|
-
/** Above this σ a Gaussian is approximated by three box passes (cost independent of σ). */
|
|
870
|
-
declare const DIRECT_GAUSSIAN_MAX_SIGMA = 8;
|
|
871
|
-
type Edge = 'zero' | 'clamp';
|
|
872
|
-
/**
|
|
873
|
-
* Separable Gaussian blur of a single-channel float image. `edge` `zero` treats pixels beyond
|
|
874
|
-
* the image as 0 (selection feather), `clamp` replicates the border (mask refinement). σ up to
|
|
875
|
-
* {@link DIRECT_GAUSSIAN_MAX_SIGMA} is convolved directly; wider blurs use three box passes, so
|
|
876
|
-
* the cost per pixel never grows with σ.
|
|
877
|
-
*/
|
|
878
|
-
declare function gaussianBlur(src: ArrayLike<number>, w: number, h: number, sigma: number, edge?: Edge): Float32Array;
|
|
879
672
|
/** Select › Modify › Feather: Gaussian blur with σ = radius (as Photoshop), zero beyond the image. */
|
|
880
673
|
declare function featherCoverage(m: ArrayLike<number>, w: number, h: number, radius: number): Float32Array;
|
|
881
674
|
/** Grey dilation (`grow`) or erosion with a square of radius `r`, separable, O(1) per pixel. */
|
|
@@ -1109,8 +902,90 @@ declare function projectMaskCoverage(coverage: Float32Array, maskWidth: number,
|
|
|
1109
902
|
*/
|
|
1110
903
|
declare function buildLayerMaskPlanes(layers: readonly AdjustmentLayer[] | undefined, naturalWidth: number, naturalHeight: number, projection: ImageProjection, targetWidth: number, targetHeight: number): Map<string, Float32Array> | undefined;
|
|
1111
904
|
|
|
1112
|
-
/**
|
|
1113
|
-
declare
|
|
905
|
+
/** A refused layer operation; the message says why and how to fix it. */
|
|
906
|
+
declare class LayerOperationError extends Error {
|
|
907
|
+
constructor(message: string);
|
|
908
|
+
}
|
|
909
|
+
/** Where a layer goes: above or below a layer (in its group), or at a position in a group. */
|
|
910
|
+
interface LayerPlacement {
|
|
911
|
+
/** Directly above this layer, in the same group. */
|
|
912
|
+
aboveId?: string;
|
|
913
|
+
/** Directly below this layer, in the same group. */
|
|
914
|
+
belowId?: string;
|
|
915
|
+
/** Inside this group (at `index`, default the top). */
|
|
916
|
+
parentId?: string;
|
|
917
|
+
/** Index in the parent's children (or the top level), 0 = bottom. */
|
|
918
|
+
index?: number;
|
|
919
|
+
}
|
|
920
|
+
/** The layer with `id`, or a `LayerOperationError` listing the ids that exist. */
|
|
921
|
+
declare function requireLayer(layers: readonly ImageLayer[], id: string): LayerLocation$1<ImageLayer>;
|
|
922
|
+
/** Refuses when the layer is locked for `what` (and always for `all`). */
|
|
923
|
+
declare function requireUnlocked(layer: ImageLayer, what: keyof LayerLocks, action: string): void;
|
|
924
|
+
/** Inserts `layer` at `placement` (default: the top level at `defaultIndex`, or the top). */
|
|
925
|
+
declare function placeLayer(layers: readonly ImageLayer[], layer: ImageLayer, placement?: LayerPlacement, defaultIndex?: number): ImageLayer[];
|
|
926
|
+
/** Removes a layer (refused when it is locked). */
|
|
927
|
+
declare function removeLayer(layers: readonly ImageLayer[], id: string): ImageLayer[];
|
|
928
|
+
/** Moves a layer to `placement`. A group cannot go inside itself. Returns the new stack. */
|
|
929
|
+
declare function moveLayer(layers: readonly ImageLayer[], id: string, placement: LayerPlacement): ImageLayer[];
|
|
930
|
+
/** Every id in a subtree gets a fresh one (for duplicates). */
|
|
931
|
+
declare function withNewIds<T extends ImageLayer>(layer: T): T;
|
|
932
|
+
/** Duplicates a layer (and its children) directly above it. Returns the stack and the copy's id. */
|
|
933
|
+
declare function duplicateLayer(layers: readonly ImageLayer[], id: string, name?: string): {
|
|
934
|
+
layers: ImageLayer[];
|
|
935
|
+
id: string;
|
|
936
|
+
};
|
|
937
|
+
/** Properties `setLayerProperties` changes. */
|
|
938
|
+
interface LayerProperties {
|
|
939
|
+
name?: string;
|
|
940
|
+
visible?: boolean;
|
|
941
|
+
/** 0..1 */
|
|
942
|
+
opacity?: number;
|
|
943
|
+
/** 0..1, pixel layers only. */
|
|
944
|
+
fillOpacity?: number;
|
|
945
|
+
blend?: LayerBlendMode;
|
|
946
|
+
clipped?: boolean;
|
|
947
|
+
locks?: LayerLocks;
|
|
948
|
+
/** Groups only (UI state). */
|
|
949
|
+
collapsed?: boolean;
|
|
950
|
+
}
|
|
951
|
+
/** Validates and applies property changes to one layer. */
|
|
952
|
+
declare function setLayerProperties(layers: readonly ImageLayer[], id: string, props: LayerProperties): ImageLayer[];
|
|
953
|
+
/**
|
|
954
|
+
* Puts layers (siblings in one group or the top level) into a new group at the position of the
|
|
955
|
+
* topmost one, keeping their order. Returns the stack and the group id.
|
|
956
|
+
*/
|
|
957
|
+
declare function groupLayers(layers: readonly ImageLayer[], ids: string[], name?: string): {
|
|
958
|
+
layers: ImageLayer[];
|
|
959
|
+
id: string;
|
|
960
|
+
};
|
|
961
|
+
/** Replaces a group by its children (the group's own opacity, blend and mask are dropped). */
|
|
962
|
+
declare function ungroupLayer(layers: readonly ImageLayer[], id: string): {
|
|
963
|
+
layers: ImageLayer[];
|
|
964
|
+
ids: string[];
|
|
965
|
+
};
|
|
966
|
+
/** Sets a pixel layer's offset (refused when its position is locked). */
|
|
967
|
+
declare function offsetLayer(layers: readonly ImageLayer[], id: string, offset: {
|
|
968
|
+
x: number;
|
|
969
|
+
y: number;
|
|
970
|
+
}): ImageLayer[];
|
|
971
|
+
/** Sets or removes (`null`) a layer's mask. */
|
|
972
|
+
declare function setLayerMask(layers: readonly ImageLayer[], id: string, mask: RasterMask | null): ImageLayer[];
|
|
973
|
+
/** A clean filter from loose input (for tools and the UI). */
|
|
974
|
+
declare function normalizeFilter(raw: Partial<LayerFilter> & {
|
|
975
|
+
kind: LayerFilter['kind'];
|
|
976
|
+
}, id?: string): LayerFilter;
|
|
977
|
+
/** Adds a filter on top of a pixel layer's filters. A layer has at most one filter of each kind. */
|
|
978
|
+
declare function addLayerFilter(layers: readonly ImageLayer[], id: string, filter: LayerFilter): ImageLayer[];
|
|
979
|
+
/** Changes one filter of a pixel layer (`changes` merged and validated). */
|
|
980
|
+
declare function updateLayerFilter(layers: readonly ImageLayer[], id: string, filterId: string, changes: Record<string, unknown>): ImageLayer[];
|
|
981
|
+
declare function removeLayerFilter(layers: readonly ImageLayer[], id: string, filterId: string): ImageLayer[];
|
|
982
|
+
/** A blend mode check for tools. */
|
|
983
|
+
declare function parseBlend(value: unknown, allowPassThrough?: boolean): BlendMode | 'pass-through' | undefined;
|
|
984
|
+
/** The union of two rectangles (either may be null). */
|
|
985
|
+
declare function unionRect(a: CropBox | null, b: CropBox | null): CropBox | null;
|
|
986
|
+
|
|
987
|
+
/** Latest serialized schema version (`3`: layers). Documents with the old shape still write 1 or 2. */
|
|
988
|
+
declare const IMAGE_EDITOR_SCHEMA_VERSION: 3;
|
|
1114
989
|
/** Changes to an adjustment layer; `params` is merged into the current parameters. */
|
|
1115
990
|
interface AdjustmentLayerUpdate<K extends AdjustmentKind = AdjustmentKind> {
|
|
1116
991
|
params?: Partial<AdjustmentParamsMap[K]>;
|
|
@@ -1135,10 +1010,113 @@ interface SampleOptions {
|
|
|
1135
1010
|
/** Pixels to use instead of reading the source image (natural size, RGBA). */
|
|
1136
1011
|
pixels?: PixelBuffer;
|
|
1137
1012
|
}
|
|
1138
|
-
/** A new adjustment layer: its kind plus optional initial values. */
|
|
1013
|
+
/** A new adjustment layer: its kind plus optional initial values and position. */
|
|
1139
1014
|
interface AdjustmentLayerInit<K extends AdjustmentKind = AdjustmentKind> extends AdjustmentLayerUpdate<K> {
|
|
1140
1015
|
kind: K;
|
|
1141
1016
|
id?: string;
|
|
1017
|
+
/** Put the new layer directly above this layer (in its group). */
|
|
1018
|
+
aboveId?: string;
|
|
1019
|
+
/** Put the new layer at the top of this group. */
|
|
1020
|
+
parentId?: string;
|
|
1021
|
+
}
|
|
1022
|
+
/** A new pixel layer: empty, a solid colour over the canvas, or given pixels, plus its properties and position. */
|
|
1023
|
+
interface PixelLayerInit extends LayerPlacement {
|
|
1024
|
+
id?: string;
|
|
1025
|
+
name?: string;
|
|
1026
|
+
/** Fill the canvas with this colour (`#rgb`, `#rrggbb`, `#rrggbbaa` or `[r, g, b, a?]` 0..255). */
|
|
1027
|
+
color?: string | number[];
|
|
1028
|
+
/** RGBA pixels placed at `x`, `y` (document pixels). */
|
|
1029
|
+
pixels?: PixelBuffer;
|
|
1030
|
+
x?: number;
|
|
1031
|
+
y?: number;
|
|
1032
|
+
visible?: boolean;
|
|
1033
|
+
/** 0..1 (default 1). */
|
|
1034
|
+
opacity?: number;
|
|
1035
|
+
fillOpacity?: number;
|
|
1036
|
+
blend?: BlendMode;
|
|
1037
|
+
}
|
|
1038
|
+
/** The paint tools' options (view state). */
|
|
1039
|
+
interface PaintOptions {
|
|
1040
|
+
brush: BrushSettings;
|
|
1041
|
+
/** `#rrggbb`: what the brush and Fill paint. */
|
|
1042
|
+
foreground: string;
|
|
1043
|
+
/** `#rrggbb`: what the eraser paints on transparency-locked layers and masks. */
|
|
1044
|
+
background: string;
|
|
1045
|
+
}
|
|
1046
|
+
/** A stroke: tool, target (default the active layer and target) and brush / colour overrides. */
|
|
1047
|
+
interface StrokeInit {
|
|
1048
|
+
tool?: 'brush' | 'eraser';
|
|
1049
|
+
layerId?: string;
|
|
1050
|
+
channel?: LayerTarget;
|
|
1051
|
+
/** Overrides of the paint options' brush. */
|
|
1052
|
+
brush?: Partial<BrushSettings>;
|
|
1053
|
+
/** Paint colour (default the foreground). Masks take its grey value. */
|
|
1054
|
+
color?: string | number[];
|
|
1055
|
+
/** Eraser colour on locked transparency / masks (default the background). */
|
|
1056
|
+
background?: string | number[];
|
|
1057
|
+
/** Kept with the stroke for replays (v1 brushes have no jitter). */
|
|
1058
|
+
seed?: number;
|
|
1059
|
+
}
|
|
1060
|
+
interface FillOptions {
|
|
1061
|
+
layerId?: string;
|
|
1062
|
+
channel?: LayerTarget;
|
|
1063
|
+
/** Default the foreground colour. */
|
|
1064
|
+
color?: string | number[];
|
|
1065
|
+
/** 0..1 (default 1). */
|
|
1066
|
+
opacity?: number;
|
|
1067
|
+
blend?: BlendMode;
|
|
1068
|
+
/** Limit to the selection when there is one (default true). */
|
|
1069
|
+
useSelection?: boolean;
|
|
1070
|
+
}
|
|
1071
|
+
/** What a stroke, fill or clear changed. */
|
|
1072
|
+
interface PaintStrokeResult {
|
|
1073
|
+
layerId: string;
|
|
1074
|
+
channel: LayerTarget;
|
|
1075
|
+
/** Document rectangle that changed (null when nothing did). */
|
|
1076
|
+
bounds: CropBox | null;
|
|
1077
|
+
dabs: number;
|
|
1078
|
+
}
|
|
1079
|
+
/** An opaque pre-stroke history snapshot. */
|
|
1080
|
+
type HistoryEntryHandle = {
|
|
1081
|
+
readonly __historyEntry: unique symbol;
|
|
1082
|
+
};
|
|
1083
|
+
/**
|
|
1084
|
+
* A stroke in progress (see `beginStroke`): `push` input points as they arrive, then `end` (one
|
|
1085
|
+
* undo step) or `cancel`.
|
|
1086
|
+
*/
|
|
1087
|
+
declare class PaintStrokeSession {
|
|
1088
|
+
private readonly controller;
|
|
1089
|
+
readonly target: {
|
|
1090
|
+
id: string;
|
|
1091
|
+
channel: LayerTarget;
|
|
1092
|
+
surface: TiledSurface;
|
|
1093
|
+
};
|
|
1094
|
+
private readonly stroke;
|
|
1095
|
+
private readonly apply;
|
|
1096
|
+
private readonly before;
|
|
1097
|
+
private readonly base;
|
|
1098
|
+
private readonly live;
|
|
1099
|
+
private readonly touched;
|
|
1100
|
+
private last;
|
|
1101
|
+
private closed;
|
|
1102
|
+
constructor(controller: ImageEditorController, target: {
|
|
1103
|
+
id: string;
|
|
1104
|
+
channel: LayerTarget;
|
|
1105
|
+
surface: TiledSurface;
|
|
1106
|
+
}, stroke: StrokeCoverage, apply: StrokeApply);
|
|
1107
|
+
get layerId(): string;
|
|
1108
|
+
/** Adds input points (document pixels); the stack shows the stroke so far. */
|
|
1109
|
+
push(points: readonly StrokePoint[]): void;
|
|
1110
|
+
private update;
|
|
1111
|
+
/** Finishes the stroke (one undo step) and returns what changed. */
|
|
1112
|
+
end(): PaintStrokeResult;
|
|
1113
|
+
/** Abandons the stroke and restores the layer. */
|
|
1114
|
+
cancel(): void;
|
|
1115
|
+
}
|
|
1116
|
+
/** Where a new annotation goes. */
|
|
1117
|
+
interface AnnotationPlacement {
|
|
1118
|
+
/** Put the annotation layer directly above this layer (default: the top of the stack). */
|
|
1119
|
+
aboveId?: string;
|
|
1142
1120
|
}
|
|
1143
1121
|
declare const DEFAULT_ADJUSTMENTS: ImageAdjustments;
|
|
1144
1122
|
/**
|
|
@@ -1147,13 +1125,24 @@ declare const DEFAULT_ADJUSTMENTS: ImageAdjustments;
|
|
|
1147
1125
|
*/
|
|
1148
1126
|
declare function normalizeStoredAdjustments(stored: Partial<ImageAdjustments> | undefined | null): ImageAdjustments;
|
|
1149
1127
|
/**
|
|
1150
|
-
* Brings a stored editor state of any schema version to
|
|
1151
|
-
* missing version) has no adjustment layers
|
|
1152
|
-
* and render exactly as before.
|
|
1128
|
+
* Brings a stored editor state of any schema version to a clean state of the same family:
|
|
1129
|
+
* version 1 (and a missing version) has no adjustment layers, version 2 has them, and both stay
|
|
1130
|
+
* in the document-level schema so old states load and render exactly as before. Version 3
|
|
1131
|
+
* (layers) is returned with its document fields cleaned. To lift a v1 / v2 state into layers,
|
|
1132
|
+
* use {@link migrateToLayeredState}.
|
|
1153
1133
|
*/
|
|
1154
1134
|
declare function migrateSerializedImageEditorState(data: Partial<SerializedImageEditorState> & {
|
|
1155
1135
|
version?: number;
|
|
1156
1136
|
}): SerializedImageEditorState;
|
|
1137
|
+
/**
|
|
1138
|
+
* Lifts a stored state of any version into the layered schema (v3) for a canvas of
|
|
1139
|
+
* `width × height`: the source becomes the Background layer with the base sliders as its
|
|
1140
|
+
* `develop` filter and the depth mask as its parametric mask, adjustment layers go above it and
|
|
1141
|
+
* annotations on top (see `layersFromLegacy`).
|
|
1142
|
+
*/
|
|
1143
|
+
declare function migrateToLayeredState(data: Partial<SerializedImageEditorState> & {
|
|
1144
|
+
version?: number;
|
|
1145
|
+
}, size: ImageDimensions): SerializedLayeredImageEditorState;
|
|
1157
1146
|
declare const DEFAULT_TRANSFORM: ImageTransform;
|
|
1158
1147
|
declare const DEFAULT_DEPTH_MASK: DepthMaskOptions;
|
|
1159
1148
|
/**
|
|
@@ -1170,11 +1159,17 @@ declare class ImageEditorController {
|
|
|
1170
1159
|
private undoStack;
|
|
1171
1160
|
private redoStack;
|
|
1172
1161
|
private maxHistoryDepth;
|
|
1162
|
+
private maxHistoryBytes;
|
|
1173
1163
|
private isApplyingHistory;
|
|
1174
1164
|
private initialSnapshot;
|
|
1175
1165
|
/** Pixels the selection tools sample (host-provided or read back from the source). */
|
|
1176
1166
|
private samplePixels;
|
|
1177
1167
|
private samplePixelsOverride;
|
|
1168
|
+
/** Decoded source pixels (the Background's surface), by the buffer or element they came from. */
|
|
1169
|
+
private sourceSurfaces;
|
|
1170
|
+
private viewKey;
|
|
1171
|
+
/** For `compositePixels` and mask evaluation (the renderer keeps its own for the viewport). */
|
|
1172
|
+
private compositor;
|
|
1178
1173
|
constructor(options?: ImageEditorOptions);
|
|
1179
1174
|
/**
|
|
1180
1175
|
* Loads a new source image and makes it the baseline that `reset()` returns to.
|
|
@@ -1186,10 +1181,24 @@ declare class ImageEditorController {
|
|
|
1186
1181
|
getImageElement(): CanvasImageSource | null;
|
|
1187
1182
|
getState(): ImageEditorState;
|
|
1188
1183
|
subscribe(listener: (state: ImageEditorState) => void): () => void;
|
|
1184
|
+
/**
|
|
1185
|
+
* Where layer pixels changed since the last viewport render, when only strokes changed them
|
|
1186
|
+
* (the renderer then recomposites just those rectangles); `'all'` after any other change.
|
|
1187
|
+
*/
|
|
1188
|
+
private pendingDirty;
|
|
1189
1189
|
private notify;
|
|
1190
|
+
/** Recomputes the compatibility views (`adjustments`, `depthMask`, `annotations`) when the stack changed. */
|
|
1191
|
+
private syncViews;
|
|
1192
|
+
private stack;
|
|
1190
1193
|
private captureHistoryEntry;
|
|
1191
1194
|
private restoreHistoryEntry;
|
|
1192
1195
|
private recordHistory;
|
|
1196
|
+
/**
|
|
1197
|
+
* Bytes of pixel tiles held only by undo / redo steps (not by the current state). The oldest
|
|
1198
|
+
* undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
1199
|
+
*/
|
|
1200
|
+
get historyBytes(): number;
|
|
1201
|
+
private trimHistoryBytes;
|
|
1193
1202
|
get canUndo(): boolean;
|
|
1194
1203
|
get canRedo(): boolean;
|
|
1195
1204
|
undo(): boolean;
|
|
@@ -1203,6 +1212,223 @@ declare class ImageEditorController {
|
|
|
1203
1212
|
setRotation(degrees: number): void;
|
|
1204
1213
|
flipHorizontal(): void;
|
|
1205
1214
|
flipVertical(): void;
|
|
1215
|
+
/** The layer stack, bottom to top (immutable objects). */
|
|
1216
|
+
getLayers(): ImageLayer[];
|
|
1217
|
+
getLayer(id: string): ImageLayer | undefined;
|
|
1218
|
+
/** The active layer, or `undefined`. */
|
|
1219
|
+
getActiveLayer(): ImageLayer | undefined;
|
|
1220
|
+
/**
|
|
1221
|
+
* Makes a layer the active one (or none) and chooses whether painting targets its pixels or
|
|
1222
|
+
* its mask. View state: no undo step. Returns false for an unknown id.
|
|
1223
|
+
*/
|
|
1224
|
+
setActiveLayer(id: string | null, target?: LayerTarget): boolean;
|
|
1225
|
+
/**
|
|
1226
|
+
* The pixels of a pixel layer, in document space (`x`, `y` is the top-left of the returned
|
|
1227
|
+
* buffer), or `null` for an unknown or empty layer. Resolves the Background's source pixels.
|
|
1228
|
+
*/
|
|
1229
|
+
getLayerPixels(id: string): (PixelBuffer & {
|
|
1230
|
+
x: number;
|
|
1231
|
+
y: number;
|
|
1232
|
+
}) | null;
|
|
1233
|
+
private boundsCache;
|
|
1234
|
+
/**
|
|
1235
|
+
* Document bounds of a layer's non-transparent pixels (pixel layers; the Background's source
|
|
1236
|
+
* included), or `null` for an empty or non-pixel layer.
|
|
1237
|
+
*/
|
|
1238
|
+
getLayerBounds(id: string): CropBox | null;
|
|
1239
|
+
/**
|
|
1240
|
+
* Composites the layer stack in document space without a canvas (annotation layers need one
|
|
1241
|
+
* and are left out): `rect` (default: the canvas) as RGBA, straight alpha. Crop, rotation and
|
|
1242
|
+
* output opacity are not applied. With `layerIds`, only those layers are composited.
|
|
1243
|
+
*/
|
|
1244
|
+
compositePixels(rect?: CropBox, options?: {
|
|
1245
|
+
layerIds?: string[];
|
|
1246
|
+
}): PixelBuffer;
|
|
1247
|
+
private compositorSources;
|
|
1248
|
+
private sourceIds;
|
|
1249
|
+
private nextSourceId;
|
|
1250
|
+
/** Changes whenever the Background's source pixels can have changed. */
|
|
1251
|
+
private sourceVersion;
|
|
1252
|
+
/** The pixels a pixel layer composites (the decoded source for the Background). */
|
|
1253
|
+
private surfaceOf;
|
|
1254
|
+
/**
|
|
1255
|
+
* The source image as a surface (cached): host-supplied sample pixels first, then the decoded
|
|
1256
|
+
* element, then pixels read back for the selection tools.
|
|
1257
|
+
*/
|
|
1258
|
+
private sourceSurface;
|
|
1259
|
+
private opaqueCache;
|
|
1260
|
+
/** Whether every source pixel is opaque (some legacy renders depend on it). */
|
|
1261
|
+
private sourceIsOpaque;
|
|
1262
|
+
/** Synchronously reads the source element's pixels through a canvas, or `null`. */
|
|
1263
|
+
private decodeSource;
|
|
1264
|
+
/** Records one undo step and applies a new stack (and any other state change in `extra`). */
|
|
1265
|
+
private commitLayers;
|
|
1266
|
+
/** The default position of a new layer: above the active layer, else the top of the stack. */
|
|
1267
|
+
private newLayerPlacement;
|
|
1268
|
+
/**
|
|
1269
|
+
* Adds a pixel layer (one undo step) and makes it active: empty, filled with `color` over the
|
|
1270
|
+
* canvas, or holding `pixels` placed at `x`, `y`. Goes above the active layer unless placed.
|
|
1271
|
+
* Returns its id.
|
|
1272
|
+
*/
|
|
1273
|
+
addPixelLayer(init?: PixelLayerInit): string;
|
|
1274
|
+
/**
|
|
1275
|
+
* `addPixelLayer` from an image: a PNG data URL or base64 PNG is decoded without a canvas;
|
|
1276
|
+
* other formats and URLs need a browser. Returns the new layer id.
|
|
1277
|
+
*/
|
|
1278
|
+
addPixelLayerFromImage(image: string, init?: Omit<PixelLayerInit, 'pixels' | 'color'>): Promise<string>;
|
|
1279
|
+
/** RGBA pixels of an image given as a data URL, base64 PNG or URL. */
|
|
1280
|
+
decodeImage(image: string): Promise<PixelBuffer>;
|
|
1281
|
+
private nextLayerName;
|
|
1282
|
+
/** Duplicates a layer (with its children) directly above it, as one undo step. Returns the copy's id. */
|
|
1283
|
+
duplicateLayer(id: string, name?: string): string;
|
|
1284
|
+
/** Deletes a layer (refused when locked), as one undo step. */
|
|
1285
|
+
removeLayer(id: string): void;
|
|
1286
|
+
/** Moves a layer above / below another, or into a group, as one undo step. Returns its new parent and index. */
|
|
1287
|
+
moveLayer(id: string, placement: LayerPlacement): {
|
|
1288
|
+
parentId: string | null;
|
|
1289
|
+
index: number;
|
|
1290
|
+
};
|
|
1291
|
+
/**
|
|
1292
|
+
* Changes name, visibility, opacity, fill, blend, clipping, locks or (groups) collapsed state, as
|
|
1293
|
+
* one undo step (`commitToHistory = false` for the moves of a slider drag). Returns the layer.
|
|
1294
|
+
*/
|
|
1295
|
+
setLayerProperties(id: string, props: LayerProperties, commitToHistory?: boolean): ImageLayer;
|
|
1296
|
+
/** Adds an empty pass-through group above the active layer (or at `placement`) and makes it active. Returns its id. */
|
|
1297
|
+
addGroup(init?: LayerPlacement & {
|
|
1298
|
+
name?: string;
|
|
1299
|
+
blend?: LayerBlendMode;
|
|
1300
|
+
}): string;
|
|
1301
|
+
/** Puts sibling layers into a new group (one undo step). Returns the group id. */
|
|
1302
|
+
groupLayers(ids: string[], name?: string): string;
|
|
1303
|
+
/** Replaces a group by its children (one undo step). Returns the child ids, bottom to top. */
|
|
1304
|
+
ungroupLayer(id: string): string[];
|
|
1305
|
+
/**
|
|
1306
|
+
* Moves a pixel layer to an absolute offset (`x`, `y`) or by `dx`, `dy`, as one undo step
|
|
1307
|
+
* (`commitToHistory = false` for the moves of a drag). Returns the offset and document bounds.
|
|
1308
|
+
*/
|
|
1309
|
+
offsetLayer(id: string, move: {
|
|
1310
|
+
x?: number;
|
|
1311
|
+
y?: number;
|
|
1312
|
+
dx?: number;
|
|
1313
|
+
dy?: number;
|
|
1314
|
+
}, commitToHistory?: boolean): {
|
|
1315
|
+
offset: {
|
|
1316
|
+
x: number;
|
|
1317
|
+
y: number;
|
|
1318
|
+
};
|
|
1319
|
+
bounds: CropBox | null;
|
|
1320
|
+
};
|
|
1321
|
+
/**
|
|
1322
|
+
* Adds a mask to a layer (one undo step): `reveal-all` (white), `hide-all` (black) or
|
|
1323
|
+
* `selection` (the selection's coverage). Replaces an existing mask. Makes the mask the paint
|
|
1324
|
+
* target when the layer is active.
|
|
1325
|
+
*/
|
|
1326
|
+
addLayerMask(id: string, from?: 'reveal-all' | 'hide-all' | 'selection', props?: LayerMaskProps): RasterMask;
|
|
1327
|
+
/** Removes a layer's mask (one undo step). */
|
|
1328
|
+
removeLayerMask(id: string): void;
|
|
1329
|
+
/** Changes any layer mask's density, feather or enabled flag (pixels kept). Returns the mask. */
|
|
1330
|
+
setLayerMaskProps(id: string, props: LayerMaskProps, commitToHistory?: boolean): RasterMask;
|
|
1331
|
+
/**
|
|
1332
|
+
* Bakes a pixel layer's mask into its pixels (alpha × coverage, including density, feather or
|
|
1333
|
+
* the depth map) and removes the mask, as one undo step.
|
|
1334
|
+
*/
|
|
1335
|
+
applyLayerMask(id: string): Promise<void>;
|
|
1336
|
+
/**
|
|
1337
|
+
* Layer via Copy (or via Cut): a new pixel layer with the selected pixels of a pixel layer (the
|
|
1338
|
+
* active one by default), directly above it, as one undo step. Returns the new id.
|
|
1339
|
+
*/
|
|
1340
|
+
layerViaCopy(options?: {
|
|
1341
|
+
layerId?: string;
|
|
1342
|
+
cut?: boolean;
|
|
1343
|
+
name?: string;
|
|
1344
|
+
}): string;
|
|
1345
|
+
/** Adds a `develop` or `blur` filter to a pixel layer (one undo step). Returns the layer's filters. */
|
|
1346
|
+
addLayerFilter(id: string, filter: Partial<LayerFilter> & {
|
|
1347
|
+
kind: LayerFilter['kind'];
|
|
1348
|
+
}): LayerFilter[];
|
|
1349
|
+
/** Changes one filter (one undo step, or none with `commitToHistory = false` during a drag). Returns the filters. */
|
|
1350
|
+
updateLayerFilter(id: string, filterId: string, changes: Record<string, unknown>, commitToHistory?: boolean): LayerFilter[];
|
|
1351
|
+
/** Removes one filter (one undo step). Returns the remaining filters. */
|
|
1352
|
+
removeLayerFilter(id: string, filterId: string): LayerFilter[];
|
|
1353
|
+
/** Composites `layers` (in isolation) over `rect` into a surface, loading depth maps first. */
|
|
1354
|
+
private compositeToSurface;
|
|
1355
|
+
/** Document bounds a layer can paint into (pixel content, annotations, or the canvas for the rest). */
|
|
1356
|
+
private paintBounds;
|
|
1357
|
+
/**
|
|
1358
|
+
* Merge Down: composites a layer onto the pixel layer directly below it (which keeps its name,
|
|
1359
|
+
* opacity and blend; masks, fill and filters are baked), as one undo step. Returns the merged id.
|
|
1360
|
+
*/
|
|
1361
|
+
mergeDown(id: string): Promise<string>;
|
|
1362
|
+
/**
|
|
1363
|
+
* Merge Visible: the visible top-level layers become one normal pixel layer (at the position of
|
|
1364
|
+
* the lowest of them); hidden layers stay. One undo step. Returns the merged id.
|
|
1365
|
+
*/
|
|
1366
|
+
mergeVisible(): Promise<string>;
|
|
1367
|
+
/** Flatten Image: every visible layer composited into one Background layer; hidden layers are discarded. One undo step. */
|
|
1368
|
+
flattenImage(): Promise<string>;
|
|
1369
|
+
private thumbCache;
|
|
1370
|
+
/**
|
|
1371
|
+
* A small RGBA preview of a pixel layer over the canvas (or of its mask with `mask: true`),
|
|
1372
|
+
* longest side `maxSide` px, point-sampled; `null` for layers without pixels.
|
|
1373
|
+
*/
|
|
1374
|
+
getLayerThumbnail(id: string, options?: {
|
|
1375
|
+
maxSide?: number;
|
|
1376
|
+
mask?: boolean;
|
|
1377
|
+
}): PixelBuffer | null;
|
|
1378
|
+
/** Brush settings, colours and tool options of the paint tools (view state, no undo). */
|
|
1379
|
+
setPaintOptions(options: Partial<Omit<PaintOptions, 'brush'>> & {
|
|
1380
|
+
brush?: Partial<BrushSettings>;
|
|
1381
|
+
}): PaintOptions;
|
|
1382
|
+
/** D: black foreground, white background. */
|
|
1383
|
+
resetPaintColors(): void;
|
|
1384
|
+
/** X: swaps the foreground and background colours. */
|
|
1385
|
+
swapPaintColors(): void;
|
|
1386
|
+
/** Resolves and validates what a stroke, fill or clear paints into. */
|
|
1387
|
+
private paintTarget;
|
|
1388
|
+
/** The layer with its pixels (or mask) replaced by `surface`. */
|
|
1389
|
+
private withSurface;
|
|
1390
|
+
/**
|
|
1391
|
+
* Starts a brush or eraser stroke on a layer's pixels or mask (default: the active layer and
|
|
1392
|
+
* target, the paint options' brush and colours). Feed points with `push`, finish with `end()`
|
|
1393
|
+
* (one undo step for the whole stroke) or `cancel()`. While it runs, the stack shows the stroke
|
|
1394
|
+
* without recording history.
|
|
1395
|
+
*/
|
|
1396
|
+
beginStroke(init?: StrokeInit): PaintStrokeSession;
|
|
1397
|
+
/** @internal Shows a stroke's live surface (no history). */
|
|
1398
|
+
_strokeUpdate(layerId: string, channel: LayerTarget, surface: TiledSurface, rects: CropBox[]): void;
|
|
1399
|
+
/** @internal Commits a finished stroke as one undo step (`before` is the pre-stroke state). */
|
|
1400
|
+
_strokeCommit(before: HistoryEntryHandle, layerId: string, channel: LayerTarget, surface: TiledSurface | null): void;
|
|
1401
|
+
/** @internal The pre-stroke snapshot. */
|
|
1402
|
+
_captureForStroke(): HistoryEntryHandle;
|
|
1403
|
+
/**
|
|
1404
|
+
* Paints a whole stroke in one call (agents, replays): `points` in document pixels with optional
|
|
1405
|
+
* pressure, through the brush or eraser. One undo step. Returns the layer, channel, the changed
|
|
1406
|
+
* document bounds and the number of dabs.
|
|
1407
|
+
*/
|
|
1408
|
+
paintStroke(init: StrokeInit & {
|
|
1409
|
+
points: StrokePoint[];
|
|
1410
|
+
}): PaintStrokeResult;
|
|
1411
|
+
/**
|
|
1412
|
+
* Edit › Fill: fills the selection (or, without one or with `useSelection: false`, the whole
|
|
1413
|
+
* canvas) on a layer's pixels or mask with a colour (default the foreground), at `opacity` with
|
|
1414
|
+
* `blend`. One undo step. Returns the changed bounds.
|
|
1415
|
+
*/
|
|
1416
|
+
fillPixels(options?: FillOptions): PaintStrokeResult;
|
|
1417
|
+
/**
|
|
1418
|
+
* Edit › Clear: removes the selected pixels (alpha to 0; on a transparency-locked layer or a mask
|
|
1419
|
+
* it fills with the background colour). Without a selection (or with `useSelection: false`) the
|
|
1420
|
+
* whole canvas. One undo step. Returns the changed bounds.
|
|
1421
|
+
*/
|
|
1422
|
+
clearPixels(options?: Omit<FillOptions, 'color' | 'blend'>): PaintStrokeResult;
|
|
1423
|
+
private fillOrClear;
|
|
1424
|
+
/** The pixel layer the base sliders edit: the active pixel layer, else the Background. */
|
|
1425
|
+
private developLayer;
|
|
1426
|
+
/**
|
|
1427
|
+
* Sets base adjustment values as one undo step (unless `commitToHistory` is false). The base
|
|
1428
|
+
* sliders edit the `develop` filter of the active pixel layer (or the Background), `blur` its
|
|
1429
|
+
* blur filter (or `legacyOutputBlur` in migrated documents), `opacity` the output opacity, and
|
|
1430
|
+
* `layers` replaces the adjustment layers.
|
|
1431
|
+
*/
|
|
1206
1432
|
setAdjustments(partial: Partial<ImageAdjustments>, commitToHistory?: boolean): void;
|
|
1207
1433
|
/** True when the adjustments use an older rendering process than {@link LATEST_PROCESS_VERSION}. */
|
|
1208
1434
|
get isProcessOutdated(): boolean;
|
|
@@ -1213,13 +1439,24 @@ declare class ImageEditorController {
|
|
|
1213
1439
|
upgradeProcess(): boolean;
|
|
1214
1440
|
/** Resets the base sliders (latest process). Adjustment layers are kept; see `clearAdjustmentLayers`. */
|
|
1215
1441
|
resetAdjustments(): void;
|
|
1216
|
-
/** The adjustment layers, bottom (first) to top (last). */
|
|
1442
|
+
/** The adjustment layers in stack order, bottom (first) to top (last). */
|
|
1217
1443
|
getAdjustmentLayers(): AdjustmentLayer[];
|
|
1218
1444
|
getAdjustmentLayer(id: string): AdjustmentLayer | undefined;
|
|
1219
|
-
private
|
|
1445
|
+
private adjustmentNodes;
|
|
1446
|
+
/**
|
|
1447
|
+
* Where a new layer goes when no position is given: directly above the topmost layer that is
|
|
1448
|
+
* not an annotation, so it adjusts what adjustment layers always adjusted (annotations stay on top).
|
|
1449
|
+
*/
|
|
1450
|
+
private defaultInsertIndex;
|
|
1451
|
+
/** Inserts `node` by `aboveId` / `parentId` / adjustment index / default position. */
|
|
1452
|
+
private placeLayer;
|
|
1453
|
+
/** `setAdjustments({ layers })`: updates nodes by id in place, removes missing ones, adds new ones. */
|
|
1454
|
+
private replaceAdjustmentNodes;
|
|
1220
1455
|
/**
|
|
1221
|
-
* Adds an adjustment layer
|
|
1222
|
-
*
|
|
1456
|
+
* Adds an adjustment layer and returns its id, as one undo step. With no position it goes
|
|
1457
|
+
* above the other adjustment layers (or, without any, above the topmost non-annotation layer,
|
|
1458
|
+
* so annotations stay on top); `index` counts adjustment layers (0 = below the others);
|
|
1459
|
+
* `aboveId` / `parentId` place it anywhere in the stack. `kind` alone gives neutral parameters.
|
|
1223
1460
|
*/
|
|
1224
1461
|
addAdjustmentLayer<K extends AdjustmentKind>(init: K | AdjustmentLayerInit<K>, index?: number): string;
|
|
1225
1462
|
/**
|
|
@@ -1230,7 +1467,8 @@ declare class ImageEditorController {
|
|
|
1230
1467
|
updateAdjustmentLayer(id: string, update: AdjustmentLayerUpdate, commitToHistory?: boolean): boolean;
|
|
1231
1468
|
/** Removes a layer as one undo step. Returns false for an unknown id. */
|
|
1232
1469
|
removeAdjustmentLayer(id: string): boolean;
|
|
1233
|
-
|
|
1470
|
+
private moveAdjustmentNode;
|
|
1471
|
+
/** Moves a layer to `toIndex` among the adjustment layers (0 = bottom) as one undo step. Returns false if nothing moved. */
|
|
1234
1472
|
moveAdjustmentLayer(id: string, toIndex: number): boolean;
|
|
1235
1473
|
/** Shows or hides a layer (flips it without `enabled`) as one undo step. */
|
|
1236
1474
|
toggleAdjustmentLayer(id: string, enabled?: boolean): boolean;
|
|
@@ -1262,13 +1500,14 @@ declare class ImageEditorController {
|
|
|
1262
1500
|
selectPolygon(points: ImagePoint[], options?: SelectionCommandOptions & ShapeSelectionOptions): boolean;
|
|
1263
1501
|
/**
|
|
1264
1502
|
* Supplies the pixels the selection tools sample (natural size RGBA), e.g. decoded in a worker
|
|
1265
|
-
* or in a test; `null` goes back to reading the source image.
|
|
1503
|
+
* or in a test; `null` goes back to reading the source image. Without a canvas (Node, workers)
|
|
1504
|
+
* these are also the Background layer's pixels.
|
|
1266
1505
|
*/
|
|
1267
1506
|
setSamplePixels(pixels: PixelBuffer | null): void;
|
|
1268
1507
|
/**
|
|
1269
1508
|
* The pixels the selection tools sample: the source image at natural size, or with
|
|
1270
|
-
* `sampleMerged` the
|
|
1271
|
-
*
|
|
1509
|
+
* `sampleMerged` the composite of the layers (no crop, rotation or annotations). `null`
|
|
1510
|
+
* without pixel access (no DOM, tainted canvas).
|
|
1272
1511
|
*/
|
|
1273
1512
|
getSamplePixels(options?: SampleOptions): Promise<PixelBuffer | null>;
|
|
1274
1513
|
private requirePixels;
|
|
@@ -1298,11 +1537,13 @@ declare class ImageEditorController {
|
|
|
1298
1537
|
}): Promise<SelectionMask | null>;
|
|
1299
1538
|
/** Quick Mask view (tints the unselected area). View state: no undo step. */
|
|
1300
1539
|
setQuickMask(on: boolean): void;
|
|
1540
|
+
private maskFromSelection;
|
|
1301
1541
|
/**
|
|
1302
1542
|
* Adds the selection as the layer's mask (Reveal Selection), replacing any mask, as one undo
|
|
1303
1543
|
* step. Without a selection, returns false.
|
|
1304
1544
|
*/
|
|
1305
1545
|
applySelectionAsLayerMask(layerId: string, props?: LayerMaskProps): boolean;
|
|
1546
|
+
private setLayerMask;
|
|
1306
1547
|
/** Sets (from a selection-shaped mask) or removes (`null`) a layer's mask as one undo step. */
|
|
1307
1548
|
setAdjustmentLayerMask(layerId: string, mask: SelectionMask | null, props?: LayerMaskProps): boolean;
|
|
1308
1549
|
/** Changes a layer mask's density (0..1), feather (px) or enabled flag; the mask pixels are kept. */
|
|
@@ -1316,9 +1557,12 @@ declare class ImageEditorController {
|
|
|
1316
1557
|
getHistogram(): ImageHistogram | null;
|
|
1317
1558
|
/** Calls `listener` now and whenever a render produces a new preview histogram. */
|
|
1318
1559
|
subscribeHistogram(listener: (histogram: ImageHistogram | null) => void): () => void;
|
|
1560
|
+
/** Sets the depth mask (a parametric mask on the active pixel layer, or the Background) as one undo step. */
|
|
1319
1561
|
setDepthMask(partial: Partial<DepthMaskOptions>): void;
|
|
1320
1562
|
resetDepthMask(): void;
|
|
1321
|
-
|
|
1563
|
+
private annotationLayer;
|
|
1564
|
+
/** Adds an annotation as its own layer (top of the stack unless `aboveId` is given). */
|
|
1565
|
+
addAnnotation(annotation: CreateAnnotationPayload, placement?: AnnotationPlacement): string;
|
|
1322
1566
|
updateAnnotation(id: string, partial: Partial<Annotation>, commitToHistory?: boolean): void;
|
|
1323
1567
|
removeAnnotation(id: string): void;
|
|
1324
1568
|
clearAnnotations(): void;
|
|
@@ -1329,6 +1573,7 @@ declare class ImageEditorController {
|
|
|
1329
1573
|
resetZoom(): void;
|
|
1330
1574
|
setPan(pan: ImagePoint): void;
|
|
1331
1575
|
setComparing(comparing: boolean): void;
|
|
1576
|
+
setFit(fit: ImageEditorFit): void;
|
|
1332
1577
|
render(targetCanvas: HTMLCanvasElement, options?: RenderOptions): Promise<void>;
|
|
1333
1578
|
renderExport(options?: ExportOptions): Promise<HTMLCanvasElement>;
|
|
1334
1579
|
/**
|
|
@@ -1366,23 +1611,572 @@ declare class ImageEditorController {
|
|
|
1366
1611
|
*/
|
|
1367
1612
|
applyInpaintedImage(newDataUrl: string): Promise<void>;
|
|
1368
1613
|
/**
|
|
1369
|
-
* Replaces the source image with a background-removed result as ONE undoable step.
|
|
1370
|
-
* Crop and annotations are kept (rescaled if the new image has different dimensions).
|
|
1614
|
+
* Replaces the source image with a background-removed result as ONE undoable step.
|
|
1615
|
+
* Crop and annotations are kept (rescaled if the new image has different dimensions).
|
|
1616
|
+
*/
|
|
1617
|
+
applyBackgroundRemovedImage(newDataUrl: string): Promise<void>;
|
|
1618
|
+
private replaceSource;
|
|
1619
|
+
/**
|
|
1620
|
+
* The serializable state. A document whose layers still have the v1 / v2 shape (the
|
|
1621
|
+
* Background with its sliders and depth mask, adjustment layers, annotations) is written as
|
|
1622
|
+
* v1 / v2 exactly as before; anything else is written as v3 with the layer pixels as PNG
|
|
1623
|
+
* assets. `selection` is included (run-length encoded) only when something is selected.
|
|
1624
|
+
*/
|
|
1625
|
+
toJSON(): SerializedImageEditorState;
|
|
1626
|
+
/** Loads a stored state of any version (one undo step). */
|
|
1627
|
+
loadJSON(data: SerializedImageEditorState): void;
|
|
1628
|
+
/** Problems found by the last `loadJSON` / `initialState` of a v3 document (unreadable layers or assets). */
|
|
1629
|
+
lastLoadProblems: string[];
|
|
1630
|
+
private applyStored;
|
|
1631
|
+
private serializeState;
|
|
1632
|
+
}
|
|
1633
|
+
/** A colour as RGBA bytes: `#rgb`, `#rrggbb`, `#rrggbbaa` or `[r, g, b, a?]` (0..255). */
|
|
1634
|
+
declare function parseColor(value: string | number[]): [number, number, number, number];
|
|
1635
|
+
/** `#rrggbb` of RGBA bytes (alpha dropped). */
|
|
1636
|
+
declare function toHex(c: readonly number[]): string;
|
|
1637
|
+
|
|
1638
|
+
interface ImageDimensions {
|
|
1639
|
+
width: number;
|
|
1640
|
+
height: number;
|
|
1641
|
+
}
|
|
1642
|
+
interface ImagePoint {
|
|
1643
|
+
x: number;
|
|
1644
|
+
y: number;
|
|
1645
|
+
}
|
|
1646
|
+
interface CropBox {
|
|
1647
|
+
x: number;
|
|
1648
|
+
y: number;
|
|
1649
|
+
width: number;
|
|
1650
|
+
height: number;
|
|
1651
|
+
}
|
|
1652
|
+
type AspectRatio = number | null;
|
|
1653
|
+
interface ImageTransform {
|
|
1654
|
+
rotate: number;
|
|
1655
|
+
flipH: boolean;
|
|
1656
|
+
flipV: boolean;
|
|
1657
|
+
}
|
|
1658
|
+
interface ImageAdjustments {
|
|
1659
|
+
brightness: number;
|
|
1660
|
+
contrast: number;
|
|
1661
|
+
saturation: number;
|
|
1662
|
+
exposure: number;
|
|
1663
|
+
temperature: number;
|
|
1664
|
+
/**
|
|
1665
|
+
* -100 (green) to 100 (magenta), 0 is default. White-balance tint correction in Duv × 3000
|
|
1666
|
+
* (process 2 only; the legacy process ignores it).
|
|
1667
|
+
*/
|
|
1668
|
+
tint?: number;
|
|
1669
|
+
blur: number;
|
|
1670
|
+
opacity: number;
|
|
1671
|
+
/**
|
|
1672
|
+
* Rendering process the values are interpreted by. `2` (the latest; new edits and Reset get
|
|
1673
|
+
* it): linear-light exposure, Bradford white balance, LUT tone curve without intermediate
|
|
1674
|
+
* clipping. `1` or missing: the legacy 8-bit rendering, so edits saved before process
|
|
1675
|
+
* versions existed look exactly as they did. See `normalizeProcessVersion`.
|
|
1676
|
+
*/
|
|
1677
|
+
process?: 1 | 2;
|
|
1678
|
+
/**
|
|
1679
|
+
* Non-destructive adjustment layers, evaluated bottom (first) to top (last) after the base
|
|
1680
|
+
* adjustments above, on the encoded sRGB result. Missing or empty: no layers (edits saved
|
|
1681
|
+
* before layers existed render exactly as before).
|
|
1682
|
+
*/
|
|
1683
|
+
layers?: AdjustmentLayer[];
|
|
1684
|
+
}
|
|
1685
|
+
type AdjustmentKind = 'curves' | 'levels' | 'hueSaturation' | 'vibrance' | 'colorBalance' | 'blackWhite' | 'invert' | 'posterize' | 'threshold' | 'photoFilter';
|
|
1686
|
+
/** A Curves point; `input` and `output` are levels, 0..255. */
|
|
1687
|
+
interface CurvePoint {
|
|
1688
|
+
input: number;
|
|
1689
|
+
output: number;
|
|
1690
|
+
}
|
|
1691
|
+
/** Curves: each channel's curve first, then the master (composite) curve, as in Photoshop. */
|
|
1692
|
+
interface CurvesParams {
|
|
1693
|
+
master: CurvePoint[];
|
|
1694
|
+
red: CurvePoint[];
|
|
1695
|
+
green: CurvePoint[];
|
|
1696
|
+
blue: CurvePoint[];
|
|
1697
|
+
}
|
|
1698
|
+
/** One Levels record. Black / white points are levels (0..255); `gamma` is the midtone slider (0.1..9.99). */
|
|
1699
|
+
interface LevelsChannel {
|
|
1700
|
+
inBlack: number;
|
|
1701
|
+
inWhite: number;
|
|
1702
|
+
gamma: number;
|
|
1703
|
+
outBlack: number;
|
|
1704
|
+
outWhite: number;
|
|
1705
|
+
}
|
|
1706
|
+
/** Levels: each channel's record first, then the master record, as in Photoshop. */
|
|
1707
|
+
interface LevelsParams {
|
|
1708
|
+
master: LevelsChannel;
|
|
1709
|
+
red: LevelsChannel;
|
|
1710
|
+
green: LevelsChannel;
|
|
1711
|
+
blue: LevelsChannel;
|
|
1712
|
+
}
|
|
1713
|
+
/** One of Hue/Saturation's six colour ranges (reds, yellows, greens, cyans, blues, magentas). */
|
|
1714
|
+
interface HueRange {
|
|
1715
|
+
/** Hue shift in degrees (-180..180). */
|
|
1716
|
+
hue: number;
|
|
1717
|
+
/** Saturation change in percent (-100..100). */
|
|
1718
|
+
saturation: number;
|
|
1719
|
+
/** Lightness change in percent (-100..100). */
|
|
1720
|
+
lightness: number;
|
|
1721
|
+
/** Hue degrees where the range starts fading in, is fully on, starts fading out and ends (may wrap). */
|
|
1722
|
+
bounds: [number, number, number, number];
|
|
1723
|
+
}
|
|
1724
|
+
interface HueSaturationParams {
|
|
1725
|
+
/** Master hue shift in degrees (-180..180), or the hue when colorizing (0..360). */
|
|
1726
|
+
hue: number;
|
|
1727
|
+
/** Percent, -100..100 (0..100 when colorizing). */
|
|
1728
|
+
saturation: number;
|
|
1729
|
+
/** Percent, -100..100. */
|
|
1730
|
+
lightness: number;
|
|
1731
|
+
colorize: boolean;
|
|
1732
|
+
/** Six ranges: reds, yellows, greens, cyans, blues, magentas. */
|
|
1733
|
+
ranges: HueRange[];
|
|
1734
|
+
}
|
|
1735
|
+
interface VibranceParams {
|
|
1736
|
+
/** -100..100 */
|
|
1737
|
+
vibrance: number;
|
|
1738
|
+
/** -100..100 */
|
|
1739
|
+
saturation: number;
|
|
1740
|
+
}
|
|
1741
|
+
/** Cyan–red, magenta–green, yellow–blue sliders, -100..100 each. */
|
|
1742
|
+
type ColorBalanceTone = [number, number, number];
|
|
1743
|
+
interface ColorBalanceParams {
|
|
1744
|
+
shadows: ColorBalanceTone;
|
|
1745
|
+
midtones: ColorBalanceTone;
|
|
1746
|
+
highlights: ColorBalanceTone;
|
|
1747
|
+
preserveLuminosity: boolean;
|
|
1748
|
+
}
|
|
1749
|
+
/** Black & White: percent weights of the six colours (Photoshop defaults 40 60 40 60 20 80). */
|
|
1750
|
+
interface BlackWhiteParams {
|
|
1751
|
+
reds: number;
|
|
1752
|
+
yellows: number;
|
|
1753
|
+
greens: number;
|
|
1754
|
+
cyans: number;
|
|
1755
|
+
blues: number;
|
|
1756
|
+
magentas: number;
|
|
1757
|
+
/** Tint colour (`#rrggbb`), applied like the Color blend mode, or `null` for none. */
|
|
1758
|
+
tint: string | null;
|
|
1759
|
+
}
|
|
1760
|
+
interface PhotoFilterParams {
|
|
1761
|
+
/** Filter colour, `#rrggbb`. */
|
|
1762
|
+
color: string;
|
|
1763
|
+
/** Percent, 0..100. */
|
|
1764
|
+
density: number;
|
|
1765
|
+
preserveLuminosity: boolean;
|
|
1766
|
+
}
|
|
1767
|
+
interface PosterizeParams {
|
|
1768
|
+
/** 2..255 */
|
|
1769
|
+
levels: number;
|
|
1770
|
+
}
|
|
1771
|
+
interface ThresholdParams {
|
|
1772
|
+
/** 1..255: luma at or above it becomes white. */
|
|
1773
|
+
level: number;
|
|
1774
|
+
}
|
|
1775
|
+
type InvertParams = Record<string, never>;
|
|
1776
|
+
interface AdjustmentParamsMap {
|
|
1777
|
+
curves: CurvesParams;
|
|
1778
|
+
levels: LevelsParams;
|
|
1779
|
+
hueSaturation: HueSaturationParams;
|
|
1780
|
+
vibrance: VibranceParams;
|
|
1781
|
+
colorBalance: ColorBalanceParams;
|
|
1782
|
+
blackWhite: BlackWhiteParams;
|
|
1783
|
+
invert: InvertParams;
|
|
1784
|
+
posterize: PosterizeParams;
|
|
1785
|
+
threshold: ThresholdParams;
|
|
1786
|
+
photoFilter: PhotoFilterParams;
|
|
1787
|
+
}
|
|
1788
|
+
interface AdjustmentLayerBase {
|
|
1789
|
+
id: string;
|
|
1790
|
+
/** Optional display name. */
|
|
1791
|
+
name?: string;
|
|
1792
|
+
enabled: boolean;
|
|
1793
|
+
/** 0..1 */
|
|
1794
|
+
opacity: number;
|
|
1795
|
+
/** How the adjusted colour is blended over the layers below. */
|
|
1796
|
+
blend: BlendMode;
|
|
1797
|
+
/**
|
|
1798
|
+
* Optional layer mask (natural image pixels): where it is 0 the layer has no effect. Missing:
|
|
1799
|
+
* the layer applies everywhere (layers saved before masks existed are unchanged).
|
|
1800
|
+
*/
|
|
1801
|
+
mask?: AdjustmentLayerMask;
|
|
1802
|
+
}
|
|
1803
|
+
/**
|
|
1804
|
+
* A layer mask: 8-bit coverage of the source image, run-length encoded (see
|
|
1805
|
+
* `encodeSelectionRle`), plus non-destructive density and feather.
|
|
1806
|
+
*/
|
|
1807
|
+
interface AdjustmentLayerMask {
|
|
1808
|
+
width: number;
|
|
1809
|
+
height: number;
|
|
1810
|
+
/** `r1:` run-length encoding of the mask bytes. */
|
|
1811
|
+
rle: string;
|
|
1812
|
+
/** 0..1 (missing = 1). */
|
|
1813
|
+
density?: number;
|
|
1814
|
+
/** Gaussian σ in pixels (missing = 0). */
|
|
1815
|
+
feather?: number;
|
|
1816
|
+
/** `false` keeps the mask but ignores it. */
|
|
1817
|
+
enabled?: boolean;
|
|
1818
|
+
}
|
|
1819
|
+
/** A non-destructive adjustment layer (Photoshop's Layer › New Adjustment Layer). */
|
|
1820
|
+
type AdjustmentLayer = {
|
|
1821
|
+
[K in AdjustmentKind]: AdjustmentLayerBase & {
|
|
1822
|
+
kind: K;
|
|
1823
|
+
params: AdjustmentParamsMap[K];
|
|
1824
|
+
};
|
|
1825
|
+
}[AdjustmentKind];
|
|
1826
|
+
type AdjustmentLayerOf<K extends AdjustmentKind> = Extract<AdjustmentLayer, {
|
|
1827
|
+
kind: K;
|
|
1828
|
+
}>;
|
|
1829
|
+
interface DepthMaskOptions {
|
|
1830
|
+
enabled: boolean;
|
|
1831
|
+
maskSource: string | null;
|
|
1832
|
+
mode: 'threshold' | 'brightness';
|
|
1833
|
+
depthRange: [number, number];
|
|
1834
|
+
softness: number;
|
|
1835
|
+
invert: boolean;
|
|
1836
|
+
}
|
|
1837
|
+
type AnnotationType = 'pen' | 'rect' | 'circle' | 'arrow' | 'line' | 'text' | 'image';
|
|
1838
|
+
interface BaseAnnotation {
|
|
1839
|
+
id: string;
|
|
1840
|
+
type: AnnotationType;
|
|
1841
|
+
x: number;
|
|
1842
|
+
y: number;
|
|
1843
|
+
rotation?: number;
|
|
1844
|
+
opacity?: number;
|
|
1845
|
+
/** Blend mode the annotation is drawn with (default `normal`). */
|
|
1846
|
+
blend?: BlendMode;
|
|
1847
|
+
}
|
|
1848
|
+
interface PenAnnotation extends BaseAnnotation {
|
|
1849
|
+
type: 'pen';
|
|
1850
|
+
points: ImagePoint[];
|
|
1851
|
+
strokeColor: string;
|
|
1852
|
+
strokeWidth: number;
|
|
1853
|
+
}
|
|
1854
|
+
interface RectAnnotation extends BaseAnnotation {
|
|
1855
|
+
type: 'rect';
|
|
1856
|
+
width: number;
|
|
1857
|
+
height: number;
|
|
1858
|
+
strokeColor: string;
|
|
1859
|
+
strokeWidth: number;
|
|
1860
|
+
fillColor?: string;
|
|
1861
|
+
cornerRadius?: number;
|
|
1862
|
+
}
|
|
1863
|
+
interface CircleAnnotation extends BaseAnnotation {
|
|
1864
|
+
type: 'circle';
|
|
1865
|
+
radiusX: number;
|
|
1866
|
+
radiusY: number;
|
|
1867
|
+
strokeColor: string;
|
|
1868
|
+
strokeWidth: number;
|
|
1869
|
+
fillColor?: string;
|
|
1870
|
+
}
|
|
1871
|
+
interface ArrowAnnotation extends BaseAnnotation {
|
|
1872
|
+
type: 'arrow';
|
|
1873
|
+
endX: number;
|
|
1874
|
+
endY: number;
|
|
1875
|
+
strokeColor: string;
|
|
1876
|
+
strokeWidth: number;
|
|
1877
|
+
}
|
|
1878
|
+
interface LineAnnotation extends BaseAnnotation {
|
|
1879
|
+
type: 'line';
|
|
1880
|
+
endX: number;
|
|
1881
|
+
endY: number;
|
|
1882
|
+
strokeColor: string;
|
|
1883
|
+
strokeWidth: number;
|
|
1884
|
+
}
|
|
1885
|
+
interface TextAnnotation extends BaseAnnotation {
|
|
1886
|
+
type: 'text';
|
|
1887
|
+
text: string;
|
|
1888
|
+
fontSize: number;
|
|
1889
|
+
fontFamily?: string;
|
|
1890
|
+
color: string;
|
|
1891
|
+
fontWeight?: string | number;
|
|
1892
|
+
}
|
|
1893
|
+
interface ImageAnnotation extends BaseAnnotation {
|
|
1894
|
+
type: 'image';
|
|
1895
|
+
src: string;
|
|
1896
|
+
width: number;
|
|
1897
|
+
height: number;
|
|
1898
|
+
}
|
|
1899
|
+
type Annotation = PenAnnotation | RectAnnotation | CircleAnnotation | ArrowAnnotation | LineAnnotation | TextAnnotation | ImageAnnotation;
|
|
1900
|
+
type CreateAnnotationPayload = Omit<PenAnnotation, 'id'> | Omit<RectAnnotation, 'id'> | Omit<CircleAnnotation, 'id'> | Omit<ArrowAnnotation, 'id'> | Omit<LineAnnotation, 'id'> | Omit<TextAnnotation, 'id'> | Omit<ImageAnnotation, 'id'>;
|
|
1901
|
+
type ImageEditorTool = 'select' | 'crop' | 'pen' | 'rect' | 'circle' | 'arrow' | 'line' | 'text' | 'watermark' | 'move' | 'brush' | 'eraser';
|
|
1902
|
+
type ImageEditorFit = 'contain' | 'margin';
|
|
1903
|
+
interface ImageEditorState {
|
|
1904
|
+
sourceUrl: string | null;
|
|
1905
|
+
/** Canvas (document) size in pixels: the source image's natural size. */
|
|
1906
|
+
imageDimensions: ImageDimensions;
|
|
1907
|
+
crop: CropBox | null;
|
|
1908
|
+
transform: ImageTransform;
|
|
1909
|
+
/**
|
|
1910
|
+
* Compatibility view of the layer stack: the develop filter of the active pixel layer (or the
|
|
1911
|
+
* Background), its blur (or `legacyOutputBlur`), the output opacity and every adjustment layer
|
|
1912
|
+
* in stack order. Edit it with `setAdjustments` and the adjustment-layer methods.
|
|
1913
|
+
*/
|
|
1914
|
+
adjustments: ImageAdjustments;
|
|
1915
|
+
/** Compatibility view: the parametric depth mask of the active pixel layer (or the Background). */
|
|
1916
|
+
depthMask: DepthMaskOptions;
|
|
1917
|
+
/** Compatibility view: the annotation of every annotation layer, bottom to top. */
|
|
1918
|
+
annotations: Annotation[];
|
|
1919
|
+
selectedAnnotationId: string | null;
|
|
1920
|
+
activeTool: ImageEditorTool;
|
|
1921
|
+
zoom: number;
|
|
1922
|
+
pan: ImagePoint;
|
|
1923
|
+
isOriginalCompared: boolean;
|
|
1924
|
+
/** Viewport fit mode: 'contain' scales to full viewport bounds; 'margin' scales to 85% with 1.0 cap (default). */
|
|
1925
|
+
fit?: ImageEditorFit;
|
|
1926
|
+
/**
|
|
1927
|
+
* The active selection (8-bit coverage over the source image), or null/missing when nothing is
|
|
1928
|
+
* selected. Recorded in undo history and saved as `selection` in `toJSON()`.
|
|
1929
|
+
*/
|
|
1930
|
+
selection?: SelectionMask | null;
|
|
1931
|
+
/** Quick Mask view: tint the unselected area instead of drawing marching ants (view state). */
|
|
1932
|
+
quickMask?: boolean;
|
|
1933
|
+
/**
|
|
1934
|
+
* The layer stack, bottom to top. Opening an image gives one pixel layer, "Background", whose
|
|
1935
|
+
* pixels are the source image. Layers are immutable: compare them by identity.
|
|
1936
|
+
*/
|
|
1937
|
+
layers: ImageLayer[];
|
|
1938
|
+
/** The layer that layer commands, painting and `setAdjustments` act on, or `null`. */
|
|
1939
|
+
activeLayerId: string | null;
|
|
1940
|
+
/** Whether painting targets the active layer's pixels or its mask. */
|
|
1941
|
+
activeTarget: LayerTarget;
|
|
1942
|
+
/** Export alpha (0..1), applied after compositing; `adjustments.opacity` mirrors it. */
|
|
1943
|
+
outputOpacity: number;
|
|
1944
|
+
/**
|
|
1945
|
+
* Blur that runs after the adjustment layers, kept from v1 / v2 documents that had both so
|
|
1946
|
+
* they render as before. New edits blur a layer instead (`blur` filter).
|
|
1947
|
+
*/
|
|
1948
|
+
legacyOutputBlur?: number;
|
|
1949
|
+
/** Brush settings and foreground / background colours of the paint tools (view state). */
|
|
1950
|
+
paint: PaintOptions;
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* A stored editor state in the document-level schema (versions 1 and 2). Documents whose layer
|
|
1954
|
+
* stack has exactly this shape are still written this way, byte for byte.
|
|
1955
|
+
*/
|
|
1956
|
+
interface LegacySerializedImageEditorState {
|
|
1957
|
+
/**
|
|
1958
|
+
* Schema version. `2` adds `adjustments.layers`; states without layers are still written as
|
|
1959
|
+
* `1` so they round-trip unchanged. See `migrateSerializedImageEditorState`.
|
|
1960
|
+
*/
|
|
1961
|
+
version: 1 | 2;
|
|
1962
|
+
crop: CropBox | null;
|
|
1963
|
+
transform: ImageTransform;
|
|
1964
|
+
adjustments: ImageAdjustments;
|
|
1965
|
+
depthMask: DepthMaskOptions;
|
|
1966
|
+
annotations: Annotation[];
|
|
1967
|
+
/** The active selection, run-length encoded. Missing when nothing is selected. */
|
|
1968
|
+
selection?: SerializedSelection;
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* A stored editor state: the document-level schema (v1 / v2) or the layered schema (v3, see
|
|
1972
|
+
* `SerializedLayeredImageEditorState`). `toJSON()` writes v1 / v2 while the layer stack still
|
|
1973
|
+
* has the shape those versions describe.
|
|
1974
|
+
*/
|
|
1975
|
+
type SerializedImageEditorState = LegacySerializedImageEditorState | SerializedLayeredImageEditorState;
|
|
1976
|
+
interface ExportOptions {
|
|
1977
|
+
format?: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
1978
|
+
quality?: number;
|
|
1979
|
+
width?: number;
|
|
1980
|
+
height?: number;
|
|
1981
|
+
includeAnnotations?: boolean;
|
|
1982
|
+
/** Render only these layers (groups with their children). */
|
|
1983
|
+
layerIds?: string[];
|
|
1984
|
+
}
|
|
1985
|
+
interface ImageEditorOptions {
|
|
1986
|
+
image?: string | HTMLImageElement;
|
|
1987
|
+
initialState?: Partial<SerializedImageEditorState>;
|
|
1988
|
+
onStateChange?: (state: ImageEditorState) => void;
|
|
1989
|
+
maxHistoryDepth?: number;
|
|
1990
|
+
/**
|
|
1991
|
+
* Upper bound for the pixel data held only by undo / redo steps (tiles shared with the
|
|
1992
|
+
* current state are free). The oldest steps are dropped first. Default 512 MiB.
|
|
1371
1993
|
*/
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1994
|
+
maxHistoryBytes?: number;
|
|
1995
|
+
/** Viewport fit mode: 'contain' scales to full viewport bounds; 'margin' scales to 85% with 1.0 cap (default). */
|
|
1996
|
+
fit?: ImageEditorFit;
|
|
1997
|
+
}
|
|
1998
|
+
interface InpaintOptions {
|
|
1999
|
+
prompt: string;
|
|
2000
|
+
imageDataUrl: string;
|
|
2001
|
+
maskDataUrl?: string;
|
|
2002
|
+
cropBox?: CropBox | null;
|
|
2003
|
+
}
|
|
2004
|
+
interface RemoveBackgroundOptions {
|
|
2005
|
+
imageDataUrl: string;
|
|
2006
|
+
}
|
|
2007
|
+
type InpaintHook = (options: InpaintOptions) => Promise<string | void> | string | void;
|
|
2008
|
+
type RemoveBackgroundHook = (options: RemoveBackgroundOptions) => Promise<string | void> | string | void;
|
|
2009
|
+
interface ImageEditorAIHooks {
|
|
2010
|
+
onInpaint?: InpaintHook;
|
|
2011
|
+
onRemoveBackground?: RemoveBackgroundHook;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/**
|
|
2015
|
+
* Applies color and tone adjustments (brightness, contrast, saturation, exposure, temperature, tint,
|
|
2016
|
+
* opacity, then any adjustment `layers`, then blur) directly to the pixel data of an ImageData buffer.
|
|
2017
|
+
*
|
|
2018
|
+
* `adjustments.process` selects the rendering: `2` is the linear-light pipeline
|
|
2019
|
+
* ({@link applyProcess2Adjustments}); anything else (including a missing value, as in edits saved
|
|
2020
|
+
* before process versions existed) is the frozen legacy rendering ({@link applyLegacyAdjustments}).
|
|
2021
|
+
*/
|
|
2022
|
+
declare function applyAdjustments(imageData: ImageData, adjustments: ImageAdjustments, options?: {
|
|
2023
|
+
layerMasks?: ReadonlyMap<string, ArrayLike<number>>;
|
|
2024
|
+
}): void;
|
|
2025
|
+
/**
|
|
2026
|
+
* Process 1: the original 8-bit gamma-space rendering, clamping after every step. Frozen so
|
|
2027
|
+
* that edits saved without a `process` look exactly as they always have. `tint` is ignored.
|
|
2028
|
+
*/
|
|
2029
|
+
declare function applyLegacyAdjustments(imageData: {
|
|
2030
|
+
data: Uint8ClampedArray;
|
|
2031
|
+
}, adjustments: ImageAdjustments): void;
|
|
2032
|
+
/**
|
|
2033
|
+
* Process 2: decode sRGB to linear float once; apply exposure (gain) and white balance (a
|
|
2034
|
+
* Bradford matrix relative to as-shot) in linear light; a per-channel tone LUT for the
|
|
2035
|
+
* highlight shoulder, contrast and brightness; luminance-preserving saturation in linear light;
|
|
2036
|
+
* then encode back to sRGB through a LUT. Nothing is clamped between stages, only at the final
|
|
2037
|
+
* encode. Neutral settings are the identity.
|
|
2038
|
+
*/
|
|
2039
|
+
declare function applyProcess2Adjustments(imageData: {
|
|
2040
|
+
data: Uint8ClampedArray;
|
|
2041
|
+
}, adjustments: ImageAdjustments): void;
|
|
2042
|
+
/**
|
|
2043
|
+
* Fast separable box blur running horizontally and vertically (`adjustments.blur` and the `blur`
|
|
2044
|
+
* layer filter): `radius` pixels each side, edges clamped, rounded after each pass.
|
|
2045
|
+
*/
|
|
2046
|
+
declare function applyBoxBlur(imageData: {
|
|
2047
|
+
width: number;
|
|
2048
|
+
height: number;
|
|
2049
|
+
data: Uint8ClampedArray;
|
|
2050
|
+
}, radius: number): void;
|
|
2051
|
+
/**
|
|
2052
|
+
* Blends a depth/alpha mask into the main image data based on Gleamforge depth masking.
|
|
2053
|
+
* Supports threshold range with softness gradation, brightness mode, and optional inversion.
|
|
2054
|
+
*/
|
|
2055
|
+
declare function applyDepthMask(mainImageData: ImageData, maskImageData: ImageData, options: DepthMaskOptions): void;
|
|
2056
|
+
/**
|
|
2057
|
+
* Removes alpha channel by setting all alpha bytes to 255 (completely opaque).
|
|
2058
|
+
* From Gleamforge image-filters.ts.
|
|
2059
|
+
*/
|
|
2060
|
+
declare function removeAlpha(imageData: ImageData): void;
|
|
2061
|
+
|
|
2062
|
+
/**
|
|
2063
|
+
* Colour science for the image editor's process 2 rendering: sRGB transfer functions,
|
|
2064
|
+
* correlated colour temperature / tint (Kim et al. Planckian locus, tint as Duv), Bradford
|
|
2065
|
+
* white-balance adaptation relative to "as shot", and the display-referred tone curve.
|
|
2066
|
+
*/
|
|
2067
|
+
/** A CIE 1931 chromaticity. */
|
|
2068
|
+
interface Chromaticity {
|
|
2069
|
+
x: number;
|
|
2070
|
+
y: number;
|
|
1379
2071
|
}
|
|
2072
|
+
/** A row-major 3×3 matrix (`[m00, m01, m02, m10, …, m22]`). */
|
|
2073
|
+
type Matrix3 = [number, number, number, number, number, number, number, number, number];
|
|
2074
|
+
/** The rendering of adjustments from before process versions existed. Frozen. */
|
|
2075
|
+
declare const LEGACY_PROCESS_VERSION: 1;
|
|
2076
|
+
/** The process new edits and Reset get. */
|
|
2077
|
+
declare const LATEST_PROCESS_VERSION: 2;
|
|
2078
|
+
type ImageProcessVersion = 1 | 2;
|
|
2079
|
+
/**
|
|
2080
|
+
* Reads a stored process number leniently: a missing or damaged value (not a whole number) is
|
|
2081
|
+
* the legacy process, so a saved edit from before process versions renders exactly as it did. A
|
|
2082
|
+
* whole number newer than this build knows renders with the latest process.
|
|
2083
|
+
*/
|
|
2084
|
+
declare function normalizeProcessVersion(value: unknown): ImageProcessVersion;
|
|
2085
|
+
declare function srgbToLinear(v: number): number;
|
|
2086
|
+
declare function linearToSrgb(v: number): number;
|
|
2087
|
+
/** Rec.709 / sRGB luminance weights (linear light). */
|
|
2088
|
+
declare const LUMA_709: readonly [number, number, number];
|
|
2089
|
+
declare const IDENTITY_MATRIX3: Matrix3;
|
|
2090
|
+
declare function mulMatrix3(a: Matrix3, b: Matrix3): Matrix3;
|
|
2091
|
+
declare function applyMatrix3(m: Matrix3, v: readonly [number, number, number]): [number, number, number];
|
|
2092
|
+
declare function invertMatrix3(m: Matrix3): Matrix3 | null;
|
|
2093
|
+
declare const D65: Chromaticity;
|
|
2094
|
+
/** Bradford chromatic adaptation (XYZ → XYZ) from white `src` to white `dst`. */
|
|
2095
|
+
declare function bradfordAdaptation(src: Chromaticity, dst: Chromaticity): Matrix3;
|
|
2096
|
+
/**
|
|
2097
|
+
* Matrix (linear sRGB → linear sRGB) that white-balances a scene lit by `src` so that it
|
|
2098
|
+
* renders as if lit by D65.
|
|
2099
|
+
*/
|
|
2100
|
+
declare function wbMatrix(src: Chromaticity): Matrix3;
|
|
2101
|
+
/** The chromaticity of a linear sRGB colour. */
|
|
2102
|
+
declare function linearSrgbToXy(rgb: readonly [number, number, number]): Chromaticity;
|
|
2103
|
+
/** Tint units per unit of Duv. */
|
|
2104
|
+
declare const TINT_SCALE = 3000;
|
|
2105
|
+
declare const MIN_KELVIN = 1667;
|
|
2106
|
+
declare const MAX_KELVIN = 25000;
|
|
2107
|
+
/** CIE 1931 xy → CIE 1960 uv. */
|
|
2108
|
+
declare function xyToUv(p: Chromaticity): [number, number];
|
|
2109
|
+
/** CIE 1960 uv → CIE 1931 xy. */
|
|
2110
|
+
declare function uvToXy(u: number, v: number): Chromaticity;
|
|
2111
|
+
/**
|
|
2112
|
+
* Source illuminant chromaticity for temperature `kelvin` and correction `tint`.
|
|
2113
|
+
* Positive tint means a green source white, whose correction adds magenta to the image.
|
|
2114
|
+
*/
|
|
2115
|
+
declare function tempTintToXy(kelvin: number, tint: number): Chromaticity;
|
|
2116
|
+
/** Inverse of {@link tempTintToXy}: nearest locus temperature (searched in mired space) and tint. */
|
|
2117
|
+
declare function xyToTempTint(p: Chromaticity): {
|
|
2118
|
+
kelvin: number;
|
|
2119
|
+
tint: number;
|
|
2120
|
+
};
|
|
2121
|
+
/** Rendered images carry no as-shot white: "as shot" is 6500 K / tint 0 and maps to the identity. */
|
|
2122
|
+
declare const AS_SHOT_KELVIN = 6500;
|
|
2123
|
+
/** Mireds per unit of the `temperature` slider (−100…100). */
|
|
2124
|
+
declare const MIRED_PER_TEMPERATURE_UNIT = 1;
|
|
2125
|
+
/**
|
|
2126
|
+
* Maps the `temperature` slider (−100 cool … +100 warm) to the Kelvin white-balance setting:
|
|
2127
|
+
* one mired per unit around 6500 K, so 0 → 6500 K, +100 → ~18 570 K (a strong warming
|
|
2128
|
+
* correction), −100 → ~3 940 K (a strong cooling correction). Mireds are perceptually even,
|
|
2129
|
+
* so equal slider steps look like equal changes.
|
|
2130
|
+
*/
|
|
2131
|
+
declare function temperatureToKelvin(temperature: number): number;
|
|
2132
|
+
/** Inverse of {@link temperatureToKelvin}. */
|
|
2133
|
+
declare function kelvinToTemperature(kelvin: number): number;
|
|
2134
|
+
/**
|
|
2135
|
+
* White-balance matrix (linear sRGB) for the `temperature` / `tint` sliders, relative to
|
|
2136
|
+
* "as shot": the identity at 0 / 0. Normalised so neutral luminance is preserved (white
|
|
2137
|
+
* balance doesn't change exposure).
|
|
2138
|
+
*/
|
|
2139
|
+
declare function whiteBalanceMatrix(temperature: number, tint?: number): Matrix3;
|
|
2140
|
+
/**
|
|
2141
|
+
* Neutral-point eyedropper: the `temperature` / `tint` that render the sampled sRGB colour
|
|
2142
|
+
* (0–255 per channel, as it appears in the unadjusted image) neutral. Results are clamped to
|
|
2143
|
+
* the slider range −100…100.
|
|
2144
|
+
*/
|
|
2145
|
+
declare function whiteBalanceFromSample(rgb: readonly [number, number, number] | {
|
|
2146
|
+
r: number;
|
|
2147
|
+
g: number;
|
|
2148
|
+
b: number;
|
|
2149
|
+
}): {
|
|
2150
|
+
temperature: number;
|
|
2151
|
+
tint: number;
|
|
2152
|
+
};
|
|
2153
|
+
/** Number of intervals in a tone LUT (the table has `TONE_LUT_SIZE + 1` entries). */
|
|
2154
|
+
declare const TONE_LUT_SIZE = 4096;
|
|
2155
|
+
/**
|
|
2156
|
+
* The process 2 tone curve for one linear input value in `[0, headroom]`:
|
|
2157
|
+
*
|
|
2158
|
+
* 1. A highlight shoulder (extended Reinhard with white point `headroom`) above a knee of 0.6
|
|
2159
|
+
* rolls values above 1 (after exposure / white balance) back into range instead of clipping.
|
|
2160
|
+
* With no headroom (`headroom = 1`) it is exactly the identity.
|
|
2161
|
+
* 2. In a gamma-2.2 perceptual domain, contrast is an S-curve anchored at 0, middle grey and 1
|
|
2162
|
+
* (as `ToneMap::display`), and brightness a midtone lift anchored at 0 and 1.
|
|
2163
|
+
*
|
|
2164
|
+
* `contrast` and `brightness` are −100…100; both 0 with `headroom = 1` is the identity.
|
|
2165
|
+
*/
|
|
2166
|
+
declare function toneCurve(y: number, contrast: number, brightness: number, headroom?: number): number;
|
|
2167
|
+
/** Tabulates {@link toneCurve} over `[0, headroom]` in {@link TONE_LUT_SIZE} steps. */
|
|
2168
|
+
declare function buildToneLut(contrast: number, brightness: number, headroom?: number): Float32Array;
|
|
2169
|
+
/** Linearly interpolated lookup into a LUT from {@link buildToneLut}. */
|
|
2170
|
+
declare function sampleToneLut(lut: Float32Array, headroom: number, y: number): number;
|
|
1380
2171
|
|
|
1381
|
-
/** The `version` that `ImageEditorController.toJSON()` writes. */
|
|
1382
|
-
declare const IMAGE_EDITOR_STATE_VERSION = 1;
|
|
1383
2172
|
/**
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
2173
|
+
* The newest `version` that `ImageEditorController.toJSON()` writes (3: layers). Documents whose
|
|
2174
|
+
* layers still have the old shape are written as version 1 or 2.
|
|
2175
|
+
*/
|
|
2176
|
+
declare const IMAGE_EDITOR_STATE_VERSION = 3;
|
|
2177
|
+
/**
|
|
2178
|
+
* Migration steps for the document-level schema (versions 1 and 2), keyed by the version they
|
|
2179
|
+
* start from. Empty: version 2 only adds `adjustments.layers`, which version 1 readers keep.
|
|
1386
2180
|
*/
|
|
1387
2181
|
declare const imageEditorStateMigrations: Record<number, MigrationStep>;
|
|
1388
2182
|
interface ImageEditorDocumentLoad {
|
|
@@ -1547,7 +2341,9 @@ declare function evaluateAdjustmentLayers(color: readonly number[], layers: read
|
|
|
1547
2341
|
* scales each masked layer's opacity per pixel: coverage 0 leaves the pixel as the layers below
|
|
1548
2342
|
* made it, 1 applies the layer fully.
|
|
1549
2343
|
*/
|
|
1550
|
-
declare function applyAdjustmentLayers(imageData:
|
|
2344
|
+
declare function applyAdjustmentLayers(imageData: {
|
|
2345
|
+
data: Uint8ClampedArray;
|
|
2346
|
+
}, layers: readonly AdjustmentLayer[] | undefined, masks?: ReadonlyMap<string, ArrayLike<number>>): void;
|
|
1551
2347
|
/** Stable cache key of a layer stack's pixel effect (for renderer caches). */
|
|
1552
2348
|
declare function adjustmentLayersKey(layers: readonly AdjustmentLayer[] | undefined): string;
|
|
1553
2349
|
|
|
@@ -1792,6 +2588,24 @@ declare function createImageSelectionTools(controller: ImageEditorController): A
|
|
|
1792
2588
|
*/
|
|
1793
2589
|
declare function createImageEditTools(controller: ImageEditorController): AgentTool[];
|
|
1794
2590
|
|
|
2591
|
+
/** A short description of a mask for agents (no pixels). */
|
|
2592
|
+
declare function maskSummary(mask: RasterMask | undefined): Record<string, unknown> | null;
|
|
2593
|
+
/**
|
|
2594
|
+
* A plain description of a layer (and its children) for agents: ids, types, names, document
|
|
2595
|
+
* bounds, visibility, opacity, fill, blend, clipping, locks, mask summary and whether it is
|
|
2596
|
+
* active. `boundsOf` gives a pixel layer's document bounds.
|
|
2597
|
+
*/
|
|
2598
|
+
declare function describeLayer(layer: ImageLayer, activeId: string | null, boundsOf: (layer: ImageLayer) => CropBox | null): Record<string, unknown>;
|
|
2599
|
+
/**
|
|
2600
|
+
* Agent tools for the image editor's layer stack: `list_layers`, `set_active_layer`,
|
|
2601
|
+
* `add_pixel_layer`, `duplicate_layer`, `remove_layer`, `move_layer`, `set_layer_properties`,
|
|
2602
|
+
* `group_layers`, `ungroup_layer`, `merge_down`, `merge_visible`, `flatten_image`, `offset_layer`,
|
|
2603
|
+
* `add_layer_mask`, `apply_layer_mask`, `remove_layer_mask`, `set_layer_mask_properties`,
|
|
2604
|
+
* `layer_via_copy`, `add_layer_filter`, `update_layer_filter` and `remove_layer_filter`. Each write
|
|
2605
|
+
* is one undo step, validates before changing anything and returns what it changed.
|
|
2606
|
+
*/
|
|
2607
|
+
declare function createImageLayerTools(controller: ImageEditorController): AgentTool[];
|
|
2608
|
+
|
|
1795
2609
|
/**
|
|
1796
2610
|
* Region-based mosaic (pixelation) and box-blur filters for redacting or anonymizing
|
|
1797
2611
|
* rectangular bounding boxes on an ImageData-like buffer.
|
|
@@ -1842,4 +2656,277 @@ declare function applyRegionBlur<T extends MosaicImageDataLike>(imageData: T, re
|
|
|
1842
2656
|
*/
|
|
1843
2657
|
declare function createImageCaptureSurface(controller: ImageEditorController): CaptureSurface;
|
|
1844
2658
|
|
|
1845
|
-
|
|
2659
|
+
/**
|
|
2660
|
+
* Between the old document-level model (schema v1 / v2: base sliders, adjustment layers, blur,
|
|
2661
|
+
* depth mask and annotations) and the layer stack:
|
|
2662
|
+
*
|
|
2663
|
+
* - `layersFromLegacy` lifts a v1 / v2 state into layers: the source becomes the Background
|
|
2664
|
+
* pixel layer carrying the base sliders as its `develop` filter and the depth mask as its
|
|
2665
|
+
* parametric mask; adjustment layers go above it, annotations on top in their order. Blur
|
|
2666
|
+
* becomes a `blur` filter on the Background, or `legacyOutputBlur` when adjustment layers
|
|
2667
|
+
* exist (blur used to run after them).
|
|
2668
|
+
* - `legacyView` reads the stack back as `adjustments` / `depthMask` / `annotations` (the
|
|
2669
|
+
* compatibility views on the editor state) and says whether the stack still has exactly the
|
|
2670
|
+
* legacy shape, in which case it serializes as v1 / v2 byte for byte.
|
|
2671
|
+
*/
|
|
2672
|
+
|
|
2673
|
+
declare const BACKGROUND_LAYER_ID = "background";
|
|
2674
|
+
declare const BACKGROUND_LAYER_NAME = "Background";
|
|
2675
|
+
declare const DEVELOP_FILTER_ID = "develop";
|
|
2676
|
+
declare const BLUR_FILTER_ID = "blur";
|
|
2677
|
+
/** The old document-level parts of the editor state. */
|
|
2678
|
+
interface LegacyParts {
|
|
2679
|
+
adjustments: ImageAdjustments;
|
|
2680
|
+
depthMask: DepthMaskOptions;
|
|
2681
|
+
annotations: Annotation[];
|
|
2682
|
+
}
|
|
2683
|
+
/** The stack as stored at document level next to the layers. */
|
|
2684
|
+
interface LayerStack {
|
|
2685
|
+
layers: ImageLayer[];
|
|
2686
|
+
/** Export alpha (the old `adjustments.opacity`), 0..1. */
|
|
2687
|
+
outputOpacity: number;
|
|
2688
|
+
/** Migrated blur that must run after the adjustment layers (never created by new edits). */
|
|
2689
|
+
legacyOutputBlur?: number;
|
|
2690
|
+
}
|
|
2691
|
+
/** A raster mask from an old adjustment-layer mask, resampled to the document if needed. */
|
|
2692
|
+
declare function rasterMaskFromLegacy(mask: AdjustmentLayerMask, width: number, height: number): RasterMask | null;
|
|
2693
|
+
/**
|
|
2694
|
+
* True when an adjustment layer's mask came from a v1 / v2 mask of another size than the canvas
|
|
2695
|
+
* (the old renderer resampled it per render; the stack holds a canvas-sized copy).
|
|
2696
|
+
*/
|
|
2697
|
+
declare function hasResampledLegacyMask(layers: readonly ImageLayer[], width: number, height: number): boolean;
|
|
2698
|
+
/** The old mask shape of a raster mask (its pixels over the canvas, run-length encoded). */
|
|
2699
|
+
declare function legacyMaskOf(mask: RasterMask, width: number, height: number): AdjustmentLayerMask;
|
|
2700
|
+
/** True when the depth mask settings are the defaults (no mask at all). */
|
|
2701
|
+
declare function isDefaultDepthMask(mask: DepthMaskOptions | undefined): boolean;
|
|
2702
|
+
declare function developFromAdjustments(adjustments: ImageAdjustments): DevelopFilter;
|
|
2703
|
+
/** The default name of an annotation layer. */
|
|
2704
|
+
declare function annotationLayerName(annotation: Annotation): string;
|
|
2705
|
+
declare function annotationLayerFor(annotation: Annotation): AnnotationLayer;
|
|
2706
|
+
declare function adjustmentNodeFromLegacy(layer: AdjustmentLayer, width: number, height: number): AdjustmentLayerNode;
|
|
2707
|
+
/** The Background layer of an opened image (its pixels are the document source). */
|
|
2708
|
+
declare function backgroundLayer(filters?: LayerFilter[], mask?: RasterMask): PixelLayer;
|
|
2709
|
+
/** A parametric depth mask on a layer. */
|
|
2710
|
+
declare function depthRasterMask(source: DepthMaskOptions): RasterMask;
|
|
2711
|
+
/** Lifts a v1 / v2 state into a layer stack (see the module comment). */
|
|
2712
|
+
declare function layersFromLegacy(parts: Partial<LegacyParts>, width: number, height: number): LayerStack;
|
|
2713
|
+
/** The old `AdjustmentLayer` shape of a node, keys in the order `normalizeAdjustmentLayer` writes. */
|
|
2714
|
+
declare function legacyAdjustmentLayer(node: AdjustmentLayerNode, width: number, height: number): AdjustmentLayer;
|
|
2715
|
+
/** The pixel layer whose develop filter the legacy API edits: the active one, else the Background. */
|
|
2716
|
+
declare function developTarget(layers: readonly ImageLayer[], activeLayerId: string | null): PixelLayer | null;
|
|
2717
|
+
interface LegacyViewResult extends LegacyParts {
|
|
2718
|
+
/**
|
|
2719
|
+
* True when the stack has exactly the shape a v1 / v2 document lifts to (an unpainted,
|
|
2720
|
+
* unmoved Background with develop / blur filters and an optional depth mask, then adjustment
|
|
2721
|
+
* layers, then plain annotation layers), so it can be written as v1 / v2.
|
|
2722
|
+
*/
|
|
2723
|
+
exact: boolean;
|
|
2724
|
+
}
|
|
2725
|
+
/** Reads the stack back as the old document-level parts (see `LegacyViewResult`). */
|
|
2726
|
+
declare function legacyView(stack: LayerStack, width: number, height: number, activeLayerId?: string | null): LegacyViewResult;
|
|
2727
|
+
/** See `LegacyViewResult.exact`. */
|
|
2728
|
+
declare function isLegacyShape(stack: LayerStack): boolean;
|
|
2729
|
+
|
|
2730
|
+
/**
|
|
2731
|
+
* Pure helpers between the compositor and the renderer: the output stage (projection to the
|
|
2732
|
+
* cropped, rotated frame, output opacity and the migrated blur), the routing rule that keeps
|
|
2733
|
+
* old-shape documents on the exact legacy path where document-space compositing cannot match it,
|
|
2734
|
+
* and per-tile histograms. No DOM.
|
|
2735
|
+
*/
|
|
2736
|
+
|
|
2737
|
+
/** True for 0, 90, 180 and 270 degrees. */
|
|
2738
|
+
declare function isQuarterTurn(rotate: number): boolean;
|
|
2739
|
+
/** The projection that draws `region` into a `baseW × baseH` buffer at scale 1 (the renderer's base canvas). */
|
|
2740
|
+
declare function baseProjection(region: CropBox, transform: ImageTransform, baseW: number, baseH: number): ImageProjection;
|
|
2741
|
+
/**
|
|
2742
|
+
* Projects `src` (RGBA covering `srcRect` in document space) into the base frame of `region`
|
|
2743
|
+
* under a quarter-turn `transform`: an exact pixel permutation (crop, flips, 90° steps), the
|
|
2744
|
+
* same mapping the canvas draws with. Returns the base buffer and its size.
|
|
2745
|
+
*/
|
|
2746
|
+
declare function projectQuarterTurn(src: ArrayLike<number>, srcRect: CropBox, region: CropBox, transform: ImageTransform): {
|
|
2747
|
+
width: number;
|
|
2748
|
+
height: number;
|
|
2749
|
+
data: Uint8ClampedArray;
|
|
2750
|
+
};
|
|
2751
|
+
/** Output opacity as the old base adjustments applied it (`clamp(a · opacity)`), then the migrated blur. */
|
|
2752
|
+
declare function applyOutputStage(img: {
|
|
2753
|
+
width: number;
|
|
2754
|
+
height: number;
|
|
2755
|
+
data: Uint8ClampedArray;
|
|
2756
|
+
}, opacity: number, legacyOutputBlur?: number): void;
|
|
2757
|
+
interface RouteInput {
|
|
2758
|
+
stack: LayerStack;
|
|
2759
|
+
region: CropBox;
|
|
2760
|
+
canvas: {
|
|
2761
|
+
width: number;
|
|
2762
|
+
height: number;
|
|
2763
|
+
};
|
|
2764
|
+
transform: ImageTransform;
|
|
2765
|
+
/** Whether the source image is fully opaque. */
|
|
2766
|
+
sourceOpaque: boolean;
|
|
2767
|
+
}
|
|
2768
|
+
/**
|
|
2769
|
+
* Whether a document must render through the legacy base path to look exactly as before. Only
|
|
2770
|
+
* documents that still have the v1 / v2 shape qualify, and only where compositing in document
|
|
2771
|
+
* space cannot reproduce the old order of operations:
|
|
2772
|
+
*
|
|
2773
|
+
* - a rotation that is not a quarter turn, or a crop with fractional coordinates (the old path
|
|
2774
|
+
* resampled before adjusting);
|
|
2775
|
+
* - an enabled depth mask (applied after the blur and resampled with the canvas);
|
|
2776
|
+
* - output opacity below 1 (it rounded alpha before the depth mask);
|
|
2777
|
+
* - a Background blur filter with a crop or a 90° / 270° turn (the old blur clamped at the crop
|
|
2778
|
+
* edge and ran on the rotated buffer);
|
|
2779
|
+
* - a migrated output blur over a source with transparency (canvas premultiplication would round
|
|
2780
|
+
* colours before blurring);
|
|
2781
|
+
* - an adjustment-layer mask stored at another size than the canvas (it was resampled through
|
|
2782
|
+
* the projection on every render).
|
|
2783
|
+
*/
|
|
2784
|
+
declare function needsLegacyBase(input: RouteInput): boolean;
|
|
2785
|
+
/**
|
|
2786
|
+
* Splits the stack into what the compositor rasterizes and the annotation layers at the top that
|
|
2787
|
+
* draw as crisp vectors over the result (as annotations always did): the trailing run of plain
|
|
2788
|
+
* top-level annotation layers (hidden ones are skipped).
|
|
2789
|
+
*/
|
|
2790
|
+
declare function splitOverlayAnnotations(layers: readonly ImageLayer[]): {
|
|
2791
|
+
composite: ImageLayer[];
|
|
2792
|
+
overlay: AnnotationLayer[];
|
|
2793
|
+
};
|
|
2794
|
+
/** The integer rectangle covering `region`. */
|
|
2795
|
+
declare function coveringRect(region: CropBox): CropBox;
|
|
2796
|
+
/**
|
|
2797
|
+
* The base image of a layered document without a canvas: the stack composited over `region`
|
|
2798
|
+
* (integer), projected under a quarter-turn `transform`, then output opacity and the migrated
|
|
2799
|
+
* blur. Annotation layers need a canvas and are skipped unless `sources` can rasterize them.
|
|
2800
|
+
* This is what the renderer's base canvas holds for such documents.
|
|
2801
|
+
*/
|
|
2802
|
+
declare function renderLayeredBase(stack: LayerStack, region: CropBox, transform: ImageTransform, sources: CompositorSources, compositor?: LayerCompositor): {
|
|
2803
|
+
width: number;
|
|
2804
|
+
height: number;
|
|
2805
|
+
data: Uint8ClampedArray;
|
|
2806
|
+
};
|
|
2807
|
+
/** An empty histogram. */
|
|
2808
|
+
declare function emptyHistogram(): ImageHistogram;
|
|
2809
|
+
/** Adds the pixels of `rect` (in tile-local coordinates of a `stride`-wide RGBA buffer) to `h`. */
|
|
2810
|
+
declare function addToHistogram(h: ImageHistogram, data: ArrayLike<number>, stride: number, rect: CropBox): void;
|
|
2811
|
+
/** Sums histograms (and recomputes `max`). */
|
|
2812
|
+
declare function sumHistograms(parts: Iterable<ImageHistogram>): ImageHistogram;
|
|
2813
|
+
|
|
2814
|
+
/**
|
|
2815
|
+
* The layers panel's view model, shared by the React and Svelte panels: the rows to show (top of
|
|
2816
|
+
* the stack first, groups indented, collapsed groups hiding their children), where a drop lands,
|
|
2817
|
+
* and the menu of layer operations with whether each one applies to the active layer.
|
|
2818
|
+
*/
|
|
2819
|
+
|
|
2820
|
+
interface LayerPanelRow {
|
|
2821
|
+
layer: ImageLayer;
|
|
2822
|
+
/** Nesting depth (0 = top level). */
|
|
2823
|
+
depth: number;
|
|
2824
|
+
parentId: string | null;
|
|
2825
|
+
/** Index among its siblings, 0 = bottom. */
|
|
2826
|
+
index: number;
|
|
2827
|
+
active: boolean;
|
|
2828
|
+
/** Display name (adjustment layers without a name show their kind). */
|
|
2829
|
+
label: string;
|
|
2830
|
+
/** Clipped to the layer below (drawn with an indent arrow). */
|
|
2831
|
+
clipped: boolean;
|
|
2832
|
+
}
|
|
2833
|
+
/** Rows top to bottom; children of collapsed groups are left out. */
|
|
2834
|
+
declare function layerPanelRows(layers: readonly ImageLayer[], activeId: string | null): LayerPanelRow[];
|
|
2835
|
+
declare function layerLabel(layer: ImageLayer): string;
|
|
2836
|
+
/** A short type badge for rows without a thumbnail. */
|
|
2837
|
+
declare function layerBadge(layer: ImageLayer): string;
|
|
2838
|
+
/** Where a row was dropped on: the top or bottom part of the row, or the middle of a group row. */
|
|
2839
|
+
type DropZone = 'above' | 'below' | 'inside';
|
|
2840
|
+
/** The zone for a pointer at `fraction` (0 top .. 1 bottom) of a row's height. */
|
|
2841
|
+
declare function dropZone(fraction: number, isGroup: boolean): DropZone;
|
|
2842
|
+
/** The placement for `move_layer` when `dragId` is dropped on row `targetId` in `zone`, or `null` for a no-op. */
|
|
2843
|
+
declare function dropPlacement(layers: readonly ImageLayer[], dragId: string, targetId: string, zone: DropZone): LayerPlacement | null;
|
|
2844
|
+
type LayerMenuAction = 'new-layer' | 'new-group' | 'duplicate' | 'delete' | 'group-selected' | 'ungroup' | 'merge-down' | 'merge-visible' | 'flatten' | 'via-copy' | 'via-cut' | 'add-mask' | 'add-mask-selection' | 'apply-mask' | 'delete-mask' | 'toggle-mask' | 'toggle-clip';
|
|
2845
|
+
interface LayerMenuItem {
|
|
2846
|
+
action: LayerMenuAction;
|
|
2847
|
+
label: string;
|
|
2848
|
+
enabled: boolean;
|
|
2849
|
+
}
|
|
2850
|
+
/** The layer menu for the controller's current state (active layer, selection). */
|
|
2851
|
+
declare function layerMenu(controller: ImageEditorController): LayerMenuItem[];
|
|
2852
|
+
/** Runs a menu action on the active layer. Resolves to the error message when it was refused. */
|
|
2853
|
+
declare function runLayerMenuAction(controller: ImageEditorController, action: LayerMenuAction): Promise<string | null>;
|
|
2854
|
+
|
|
2855
|
+
/**
|
|
2856
|
+
* Agent tools for painting: `paint_stroke` (brush or eraser along points, on pixels or a mask),
|
|
2857
|
+
* `fill_pixels` and `clear_pixels` (Edit › Fill / Clear inside the selection). Each is one undo
|
|
2858
|
+
* step and returns the layer, channel and changed bounds.
|
|
2859
|
+
*/
|
|
2860
|
+
declare function createImagePaintTools(controller: ImageEditorController): AgentTool[];
|
|
2861
|
+
|
|
2862
|
+
/**
|
|
2863
|
+
* The paint tools' view model, shared by the React and Svelte editors: the brush options bar's
|
|
2864
|
+
* controls, Photoshop's shortcuts (B, E, V, [ ], Shift+[ ], number keys, D, X) and a pointer
|
|
2865
|
+
* gesture that turns pointer events into strokes (Brush, Eraser) or layer moves (Move).
|
|
2866
|
+
*/
|
|
2867
|
+
|
|
2868
|
+
/** Controls of the brush options bar (`hardness`, `opacity`, `flow`, `smoothing` shown in %). */
|
|
2869
|
+
declare const BRUSH_OPTION_CONTROLS: readonly (ControlSpec & {
|
|
2870
|
+
id: 'size' | 'hardness' | 'opacity' | 'flow' | 'smoothing';
|
|
2871
|
+
})[];
|
|
2872
|
+
/** The paint tools in the toolbar. */
|
|
2873
|
+
declare const PAINT_TOOLS: readonly [{
|
|
2874
|
+
readonly id: "move";
|
|
2875
|
+
readonly label: "Move";
|
|
2876
|
+
readonly shortcut: "V";
|
|
2877
|
+
}, {
|
|
2878
|
+
readonly id: "brush";
|
|
2879
|
+
readonly label: "Brush";
|
|
2880
|
+
readonly shortcut: "B";
|
|
2881
|
+
}, {
|
|
2882
|
+
readonly id: "eraser";
|
|
2883
|
+
readonly label: "Eraser";
|
|
2884
|
+
readonly shortcut: "E";
|
|
2885
|
+
}];
|
|
2886
|
+
type PaintTool = (typeof PAINT_TOOLS)[number]['id'];
|
|
2887
|
+
declare const isPaintTool: (tool: string) => tool is PaintTool;
|
|
2888
|
+
interface ShortcutEvent {
|
|
2889
|
+
key: string;
|
|
2890
|
+
shiftKey?: boolean;
|
|
2891
|
+
ctrlKey?: boolean;
|
|
2892
|
+
metaKey?: boolean;
|
|
2893
|
+
altKey?: boolean;
|
|
2894
|
+
/** The event target: shortcuts are ignored while typing in inputs. */
|
|
2895
|
+
target?: unknown;
|
|
2896
|
+
}
|
|
2897
|
+
/**
|
|
2898
|
+
* Applies a paint shortcut. Returns true when it was one (the caller then prevents the default).
|
|
2899
|
+
* B / E / V choose the tool; [ and ] change the size, with Shift the hardness by 25 %; 1..9 set the
|
|
2900
|
+
* opacity to 10..90 % and 0 to 100 %; D resets the colours to black and white; X swaps them.
|
|
2901
|
+
*/
|
|
2902
|
+
declare function handlePaintShortcut(controller: ImageEditorController, e: ShortcutEvent): boolean;
|
|
2903
|
+
/** One pointer sample in document pixels. */
|
|
2904
|
+
interface PaintPointerSample extends ImagePoint {
|
|
2905
|
+
/** 0..1; a mouse is 1. */
|
|
2906
|
+
pressure: number;
|
|
2907
|
+
}
|
|
2908
|
+
/** Pressure of a pointer event: pens report it; mice report 0.5 while pressed, which means "full". */
|
|
2909
|
+
declare function pointerPressure(e: {
|
|
2910
|
+
pointerType?: string;
|
|
2911
|
+
pressure?: number;
|
|
2912
|
+
}): number;
|
|
2913
|
+
/**
|
|
2914
|
+
* Turns pointer events into strokes (Brush, Eraser on the active layer's target) or layer moves
|
|
2915
|
+
* (Move on the active pixel layer). `down` returns an error message when the tool cannot act.
|
|
2916
|
+
*/
|
|
2917
|
+
declare class PaintGesture {
|
|
2918
|
+
private readonly controller;
|
|
2919
|
+
private stroke;
|
|
2920
|
+
private move;
|
|
2921
|
+
/** The last refusal (e.g. "layer is locked"), for the editor to show. */
|
|
2922
|
+
error: string | null;
|
|
2923
|
+
constructor(controller: ImageEditorController);
|
|
2924
|
+
get active(): boolean;
|
|
2925
|
+
down(sample: PaintPointerSample): string | null;
|
|
2926
|
+
/** Feeds pointer samples (all coalesced events of one move, in order). */
|
|
2927
|
+
moveTo(samples: PaintPointerSample[]): void;
|
|
2928
|
+
up(): void;
|
|
2929
|
+
cancel(): void;
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
export { ADJUSTMENT_KINDS, ADJUSTMENT_LAYER_CONTROLS, ADJUSTMENT_LAYER_OPACITY_CONTROL, ADJUSTMENT_LUT_SIZE, AS_SHOT_KELVIN, type AdjustmentKind, type AdjustmentKindInfo, type AdjustmentLayer, type AdjustmentLayerBase, type AdjustmentLayerInit, type AdjustmentLayerMask, type AdjustmentLayerNode, type AdjustmentLayerOf, type AdjustmentLayerUpdate, type AdjustmentParamsMap, type Annotation, type AnnotationLayer, type AnnotationPlacement, type AnnotationType, type ArrowAnnotation, type AspectRatio, BACKGROUND_LAYER_ID, BACKGROUND_LAYER_NAME, BLUR_FILTER_ID, BRUSH_OPTION_CONTROLS, type BaseAnnotation, type BlackWhiteParams, BlendMode, type BlurFilter, BrushSettings, type Chromaticity, type CircleAnnotation, type ColorBalanceParams, type ColorBalanceTone, type ColorDistance, type ColorRangeOptions, type ColorRangeSample, CompositorOptions, type CompositorSources, type ControlSection, type ControlSpec, type ControlTrack, type CreateAnnotationPayload, type CropBox, type CropHandle, type CurvePoint, type CurvesParams, D65, DEFAULT_ADJUSTMENTS, DEFAULT_DEPTH_MASK, DEFAULT_REFINE_EDGE_PARAMS, DEFAULT_SELECTION_TOOL_OPTIONS, DEFAULT_TRANSFORM, DEVELOP_FILTER_ID, type DepthMaskOptions, type DeserializeContext, type DevelopFilter, type DevelopSettings, type DropZone, EMPTY_DISTANCE, type ExportOptions, type FillOptions, GUIDED_FILTER_EPS, type GestureModifiers, type GroupLayer, HISTOGRAM_BINS, HUE_RANGE_LABELS, type HistogramChannel, type HistoryEntryHandle, type HueRange, type HueSaturationParams, IDENTITY_MATRIX3, IMAGE_ADJUSTMENT_CONTROLS, IMAGE_EDITOR_SCHEMA_VERSION, IMAGE_EDITOR_STATE_VERSION, type ImageAdjustments, type ImageAnnotation, type ImageDimensions, type ImageEditorAIHooks, ImageEditorController, type ImageEditorDocumentLoad, type ImageEditorFit, type ImageEditorOptions, ImageEditorRenderer, type ImageEditorState, type ImageEditorTool, type ImageEditorToolProviderOptions, type ImageHistogram, type ImageLayer, type ImageLayerType, type ImagePoint, type ImageProcessVersion, type ImageProjection, type ImageTransform, type InpaintHook, type InpaintOptions, type InvertParams, LATEST_PROCESS_VERSION, LAYERED_SCHEMA_VERSION, LEGACY_PROCESS_VERSION, LUMA_709, type LayerBase, type LayerBlendMode, LayerCompositor, type LayerFilter, type LayerFilterKind, type LayerLocation, LayerLocks, type LayerMaskProps, type LayerMenuAction, type LayerMenuItem, LayerOperationError, type LayerPanelRow, type LayerPlacement, type LayerProperties, type LayerSourcesHost, type LayerStack, type LayerTarget, type LegacyParts, type LegacySerializedImageEditorState, type LegacyViewResult, type LevelsChannel, type LevelsParams, type LineAnnotation, MAX_KELVIN, MIN_KELVIN, MIRED_PER_TEMPERATURE_UNIT, type MagicWandOptions, type Matrix3, type MosaicImageDataLike, type MosaicRegion, PAINT_TOOLS, PaintGesture, type PaintOptions, type PaintPointerSample, type PaintStrokeResult, PaintStrokeSession, type PaintTool, type PenAnnotation, type PhotoFilterParams, type PixelBuffer, type PixelLayer, type PixelLayerInit, type PixelOp, PixelSurface, type PosterizeParams, type QuickMaskStyle, REFINE_EDGE_CONTROLS, type RasterMask, type RectAnnotation, type RefineEdgeControl, type RefineEdgeParams, type RemoveBackgroundHook, type RemoveBackgroundOptions, type RenderOptions, type RouteInput, SELECTION_MODES, SELECTION_MODE_LABELS, SELECTION_MODIFY_OPS, SELECTION_TOOLS, type SampleOptions, type SelectionChannel, type SelectionCommandOptions, SelectionGesture, type SelectionMask, type SelectionMode, type SelectionModifyOp, type SelectionToolKind, type SelectionToolOptions, type SerializeContext, type SerializedAdjustmentLayer, type SerializedAnnotationLayer, type SerializedGroupLayer, type SerializedImageEditorState, type SerializedLayer, type SerializedLayeredImageEditorState, type SerializedPixelLayer, type SerializedRasterMask, type SerializedSelection, type ShapeSelectionOptions, type ShortcutEvent, StrokeApply, StrokeCoverage, type StrokeInit, StrokePoint, TINT_SCALE, TONE_LUT_SIZE, TONE_RANGE_PRESETS, type TextAnnotation, type ThresholdParams, TiledSurface, type ToneRangePreset, type UnitLevels, VIBRANCE_GREY, type VibranceParams, type ViewportMetrics, activeAdjustmentLayers, addLayerFilter, addToHistogram, adjustmentKindLabel, adjustmentLayersKey, adjustmentNodeAsLayer, adjustmentNodeFromLegacy, annotationLayerFor, annotationLayerName, applyAdjustmentLayers, applyAdjustments, applyBoxBlur, applyDepthMask, applyImageProjectionToContext, applyLegacyAdjustments, applyMatrix3, applyOutputStage, applyProcess2Adjustments, applyRegionBlur, applyRegionMosaic, backgroundLayer, baseProjection, blackWhiteGray, blurFilter, borderCoverage, boxMean, boxToCurvePoint, bradfordAdaptation, buildLayerMaskPlanes, buildToneLut, calculateCropDrag, canvasToImagePoint, clampControlValue, clampCropToImage, colorBalanceChannel, colorRange, combineSelections, compileAdjustmentLayer, computeHistogram, computeSelectionBounds, contractCoverage, controlPosition, controlTrackBackground, coverageToByte, coveringRect, createAdjustmentLayer, createImageCaptureSurface, createImageEditTools, createImageEditorToolProvider, createImageLayerTools, createImagePaintTools, createImageSelectionTools, createSelectionMask, curveLut, curveLutFromLevels, curvePointToBox, curveSvgPath, decodeLayerMask, decodePngDataUrl, decodeSelectionRle, defaultAdjustmentParams, depthMaskAlpha, depthRasterMask, describeLayer, describeSelection, deserializeLayer, deserializeLayers, deserializeSelection, developFilter, developFromAdjustments, developTarget, distanceTransform, dropPlacement, dropZone, duplicateLayer, edgeWidth, ellipsePoints, ellipseSelection, emptyHistogram, encodeSelectionRle, encodeSurface, evaluateAdjustmentLayers, expandCoverage, featherCoverage, findAdjustmentControl, findLayerControl, formatControlValue, fullSelection, getAnnotationBounds, getControlPath, getCropCursor, getRotatedSize, getViewportMetrics, getViewportProjection, globalImageCache, greyMorphology, groupLayers, guidePlanes, guidedFilterColor, handlePaintShortcut, hasResampledLegacyMask, hashMaskContent, hexToRgb, histogramPath, hitTestAnnotation, hitTestCrop, hitTestCurvePoint, hslToRgb, hueRange, hueRangeTables, hueRangeWeight, hueSaturation, identityCurve, identityLevels, imageEditorStateMigrations, imageToCanvasPoint, insertCurvePoint, invertMatrix3, invertSelection, isActiveFilter, isAdjustmentKind, isDefaultDepthMask, isLegacyShape, isPaintTool, isQuarterTurn, isQuarterTurnSwapped, isSelectionEmpty, isSelectionMode, isSpatialFilter, kelvinToTemperature, layerBadge, layerLabel, layerMaskCoverage, layerMaskFromSelection, layerMaskKey, layerMenu, layerPanelRows, layerTypeLabel, layersFromLegacy, legacyAdjustmentLayer, legacyMaskOf, legacyView, levelsValue, linearSrgbToXy, linearToSrgb, loadImageEditorDocument, magicWand, mapCropHandle, maskSummary, migrateSerializedImageEditorState, migrateToLayeredState, modifySelection, moveCurvePoint, moveLayer, mulMatrix3, needsLegacyBase, neutralHueRange, newLayerId, normalizeAdjustmentLayer, normalizeAdjustmentLayers, normalizeAngle, normalizeFilter, normalizeLayerMask, normalizeProcessVersion, normalizeRect, normalizeRefineEdgeParams, normalizeStoredAdjustments, offsetLayer, parseBlend, parseColor, parseSelectionMode, photoFilterMatrix, pixelLayerBounds, pixelLayers, placeLayer, pointerPressure, polygonCoverage, polygonSelection, posterizeValue, projectImagePoint, projectImageRect, projectMaskCoverage, projectQuarterTurn, quickMaskPixels, rangeLightness, rasterMaskFromLegacy, readAdjustmentControls, rectSelection, refineCoverage, refineEdgeHalo, refineSelection, removeAlpha, removeCurvePoint, removeLayer, removeLayerFilter, renderLayeredBase, requireLayer, requireUnlocked, resizeSelection, resolveMosaicRegionBounds, rgbToGray, rgbToHsl, runLayerMenuAction, sampleLut, sampleToneLut, selectionArea, selectionFromCoverage, selectionFromPixels, selectionModeFromModifiers, selectionOutline, selectionToCoverage, selectionToPixels, selectionValueAt, serializeLayer, serializeLayers, serializeSelection, setControlPath, setLayerMask, setLayerProperties, shiftCoverage, smoothCoverage, splitOverlayAnnotations, srgb8ToLab, srgbToLinear, sumHistograms, tempTintToXy, temperatureToKelvin, toHex, toneCurve, toneLuts, toneRange, ungroupLayer, unionRect, unprojectCanvasPoint, updateLayerFilter, updateLayerMaskProps, uvToXy, vibranceLinear, vibrancePixel, wbMatrix, whiteBalanceFromSample, whiteBalanceMatrix, withNewIds, xyToTempTint, xyToUv };
|