@pixerate/editor 0.187.0 → 0.188.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-FW7N64XK.js → chunk-IGMNJM2H.js} +221 -20
- package/dist/{chunk-X2KQQZBT.cjs → chunk-JYV4R62M.cjs} +381 -180
- package/dist/image-editor/controller.d.cts +3 -3
- package/dist/image-editor/controller.d.ts +3 -3
- package/dist/image-editor/index.cjs +729 -714
- package/dist/image-editor/index.js +59 -44
- package/dist/image-editor/selection/mask.d.cts +20 -1
- package/dist/image-editor/selection/mask.d.ts +20 -1
- package/dist/image-editor/selection/shapes.d.cts +8 -0
- package/dist/image-editor/selection/shapes.d.ts +8 -0
- package/dist/image-editor/selection/tool-options.d.cts +1 -1
- package/dist/image-editor/selection/tool-options.d.ts +1 -1
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
|
@@ -298,6 +298,8 @@ import {
|
|
|
298
298
|
selectionArea,
|
|
299
299
|
selectionFromCoverage,
|
|
300
300
|
selectionFromPixels,
|
|
301
|
+
selectionFromRegion,
|
|
302
|
+
selectionFromTiles,
|
|
301
303
|
selectionToCoverage,
|
|
302
304
|
selectionToPixels,
|
|
303
305
|
selectionValueAt,
|
|
@@ -370,7 +372,7 @@ import {
|
|
|
370
372
|
writePsd,
|
|
371
373
|
xyToTempTint,
|
|
372
374
|
xyToUv
|
|
373
|
-
} from "../chunk-
|
|
375
|
+
} from "../chunk-IGMNJM2H.js";
|
|
374
376
|
import {
|
|
375
377
|
parseCssColor
|
|
376
378
|
} from "../chunk-3CI7FRMK.js";
|
|
@@ -2835,8 +2837,33 @@ var TypeToolGesture = class {
|
|
|
2835
2837
|
|
|
2836
2838
|
// src/image-editor/selection/shapes.ts
|
|
2837
2839
|
function polygonCoverage(points, width, height, antiAlias = true) {
|
|
2840
|
+
const { box, coverage } = polygonCoverageBox(points, width, height, antiAlias);
|
|
2841
|
+
if (!box || box.width === width && box.height === height) return box ? coverage : new Float32Array(width * height);
|
|
2838
2842
|
const m = new Float32Array(width * height);
|
|
2839
|
-
|
|
2843
|
+
for (let y = 0; y < box.height; y++) m.set(coverage.subarray(y * box.width, (y + 1) * box.width), (box.y + y) * width + box.x);
|
|
2844
|
+
return m;
|
|
2845
|
+
}
|
|
2846
|
+
function polygonCoverageBox(points, width, height, antiAlias = true) {
|
|
2847
|
+
const none = { box: null, coverage: new Float32Array(0) };
|
|
2848
|
+
if (points.length < 3 || width <= 0 || height <= 0) return none;
|
|
2849
|
+
let minX = Infinity;
|
|
2850
|
+
let minY = Infinity;
|
|
2851
|
+
let maxX = -Infinity;
|
|
2852
|
+
let maxY = -Infinity;
|
|
2853
|
+
for (const p of points) {
|
|
2854
|
+
if (!Number.isFinite(p.x) || !Number.isFinite(p.y)) continue;
|
|
2855
|
+
minX = Math.min(minX, p.x);
|
|
2856
|
+
minY = Math.min(minY, p.y);
|
|
2857
|
+
maxX = Math.max(maxX, p.x);
|
|
2858
|
+
maxY = Math.max(maxY, p.y);
|
|
2859
|
+
}
|
|
2860
|
+
const bx0 = Math.max(0, Math.floor(minX));
|
|
2861
|
+
const by0 = Math.max(0, Math.floor(minY));
|
|
2862
|
+
const bx1 = Math.min(width, Math.ceil(maxX));
|
|
2863
|
+
const by1 = Math.min(height, Math.ceil(maxY));
|
|
2864
|
+
if (!(bx1 > bx0 && by1 > by0)) return none;
|
|
2865
|
+
const bw = bx1 - bx0;
|
|
2866
|
+
const m = new Float32Array(bw * (by1 - by0));
|
|
2840
2867
|
const sub2 = antiAlias ? 4 : 1;
|
|
2841
2868
|
const edges = [];
|
|
2842
2869
|
for (let i = 0; i < points.length; i++) {
|
|
@@ -2850,8 +2877,8 @@ function polygonCoverage(points, width, height, antiAlias = true) {
|
|
|
2850
2877
|
let next = 0;
|
|
2851
2878
|
let active = [];
|
|
2852
2879
|
const xs = [];
|
|
2853
|
-
for (let py =
|
|
2854
|
-
const row = py *
|
|
2880
|
+
for (let py = by0; py < by1; py++) {
|
|
2881
|
+
const row = (py - by0) * bw - bx0;
|
|
2855
2882
|
for (let s = 0; s < sub2; s++) {
|
|
2856
2883
|
const y = py + (s + 0.5) / sub2;
|
|
2857
2884
|
while (next < edges.length && edges[next].top <= y) active.push(edges[next++]);
|
|
@@ -2881,15 +2908,14 @@ function polygonCoverage(points, width, height, antiAlias = true) {
|
|
|
2881
2908
|
}
|
|
2882
2909
|
}
|
|
2883
2910
|
for (let i = 0; i < m.length; i++) if (m[i] > 1) m[i] = 1;
|
|
2884
|
-
return m;
|
|
2911
|
+
return { box: { x: bx0, y: by0, width: bw, height: by1 - by0 }, coverage: m };
|
|
2885
2912
|
}
|
|
2886
|
-
function
|
|
2913
|
+
function polygonSelection(width, height, points, options = {}) {
|
|
2914
|
+
const { box, coverage } = polygonCoverageBox(points, width, height, options.antiAlias ?? true);
|
|
2915
|
+
if (!box) return createSelectionMask(width, height);
|
|
2887
2916
|
const out = new Uint8Array(coverage.length);
|
|
2888
2917
|
for (let i = 0; i < out.length; i++) out[i] = coverageToByte(coverage[i]);
|
|
2889
|
-
return
|
|
2890
|
-
}
|
|
2891
|
-
function polygonSelection(width, height, points, options = {}) {
|
|
2892
|
-
return toMask(width, height, polygonCoverage(points, width, height, options.antiAlias ?? true));
|
|
2918
|
+
return selectionFromRegion(width, height, box, out);
|
|
2893
2919
|
}
|
|
2894
2920
|
function normalizeRect(rect) {
|
|
2895
2921
|
const x = rect.width < 0 ? rect.x + rect.width : rect.x;
|
|
@@ -3531,9 +3557,7 @@ function selectionRing(sel, width, location) {
|
|
|
3531
3557
|
var DEFAULT_CHANNEL_COLOR = "#ff0000";
|
|
3532
3558
|
function describeChannel(channel) {
|
|
3533
3559
|
const { mask, ...rest } = channel;
|
|
3534
|
-
|
|
3535
|
-
for (let i = 0; i < mask.data.length; i++) sum += mask.data[i];
|
|
3536
|
-
const percent = Math.round(sum / 255 / Math.max(1, mask.data.length) * 1e4) / 100;
|
|
3560
|
+
const percent = Math.round(selectionArea(mask) / Math.max(1, mask.width * mask.height) * 1e4) / 100;
|
|
3537
3561
|
return { ...rest, bounds: mask.bounds, percent };
|
|
3538
3562
|
}
|
|
3539
3563
|
function serializeChannels(channels) {
|
|
@@ -4144,8 +4168,7 @@ var FreeTransformSession = class {
|
|
|
4144
4168
|
const result = part.base ? compositeSurfaceOver(part.base, moved) : moved;
|
|
4145
4169
|
if (part.what === "selection") {
|
|
4146
4170
|
const { width, height } = this.host.canvas();
|
|
4147
|
-
const
|
|
4148
|
-
const next = createSelectionMask(width, height, data);
|
|
4171
|
+
const next = selectionFromTiles(width, height, result);
|
|
4149
4172
|
selection = next.bounds ? next : null;
|
|
4150
4173
|
} else if (part.what === "pixels") {
|
|
4151
4174
|
layers = mapLayer(layers, targetId, (l) => {
|
|
@@ -5471,14 +5494,18 @@ var ImageEditorController = class {
|
|
|
5471
5494
|
this.trimHistoryBytes();
|
|
5472
5495
|
}
|
|
5473
5496
|
/**
|
|
5474
|
-
* Bytes of pixel tiles held only by undo / redo steps (not by the
|
|
5475
|
-
* undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
5497
|
+
* Bytes of pixel, selection and channel tiles held only by undo / redo steps (not by the
|
|
5498
|
+
* current state). The oldest undo steps are dropped while it exceeds `maxHistoryBytes`.
|
|
5476
5499
|
*/
|
|
5477
5500
|
get historyBytes() {
|
|
5478
5501
|
const live = /* @__PURE__ */ new Set();
|
|
5479
5502
|
collectStateTiles(this.state.layers, live);
|
|
5503
|
+
collectSelectionTiles(this.state.selection, this.state.channels, live);
|
|
5480
5504
|
const held = /* @__PURE__ */ new Set();
|
|
5481
|
-
for (const e of [...this.undoStack, ...this.redoStack])
|
|
5505
|
+
for (const e of [...this.undoStack, ...this.redoStack]) {
|
|
5506
|
+
collectStateTiles(e.layers, held);
|
|
5507
|
+
collectSelectionTiles(e.selection, e.channels, held);
|
|
5508
|
+
}
|
|
5482
5509
|
let n = 0;
|
|
5483
5510
|
for (const t of held) if (!live.has(t)) n += t.data.byteLength;
|
|
5484
5511
|
return n;
|
|
@@ -7376,7 +7403,7 @@ var ImageEditorController = class {
|
|
|
7376
7403
|
/** @internal Shows a stroke's live surface (no history). */
|
|
7377
7404
|
_strokeUpdate(layerId, channel, surface, rects) {
|
|
7378
7405
|
if (channel === "quick-mask") {
|
|
7379
|
-
this.state.selection = this.selectionFromSurface(surface
|
|
7406
|
+
this.state.selection = this.selectionFromSurface(surface);
|
|
7380
7407
|
this.notify();
|
|
7381
7408
|
return;
|
|
7382
7409
|
}
|
|
@@ -8454,35 +8481,18 @@ var ImageEditorController = class {
|
|
|
8454
8481
|
const { width, height } = this.naturalSize;
|
|
8455
8482
|
const sel = this.state.selection;
|
|
8456
8483
|
if (!sel?.bounds) return emptySurface(1, 0);
|
|
8457
|
-
|
|
8458
|
-
return surfaceFromPixels({ width, height, data: sized.data }, 1, 0, 0, 0);
|
|
8484
|
+
return (sel.width === width && sel.height === height ? sel : resizeSelection(sel, width, height)).surface;
|
|
8459
8485
|
}
|
|
8460
|
-
/** The selection a painted Quick Mask surface stands for (
|
|
8461
|
-
selectionFromSurface(surface
|
|
8486
|
+
/** The selection a painted Quick Mask surface stands for (it shares the surface's tiles). */
|
|
8487
|
+
selectionFromSurface(surface) {
|
|
8462
8488
|
const { width, height } = this.naturalSize;
|
|
8463
|
-
|
|
8464
|
-
if (base && rects && base.width === width && base.height === height) {
|
|
8465
|
-
data = new Uint8Array(base.data);
|
|
8466
|
-
for (const r of rects) {
|
|
8467
|
-
const x0 = Math.max(0, Math.floor(r.x));
|
|
8468
|
-
const y0 = Math.max(0, Math.floor(r.y));
|
|
8469
|
-
const x1 = Math.min(width, Math.ceil(r.x + r.width));
|
|
8470
|
-
const y1 = Math.min(height, Math.ceil(r.y + r.height));
|
|
8471
|
-
if (x1 <= x0 || y1 <= y0) continue;
|
|
8472
|
-
const part = readRegion(surface, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
|
|
8473
|
-
for (let y = y0; y < y1; y++) data.set(part.subarray((y - y0) * (x1 - x0), (y - y0 + 1) * (x1 - x0)), y * width + x0);
|
|
8474
|
-
}
|
|
8475
|
-
} else {
|
|
8476
|
-
const all = readRegion(surface, { x: 0, y: 0, width, height });
|
|
8477
|
-
data = new Uint8Array(all.buffer, all.byteOffset, all.length);
|
|
8478
|
-
}
|
|
8479
|
-
return normalizeSelection(createSelectionMask(width, height, data));
|
|
8489
|
+
return normalizeSelection(selectionFromTiles(width, height, surface));
|
|
8480
8490
|
}
|
|
8481
8491
|
// --- Layer masks ---
|
|
8482
8492
|
maskFromSelection(sel, props = {}) {
|
|
8483
8493
|
const { width, height } = this.naturalSize;
|
|
8484
8494
|
const sized = sel.width === width && sel.height === height ? sel : resizeSelection(sel, width, height);
|
|
8485
|
-
const mask = { surface:
|
|
8495
|
+
const mask = { surface: sized.surface, defaultValue: 0 };
|
|
8486
8496
|
return withMaskProps(mask, props);
|
|
8487
8497
|
}
|
|
8488
8498
|
/**
|
|
@@ -10154,6 +10164,10 @@ function isOpaqueInside(surface, width, height) {
|
|
|
10154
10164
|
}
|
|
10155
10165
|
return true;
|
|
10156
10166
|
}
|
|
10167
|
+
function collectSelectionTiles(selection, channels, into) {
|
|
10168
|
+
if (selection) collectTiles(selection.surface, into);
|
|
10169
|
+
for (const c of channels ?? []) collectTiles(c.mask.surface, into);
|
|
10170
|
+
}
|
|
10157
10171
|
function collectStateTiles(layers, into) {
|
|
10158
10172
|
for (const l of flattenLayers(layers)) {
|
|
10159
10173
|
if (l.type === "pixel" && l.source !== "document") collectTiles(l.surface, into);
|
|
@@ -11063,9 +11077,7 @@ var REFINE_EDGE_CONTROLS = [
|
|
|
11063
11077
|
];
|
|
11064
11078
|
function describeSelection(mask) {
|
|
11065
11079
|
if (!mask || !mask.bounds) return "No selection";
|
|
11066
|
-
|
|
11067
|
-
for (let i = 0; i < mask.data.length; i++) sum += mask.data[i];
|
|
11068
|
-
const pct2 = sum / 255 / mask.data.length * 100;
|
|
11080
|
+
const pct2 = selectionArea(mask) / (mask.width * mask.height) * 100;
|
|
11069
11081
|
const shown = pct2 >= 10 ? Math.round(pct2) : Math.round(pct2 * 10) / 10;
|
|
11070
11082
|
return `${mask.bounds.width} \xD7 ${mask.bounds.height} px selected (${shown}% of the image)`;
|
|
11071
11083
|
}
|
|
@@ -18410,6 +18422,7 @@ export {
|
|
|
18410
18422
|
pointerStrokeSample,
|
|
18411
18423
|
pointerStrokeSamples,
|
|
18412
18424
|
polygonCoverage,
|
|
18425
|
+
polygonCoverageBox,
|
|
18413
18426
|
polygonSelection,
|
|
18414
18427
|
posterizeValue,
|
|
18415
18428
|
presetWarp,
|
|
@@ -18509,6 +18522,8 @@ export {
|
|
|
18509
18522
|
selectionArea,
|
|
18510
18523
|
selectionFromCoverage,
|
|
18511
18524
|
selectionFromPixels,
|
|
18525
|
+
selectionFromRegion,
|
|
18526
|
+
selectionFromTiles,
|
|
18512
18527
|
selectionModeFromModifiers,
|
|
18513
18528
|
selectionOutline,
|
|
18514
18529
|
selectionRing,
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { CropBox } from '../types.cjs';
|
|
2
|
+
import { TiledSurface } from '../../raster/surface.cjs';
|
|
2
3
|
/**
|
|
3
4
|
* A selection: one 8-bit coverage value per image pixel (0 = not selected, 255 = fully
|
|
4
5
|
* selected), row-major over the whole source image in natural pixels — the same space as the
|
|
5
6
|
* crop box and annotations. Soft values are partial selection (feathered or anti-aliased edges).
|
|
6
7
|
*
|
|
8
|
+
* The coverage is stored as 256 × 256 tiles (`surface`, one byte per pixel, missing tiles are 0
|
|
9
|
+
* and every pixel outside the image is 0), so an empty or fully selected area costs nothing and
|
|
10
|
+
* masks share the tiles an operation did not change. `data` is the same coverage as one array,
|
|
11
|
+
* built on first read and cached for the few masks read most recently.
|
|
12
|
+
*
|
|
7
13
|
* Treat a mask as immutable: every operation returns a new one, so history entries can share
|
|
8
|
-
* them without copying.
|
|
14
|
+
* them without copying. Never write to `data`.
|
|
9
15
|
*/
|
|
10
16
|
export interface SelectionMask {
|
|
11
17
|
readonly width: number;
|
|
@@ -13,6 +19,8 @@ export interface SelectionMask {
|
|
|
13
19
|
readonly data: Uint8Array;
|
|
14
20
|
/** Bounding box of the non-zero coverage, or `null` when nothing is selected. */
|
|
15
21
|
readonly bounds: CropBox | null;
|
|
22
|
+
/** The coverage as tiles (1 channel, default 0), shared with other masks where equal. */
|
|
23
|
+
readonly surface: TiledSurface;
|
|
16
24
|
}
|
|
17
25
|
/** How a new selection combines with the current one. */
|
|
18
26
|
export type SelectionMode = 'replace' | 'add' | 'subtract' | 'intersect';
|
|
@@ -35,8 +43,19 @@ export interface SerializedSelection {
|
|
|
35
43
|
}
|
|
36
44
|
/** Bounding box of non-zero bytes. */
|
|
37
45
|
export declare function computeSelectionBounds(width: number, height: number, data: ArrayLike<number>): CropBox | null;
|
|
46
|
+
/**
|
|
47
|
+
* A selection over `width × height` from a 1-channel tiled surface in image space (Quick Mask
|
|
48
|
+
* paint, a mask): its tiles are shared, and coverage outside the image is dropped. A surface
|
|
49
|
+
* whose default is not 0 is read out instead.
|
|
50
|
+
*/
|
|
51
|
+
export declare function selectionFromTiles(width: number, height: number, surface: TiledSurface): SelectionMask;
|
|
38
52
|
/** Wraps coverage bytes (taken over, not copied) as a selection, computing its bounds. */
|
|
39
53
|
export declare function createSelectionMask(width: number, height: number, data?: Uint8Array): SelectionMask;
|
|
54
|
+
/**
|
|
55
|
+
* A selection that is `data` (`rect.width × rect.height` coverage bytes) inside `rect` and
|
|
56
|
+
* nothing elsewhere, without allocating the whole image. `rect` must lie inside the image.
|
|
57
|
+
*/
|
|
58
|
+
export declare function selectionFromRegion(width: number, height: number, rect: CropBox, data: ArrayLike<number>): SelectionMask;
|
|
40
59
|
/** Select › All. */
|
|
41
60
|
export declare function fullSelection(width: number, height: number): SelectionMask;
|
|
42
61
|
export declare function isSelectionEmpty(mask: SelectionMask | null | undefined): boolean;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { CropBox } from '../types.js';
|
|
2
|
+
import { TiledSurface } from '../../raster/surface.js';
|
|
2
3
|
/**
|
|
3
4
|
* A selection: one 8-bit coverage value per image pixel (0 = not selected, 255 = fully
|
|
4
5
|
* selected), row-major over the whole source image in natural pixels — the same space as the
|
|
5
6
|
* crop box and annotations. Soft values are partial selection (feathered or anti-aliased edges).
|
|
6
7
|
*
|
|
8
|
+
* The coverage is stored as 256 × 256 tiles (`surface`, one byte per pixel, missing tiles are 0
|
|
9
|
+
* and every pixel outside the image is 0), so an empty or fully selected area costs nothing and
|
|
10
|
+
* masks share the tiles an operation did not change. `data` is the same coverage as one array,
|
|
11
|
+
* built on first read and cached for the few masks read most recently.
|
|
12
|
+
*
|
|
7
13
|
* Treat a mask as immutable: every operation returns a new one, so history entries can share
|
|
8
|
-
* them without copying.
|
|
14
|
+
* them without copying. Never write to `data`.
|
|
9
15
|
*/
|
|
10
16
|
export interface SelectionMask {
|
|
11
17
|
readonly width: number;
|
|
@@ -13,6 +19,8 @@ export interface SelectionMask {
|
|
|
13
19
|
readonly data: Uint8Array;
|
|
14
20
|
/** Bounding box of the non-zero coverage, or `null` when nothing is selected. */
|
|
15
21
|
readonly bounds: CropBox | null;
|
|
22
|
+
/** The coverage as tiles (1 channel, default 0), shared with other masks where equal. */
|
|
23
|
+
readonly surface: TiledSurface;
|
|
16
24
|
}
|
|
17
25
|
/** How a new selection combines with the current one. */
|
|
18
26
|
export type SelectionMode = 'replace' | 'add' | 'subtract' | 'intersect';
|
|
@@ -35,8 +43,19 @@ export interface SerializedSelection {
|
|
|
35
43
|
}
|
|
36
44
|
/** Bounding box of non-zero bytes. */
|
|
37
45
|
export declare function computeSelectionBounds(width: number, height: number, data: ArrayLike<number>): CropBox | null;
|
|
46
|
+
/**
|
|
47
|
+
* A selection over `width × height` from a 1-channel tiled surface in image space (Quick Mask
|
|
48
|
+
* paint, a mask): its tiles are shared, and coverage outside the image is dropped. A surface
|
|
49
|
+
* whose default is not 0 is read out instead.
|
|
50
|
+
*/
|
|
51
|
+
export declare function selectionFromTiles(width: number, height: number, surface: TiledSurface): SelectionMask;
|
|
38
52
|
/** Wraps coverage bytes (taken over, not copied) as a selection, computing its bounds. */
|
|
39
53
|
export declare function createSelectionMask(width: number, height: number, data?: Uint8Array): SelectionMask;
|
|
54
|
+
/**
|
|
55
|
+
* A selection that is `data` (`rect.width × rect.height` coverage bytes) inside `rect` and
|
|
56
|
+
* nothing elsewhere, without allocating the whole image. `rect` must lie inside the image.
|
|
57
|
+
*/
|
|
58
|
+
export declare function selectionFromRegion(width: number, height: number, rect: CropBox, data: ArrayLike<number>): SelectionMask;
|
|
40
59
|
/** Select › All. */
|
|
41
60
|
export declare function fullSelection(width: number, height: number): SelectionMask;
|
|
42
61
|
export declare function isSelectionEmpty(mask: SelectionMask | null | undefined): boolean;
|
|
@@ -11,6 +11,14 @@ export interface ShapeSelectionOptions {
|
|
|
11
11
|
* their top), so the cost is about pixels + edges × rows they span.
|
|
12
12
|
*/
|
|
13
13
|
export declare function polygonCoverage(points: readonly ImagePoint[], width: number, height: number, antiAlias?: boolean): Float32Array;
|
|
14
|
+
/**
|
|
15
|
+
* {@link polygonCoverage} over just the polygon's bounding box (clipped to the image): `coverage`
|
|
16
|
+
* is `box.width × box.height`; `box` is `null` when the polygon covers no pixel row or column.
|
|
17
|
+
*/
|
|
18
|
+
export declare function polygonCoverageBox(points: readonly ImagePoint[], width: number, height: number, antiAlias?: boolean): {
|
|
19
|
+
box: CropBox | null;
|
|
20
|
+
coverage: Float32Array;
|
|
21
|
+
};
|
|
14
22
|
/** Lasso / polygonal lasso: an even-odd polygon in natural image pixels. */
|
|
15
23
|
export declare function polygonSelection(width: number, height: number, points: readonly ImagePoint[], options?: ShapeSelectionOptions): SelectionMask;
|
|
16
24
|
/** Normalises a rectangle with a negative width or height. */
|
|
@@ -11,6 +11,14 @@ export interface ShapeSelectionOptions {
|
|
|
11
11
|
* their top), so the cost is about pixels + edges × rows they span.
|
|
12
12
|
*/
|
|
13
13
|
export declare function polygonCoverage(points: readonly ImagePoint[], width: number, height: number, antiAlias?: boolean): Float32Array;
|
|
14
|
+
/**
|
|
15
|
+
* {@link polygonCoverage} over just the polygon's bounding box (clipped to the image): `coverage`
|
|
16
|
+
* is `box.width × box.height`; `box` is `null` when the polygon covers no pixel row or column.
|
|
17
|
+
*/
|
|
18
|
+
export declare function polygonCoverageBox(points: readonly ImagePoint[], width: number, height: number, antiAlias?: boolean): {
|
|
19
|
+
box: CropBox | null;
|
|
20
|
+
coverage: Float32Array;
|
|
21
|
+
};
|
|
14
22
|
/** Lasso / polygonal lasso: an even-odd polygon in natural image pixels. */
|
|
15
23
|
export declare function polygonSelection(width: number, height: number, points: readonly ImagePoint[], options?: ShapeSelectionOptions): SelectionMask;
|
|
16
24
|
/** Normalises a rectangle with a negative width or height. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SelectionMask, type SelectionMode } from './mask.cjs';
|
|
2
2
|
import type { ColorDistance, ColorRangePreset } from './wand.cjs';
|
|
3
3
|
import type { RefineEdgeParams } from './refine.cjs';
|
|
4
4
|
/** Selection tools of the image editor UI. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SelectionMask, type SelectionMode } from './mask.js';
|
|
2
2
|
import type { ColorDistance, ColorRangePreset } from './wand.js';
|
|
3
3
|
import type { RefineEdgeParams } from './refine.js';
|
|
4
4
|
/** Selection tools of the image editor UI. */
|
|
@@ -7,7 +7,7 @@ var _chunkZ64NRDEHcjs = require('../chunk-Z64NRDEH.cjs');
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkJYV4R62Mcjs = require('../chunk-JYV4R62M.cjs');
|
|
11
11
|
require('../chunk-A2IS7EHE.cjs');
|
|
12
12
|
|
|
13
13
|
|
|
@@ -1653,11 +1653,11 @@ function header(state, options) {
|
|
|
1653
1653
|
return out;
|
|
1654
1654
|
}
|
|
1655
1655
|
function serializePaintDocument(state, options = {}) {
|
|
1656
|
-
const { layers, assets } =
|
|
1656
|
+
const { layers, assets } = _chunkJYV4R62Mcjs.serializeLayers.call(void 0, state.layers);
|
|
1657
1657
|
return { ...header(state, options), layers, assets };
|
|
1658
1658
|
}
|
|
1659
1659
|
async function serializePaintDocumentExternal(state, store, options = {}) {
|
|
1660
|
-
const { layers, assets } = await
|
|
1660
|
+
const { layers, assets } = await _chunkJYV4R62Mcjs.serializeLayersExternal.call(void 0, state.layers, store);
|
|
1661
1661
|
return { ...header(state, options), layers, assets };
|
|
1662
1662
|
}
|
|
1663
1663
|
function paintLayersOnly(layers, problems) {
|
|
@@ -1694,7 +1694,7 @@ function deserializePaintDocument(raw) {
|
|
|
1694
1694
|
const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
|
|
1695
1695
|
const paper = _chunkYQ5C5BVKcjs.normalizePaper.call(void 0, _nullishCoalesce(r.paper, () => ( {})));
|
|
1696
1696
|
const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
|
|
1697
|
-
const layers = paintLayersOnly(
|
|
1697
|
+
const layers = paintLayersOnly(_chunkJYV4R62Mcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
|
|
1698
1698
|
const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
|
|
1699
1699
|
const activeLayerId = wanted && _chunkHGTDMKNEcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkHGTDMKNEcjs.flattenLayers.call(void 0, layers), 'access', _70 => _70.filter, 'call', _71 => _71((l) => l.type === "pixel"), 'access', _72 => _72.pop, 'call', _73 => _73(), 'optionalAccess', _74 => _74.id]), () => ( null));
|
|
1700
1700
|
const wetEvents = Array.isArray(r.wetEvents) ? r.wetEvents.filter((e) => e && typeof e === "object" && Number.isInteger(e.clock) && typeof e.kind === "string") : [];
|
|
@@ -1710,7 +1710,7 @@ async function deserializePaintDocumentAsync(raw, store) {
|
|
|
1710
1710
|
if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
|
|
1711
1711
|
const r = raw;
|
|
1712
1712
|
const problems = [];
|
|
1713
|
-
const assets = await
|
|
1713
|
+
const assets = await _chunkJYV4R62Mcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
|
|
1714
1714
|
const loaded = deserializePaintDocument({ ...r, assets });
|
|
1715
1715
|
return { ...loaded, problems: [...problems, ...loaded.problems] };
|
|
1716
1716
|
}
|
|
@@ -5409,7 +5409,7 @@ var PaintEditorController = (_class10 = class _PaintEditorController {
|
|
|
5409
5409
|
return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
|
|
5410
5410
|
});
|
|
5411
5411
|
const layers = toStandard(dried);
|
|
5412
|
-
const result =
|
|
5412
|
+
const result = _chunkJYV4R62Mcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
|
|
5413
5413
|
for (const [mode, names] of changed) {
|
|
5414
5414
|
const label = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _271 => _271.find, 'call', _272 => _272((m) => m.id === mode), 'optionalAccess', _273 => _273.label]), () => ( mode));
|
|
5415
5415
|
const std = _nullishCoalesce(_optionalChain([_chunkCWM3CUUXcjs.BLEND_MODES, 'access', _274 => _274.find, 'call', _275 => _275((m) => m.id === _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _276 => _276.label]), () => ( _chunkCWM3CUUXcjs.standardBlendMode.call(void 0, mode)));
|