@pixerate/editor 0.210.0 → 0.211.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-QE7D7TZR.cjs → chunk-H65IBXFI.cjs} +74 -25
- package/dist/{chunk-KFIOEOCQ.js → chunk-W3TOZTL7.js} +55 -6
- package/dist/image-editor/controller.d.cts +51 -0
- package/dist/image-editor/controller.d.ts +51 -0
- package/dist/image-editor/index.cjs +1464 -1005
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +473 -14
- package/dist/image-editor/layers/serialize.d.cts +5 -8
- package/dist/image-editor/layers/serialize.d.ts +5 -8
- package/dist/image-editor/paths.d.cts +41 -0
- package/dist/image-editor/paths.d.ts +41 -0
- package/dist/image-editor/psd/export.d.cts +8 -1
- package/dist/image-editor/psd/export.d.ts +8 -1
- package/dist/image-editor/psd/import.d.cts +7 -0
- package/dist/image-editor/psd/import.d.ts +7 -0
- package/dist/image-editor/psd/paths.d.cts +11 -0
- package/dist/image-editor/psd/paths.d.ts +11 -0
- package/dist/image-editor/selection/gesture.d.cts +10 -2
- package/dist/image-editor/selection/gesture.d.ts +10 -2
- package/dist/image-editor/selection/select-and-mask.d.cts +5 -0
- package/dist/image-editor/selection/select-and-mask.d.ts +5 -0
- package/dist/image-editor/types.d.cts +12 -0
- package/dist/image-editor/types.d.ts +12 -0
- package/dist/paint-editor/index.cjs +6 -6
- package/dist/paint-editor/index.js +1 -1
- package/package.json +1 -1
|
@@ -301,6 +301,7 @@ import {
|
|
|
301
301
|
rasterizeCoverage,
|
|
302
302
|
rasterizeSmartObject,
|
|
303
303
|
readPsd,
|
|
304
|
+
readShapeComponents,
|
|
304
305
|
referencePoint,
|
|
305
306
|
removeAlpha,
|
|
306
307
|
removeLayer,
|
|
@@ -401,7 +402,7 @@ import {
|
|
|
401
402
|
writePsd,
|
|
402
403
|
xyToTempTint,
|
|
403
404
|
xyToUv
|
|
404
|
-
} from "../chunk-
|
|
405
|
+
} from "../chunk-W3TOZTL7.js";
|
|
405
406
|
import {
|
|
406
407
|
parseCssColor
|
|
407
408
|
} from "../chunk-3CI7FRMK.js";
|
|
@@ -1477,8 +1478,9 @@ var ImageEditorRenderer = class {
|
|
|
1477
1478
|
ctx.restore();
|
|
1478
1479
|
}
|
|
1479
1480
|
const { width: iw, height: ih } = state.imageDimensions;
|
|
1480
|
-
const
|
|
1481
|
-
|
|
1481
|
+
const shownSel = state.selectionPreview !== void 0 ? state.selectionPreview : state.selection;
|
|
1482
|
+
const quickMaskSel = display === "quickMask" && state.quickMaskEditing && !shownSel?.bounds ? this.emptyMask(Math.round(iw), Math.round(ih)) : null;
|
|
1483
|
+
if (shownSel?.bounds && display !== "none" || quickMaskSel || options.draftSelectionPath?.length) {
|
|
1482
1484
|
ctx.save();
|
|
1483
1485
|
try {
|
|
1484
1486
|
applyImageProjectionToContext(ctx, projection);
|
|
@@ -1486,8 +1488,8 @@ var ImageEditorRenderer = class {
|
|
|
1486
1488
|
ctx.rect(region.x, region.y, region.width, region.height);
|
|
1487
1489
|
ctx.clip();
|
|
1488
1490
|
if (quickMaskSel) this.drawQuickMask(ctx, quickMaskSel);
|
|
1489
|
-
else if (
|
|
1490
|
-
else if (
|
|
1491
|
+
else if (shownSel?.bounds && display === "quickMask") this.drawQuickMask(ctx, shownSel);
|
|
1492
|
+
else if (shownSel?.bounds && display === "ants") this.drawAnts(ctx, shownSel, projection.scale / u, options.antsOffset ?? 0);
|
|
1491
1493
|
if (options.draftSelectionPath?.length) this.drawDraftPath(ctx, options.draftSelectionPath, projection.scale / u);
|
|
1492
1494
|
} catch {
|
|
1493
1495
|
}
|
|
@@ -2861,6 +2863,58 @@ function magneticAnchorSpacing(frequency = 57) {
|
|
|
2861
2863
|
return 8 + (100 - f);
|
|
2862
2864
|
}
|
|
2863
2865
|
|
|
2866
|
+
// src/image-editor/paths.ts
|
|
2867
|
+
var WORK_PATH_NAME = "Work Path";
|
|
2868
|
+
var counter = 0;
|
|
2869
|
+
function newPathId() {
|
|
2870
|
+
counter = (counter + 1) % 1e6;
|
|
2871
|
+
return `path-${Date.now().toString(36)}-${counter.toString(36)}`;
|
|
2872
|
+
}
|
|
2873
|
+
function pathSvgData(path) {
|
|
2874
|
+
return subpathsToSvgPath(path.components.flatMap((c) => c.subpaths));
|
|
2875
|
+
}
|
|
2876
|
+
function pathBounds(path) {
|
|
2877
|
+
return vectorMaskBounds({ components: path.components });
|
|
2878
|
+
}
|
|
2879
|
+
function pathAnchorCount(path) {
|
|
2880
|
+
return path.components.reduce((n, c) => n + c.subpaths.reduce((m, sp) => m + sp.anchors.length, 0), 0);
|
|
2881
|
+
}
|
|
2882
|
+
function serializePaths(paths) {
|
|
2883
|
+
return paths.map((p) => ({
|
|
2884
|
+
id: p.id,
|
|
2885
|
+
name: p.name,
|
|
2886
|
+
components: JSON.parse(JSON.stringify(p.components)),
|
|
2887
|
+
...p.fillRule === "evenodd" ? { fillRule: "evenodd" } : {},
|
|
2888
|
+
...p.work ? { work: true } : {}
|
|
2889
|
+
}));
|
|
2890
|
+
}
|
|
2891
|
+
function readPaths(stored, problems = []) {
|
|
2892
|
+
if (!Array.isArray(stored)) return [];
|
|
2893
|
+
const out = [];
|
|
2894
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2895
|
+
let work = false;
|
|
2896
|
+
for (const [i, raw] of stored.entries()) {
|
|
2897
|
+
const r = raw;
|
|
2898
|
+
const name = typeof r?.name === "string" && r.name.trim() ? r.name.trim() : `Path ${i + 1}`;
|
|
2899
|
+
try {
|
|
2900
|
+
const components = readShapeComponents(r?.components);
|
|
2901
|
+
let id = typeof r?.id === "string" && r.id ? r.id : newPathId();
|
|
2902
|
+
if (ids.has(id)) id = newPathId();
|
|
2903
|
+
ids.add(id);
|
|
2904
|
+
const path = { id, name, components };
|
|
2905
|
+
if (r?.fillRule === "evenodd") path.fillRule = "evenodd";
|
|
2906
|
+
if (r?.work === true && !work) {
|
|
2907
|
+
path.work = true;
|
|
2908
|
+
work = true;
|
|
2909
|
+
}
|
|
2910
|
+
out.push(path);
|
|
2911
|
+
} catch (err) {
|
|
2912
|
+
problems.push(`Path "${name}" could not be read (${err instanceof Error ? err.message : String(err)}) and was left out.`);
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
return out;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2864
2918
|
// src/image-editor/layers/shape-type-ui.ts
|
|
2865
2919
|
var DEFAULT_SHAPE_TOOL_OPTIONS = {
|
|
2866
2920
|
kind: "rect",
|
|
@@ -5643,6 +5697,7 @@ var ImageEditorController = class {
|
|
|
5643
5697
|
outputOpacity: s.outputOpacity,
|
|
5644
5698
|
selection: s.selection ?? null,
|
|
5645
5699
|
...s.channels?.length ? { channels: s.channels } : {},
|
|
5700
|
+
...s.paths?.length ? { paths: s.paths } : {},
|
|
5646
5701
|
source: {
|
|
5647
5702
|
sourceUrl: s.sourceUrl,
|
|
5648
5703
|
element: this.imageElement,
|
|
@@ -5680,6 +5735,9 @@ var ImageEditorController = class {
|
|
|
5680
5735
|
s.selection = entry.selection;
|
|
5681
5736
|
if (entry.channels?.length) s.channels = entry.channels;
|
|
5682
5737
|
else delete s.channels;
|
|
5738
|
+
if (entry.paths?.length) s.paths = entry.paths;
|
|
5739
|
+
else delete s.paths;
|
|
5740
|
+
if (s.activePathId && !s.paths?.some((p) => p.id === s.activePathId)) s.activePathId = null;
|
|
5683
5741
|
if (this.imageElement !== entry.source.element && !this.samplePixelsOverride) this.samplePixels = null;
|
|
5684
5742
|
this.imageElement = entry.source.element;
|
|
5685
5743
|
s.sourceUrl = entry.source.sourceUrl;
|
|
@@ -6491,6 +6549,138 @@ var ImageEditorController = class {
|
|
|
6491
6549
|
const mask = pathToSelection(components, width, height, { ...options, fillRule: path.fillRule ?? options.fillRule });
|
|
6492
6550
|
return this.setSelection(mask, options.mode ?? "replace");
|
|
6493
6551
|
}
|
|
6552
|
+
// --- Document paths (the Paths panel) ---
|
|
6553
|
+
/** The document's paths: saved paths and the Work Path, in panel order. */
|
|
6554
|
+
getPaths() {
|
|
6555
|
+
return this.state.paths ?? [];
|
|
6556
|
+
}
|
|
6557
|
+
getPath(id) {
|
|
6558
|
+
return this.state.paths?.find((p) => p.id === id) ?? null;
|
|
6559
|
+
}
|
|
6560
|
+
requirePath(id) {
|
|
6561
|
+
const path = this.getPath(id);
|
|
6562
|
+
if (!path) {
|
|
6563
|
+
const ids = this.getPaths().map((p) => `${p.id} (${p.name})`);
|
|
6564
|
+
throw new LayerOperationError(`There is no path "${id}"; the paths are ${ids.join(", ") || "none (make a work path from a selection, or add one)"}.`);
|
|
6565
|
+
}
|
|
6566
|
+
return path;
|
|
6567
|
+
}
|
|
6568
|
+
/** Selects a path in the Paths panel (or none). View state: no undo step. */
|
|
6569
|
+
setActivePath(id) {
|
|
6570
|
+
if (id !== null) this.requirePath(id);
|
|
6571
|
+
if ((this.state.activePathId ?? null) === id) return;
|
|
6572
|
+
this.state.activePathId = id;
|
|
6573
|
+
this.notify();
|
|
6574
|
+
}
|
|
6575
|
+
commitPaths(next, active) {
|
|
6576
|
+
this.recordHistory();
|
|
6577
|
+
if (next.length) this.state.paths = next;
|
|
6578
|
+
else delete this.state.paths;
|
|
6579
|
+
if (active !== void 0) this.state.activePathId = active;
|
|
6580
|
+
else if (this.state.activePathId && !next.some((p) => p.id === this.state.activePathId)) this.state.activePathId = null;
|
|
6581
|
+
this.notify();
|
|
6582
|
+
}
|
|
6583
|
+
/**
|
|
6584
|
+
* Paths › Make Work Path: the selection's outline, traced, becomes the Work Path (replacing the
|
|
6585
|
+
* last one, unless it was saved). One undo step. Returns the path.
|
|
6586
|
+
*/
|
|
6587
|
+
makeWorkPath(options = {}) {
|
|
6588
|
+
const subpaths = this.traceSelection(options);
|
|
6589
|
+
const paths = this.getPaths();
|
|
6590
|
+
const old = paths.find((p) => p.work);
|
|
6591
|
+
const work = { id: old?.id ?? newPathId(), name: WORK_PATH_NAME, components: [{ op: "combine", subpaths }], fillRule: "evenodd", work: true };
|
|
6592
|
+
this.commitPaths(old ? paths.map((p) => p === old ? work : p) : [...paths, work], work.id);
|
|
6593
|
+
return work;
|
|
6594
|
+
}
|
|
6595
|
+
/** A new saved path from geometry (`shape`, `subpaths` or `components`). One undo step. */
|
|
6596
|
+
addPath(input) {
|
|
6597
|
+
const paths = this.getPaths();
|
|
6598
|
+
const path = { id: newPathId(), name: input.name?.trim() || `Path ${paths.filter((p) => !p.work).length + 1}`, components: this.vectorMaskComponents(input) };
|
|
6599
|
+
if (input.fillRule === "evenodd") path.fillRule = "evenodd";
|
|
6600
|
+
this.commitPaths([...paths.filter((p) => !p.work), path, ...paths.filter((p) => p.work)], path.id);
|
|
6601
|
+
return path;
|
|
6602
|
+
}
|
|
6603
|
+
/** Replaces a path's geometry (its name is kept). One undo step. */
|
|
6604
|
+
setPathGeometry(id, input) {
|
|
6605
|
+
const old = this.requirePath(id);
|
|
6606
|
+
const path = { ...old, components: this.vectorMaskComponents(input) };
|
|
6607
|
+
if (input.fillRule === "evenodd") path.fillRule = "evenodd";
|
|
6608
|
+
else if (input.fillRule === "nonzero") delete path.fillRule;
|
|
6609
|
+
this.commitPaths(this.getPaths().map((p) => p.id === id ? path : p));
|
|
6610
|
+
return path;
|
|
6611
|
+
}
|
|
6612
|
+
/** Renames a path; renaming the Work Path saves it (Photoshop's Save Path). One undo step. */
|
|
6613
|
+
renamePath(id, name) {
|
|
6614
|
+
const old = this.requirePath(id);
|
|
6615
|
+
const trimmed = name.trim();
|
|
6616
|
+
if (!trimmed) throw new LayerOperationError("A path needs a name.");
|
|
6617
|
+
const path = { ...old, name: trimmed };
|
|
6618
|
+
delete path.work;
|
|
6619
|
+
this.commitPaths(this.getPaths().map((p) => p.id === id ? path : p));
|
|
6620
|
+
return path;
|
|
6621
|
+
}
|
|
6622
|
+
/** Duplicates a path as a saved path. One undo step. */
|
|
6623
|
+
duplicatePath(id, name) {
|
|
6624
|
+
const old = this.requirePath(id);
|
|
6625
|
+
const copy = { ...old, id: newPathId(), name: name?.trim() || `${old.name} copy`, components: JSON.parse(JSON.stringify(old.components)) };
|
|
6626
|
+
delete copy.work;
|
|
6627
|
+
const paths = this.getPaths();
|
|
6628
|
+
this.commitPaths([...paths.filter((p) => !p.work), copy, ...paths.filter((p) => p.work)], copy.id);
|
|
6629
|
+
return copy;
|
|
6630
|
+
}
|
|
6631
|
+
/** Deletes a path. One undo step. */
|
|
6632
|
+
deletePath(id) {
|
|
6633
|
+
this.requirePath(id);
|
|
6634
|
+
this.commitPaths(this.getPaths().filter((p) => p.id !== id));
|
|
6635
|
+
}
|
|
6636
|
+
/** The area a path fills over the image, as a selection mask. */
|
|
6637
|
+
pathArea(path, options = {}) {
|
|
6638
|
+
const { width, height } = this.naturalSize;
|
|
6639
|
+
return pathToSelection(path.components, width, height, { ...options, fillRule: path.fillRule ?? options.fillRule });
|
|
6640
|
+
}
|
|
6641
|
+
/** Paths › Make Selection: loads a path as the selection, combined by `mode`. One undo step. */
|
|
6642
|
+
loadPathAsSelection(id, options = {}) {
|
|
6643
|
+
if (options.feather !== void 0 && !(options.feather >= 0 && options.feather <= 1e3)) throw new LayerOperationError("feather must be from 0 to 1000 px.");
|
|
6644
|
+
return this.setSelection(this.pathArea(this.requirePath(id), options), options.mode ?? "replace");
|
|
6645
|
+
}
|
|
6646
|
+
/**
|
|
6647
|
+
* Paths › Fill Path: fills the path's area on a pixel layer (default the active one) with a
|
|
6648
|
+
* colour (default the foreground). The selection is not changed. One undo step.
|
|
6649
|
+
*/
|
|
6650
|
+
fillPath(id, options = {}) {
|
|
6651
|
+
const area = this.pathArea(this.requirePath(id));
|
|
6652
|
+
if (!area.bounds) throw new LayerOperationError("The path encloses no area to fill.");
|
|
6653
|
+
return this.withSelection(area, () => this.fillPixels({ ...options, useSelection: true }));
|
|
6654
|
+
}
|
|
6655
|
+
/**
|
|
6656
|
+
* Paths › Stroke Path: strokes along the path's outline on a pixel layer (default the active
|
|
6657
|
+
* one), `width` px wide and centred on it. The selection is not changed. One undo step.
|
|
6658
|
+
*/
|
|
6659
|
+
strokePath(id, options) {
|
|
6660
|
+
const area = this.pathArea(this.requirePath(id), { antiAlias: true });
|
|
6661
|
+
if (!area.bounds) throw new LayerOperationError("The path encloses no area; stroke a closed path.");
|
|
6662
|
+
return this.withSelection(area, () => this.strokeSelection({ ...options, location: "center" }));
|
|
6663
|
+
}
|
|
6664
|
+
/** Paths › Add Vector Mask: masks a layer (default the active one) with a document path. One undo step. */
|
|
6665
|
+
addVectorMaskFromPath(pathId, layerId) {
|
|
6666
|
+
const path = this.requirePath(pathId);
|
|
6667
|
+
const id = layerId ?? this.state.activeLayerId;
|
|
6668
|
+
if (!id) throw new LayerOperationError("No layer given and none is active; pass layerId (see list_layers).");
|
|
6669
|
+
return this.addVectorMask(id, "path", { components: path.components.map((c) => ({ op: c.op, subpaths: c.subpaths })), ...path.fillRule ? { fillRule: path.fillRule } : {} });
|
|
6670
|
+
}
|
|
6671
|
+
/** Runs `fn` with `mask` as the selection, then puts the selection back, all as one undo step. */
|
|
6672
|
+
withSelection(mask, fn) {
|
|
6673
|
+
return this.asOneStep(() => {
|
|
6674
|
+
const before = this.state.selection ?? null;
|
|
6675
|
+
this.state.selection = mask;
|
|
6676
|
+
try {
|
|
6677
|
+
return fn();
|
|
6678
|
+
} finally {
|
|
6679
|
+
this.state.selection = before;
|
|
6680
|
+
this.notify();
|
|
6681
|
+
}
|
|
6682
|
+
});
|
|
6683
|
+
}
|
|
6494
6684
|
/** Replaces a vector mask's path (its properties are kept). One undo step. Returns the vector mask. */
|
|
6495
6685
|
setVectorMaskPath(id, path) {
|
|
6496
6686
|
const { vm } = this.requireVectorMask(id);
|
|
@@ -8511,6 +8701,17 @@ var ImageEditorController = class {
|
|
|
8511
8701
|
this.notify();
|
|
8512
8702
|
return true;
|
|
8513
8703
|
}
|
|
8704
|
+
/**
|
|
8705
|
+
* Shows `mask` in place of the selection while a gesture runs (Quick Selection as the brush
|
|
8706
|
+
* moves; `null` shows nothing selected), or with `undefined` stops. View state only: no undo
|
|
8707
|
+
* step, not saved.
|
|
8708
|
+
*/
|
|
8709
|
+
setSelectionPreview(mask) {
|
|
8710
|
+
if (this.state.selectionPreview === mask) return;
|
|
8711
|
+
if (mask === void 0) delete this.state.selectionPreview;
|
|
8712
|
+
else this.state.selectionPreview = mask;
|
|
8713
|
+
this.notify();
|
|
8714
|
+
}
|
|
8514
8715
|
/** Select › All. */
|
|
8515
8716
|
selectAll() {
|
|
8516
8717
|
const { width, height } = this.naturalSize;
|
|
@@ -10482,6 +10683,10 @@ var ImageEditorController = class {
|
|
|
10482
10683
|
}));
|
|
10483
10684
|
if (psdChannels.length) s.channels = psdChannels;
|
|
10484
10685
|
else delete s.channels;
|
|
10686
|
+
const psdPaths = (result.paths ?? []).map((p) => ({ id: newPathId(), name: p.name, components: p.components, ...p.work ? { work: true } : {} }));
|
|
10687
|
+
if (psdPaths.length) s.paths = psdPaths;
|
|
10688
|
+
else delete s.paths;
|
|
10689
|
+
s.activePathId = null;
|
|
10485
10690
|
s.selectedAnnotationId = null;
|
|
10486
10691
|
s.activeLayerId = defaultActiveLayerId(s.layers);
|
|
10487
10692
|
s.activeTarget = "pixels";
|
|
@@ -10679,7 +10884,7 @@ var ImageEditorController = class {
|
|
|
10679
10884
|
opacity: c.opacity,
|
|
10680
10885
|
indicates: c.indicates
|
|
10681
10886
|
}));
|
|
10682
|
-
const result = exportPsd({ width, height, layers: prepared, merged, mergedDeep, resolution: this.psdResolution, patterns: this.state.patterns, globalLight: this.state.globalLight, depth, alphaChannels, ...color });
|
|
10887
|
+
const result = exportPsd({ width, height, layers: prepared, merged, mergedDeep, resolution: this.psdResolution, patterns: this.state.patterns, globalLight: this.state.globalLight, depth, alphaChannels, paths: this.getPaths(), ...color });
|
|
10683
10888
|
warnings.push(...result.warnings);
|
|
10684
10889
|
return { bytes: result.bytes, warnings, psb: result.psb, width, height };
|
|
10685
10890
|
}
|
|
@@ -10753,6 +10958,7 @@ var ImageEditorController = class {
|
|
|
10753
10958
|
out = this.serializeState();
|
|
10754
10959
|
if (this.state.selection?.bounds) out.selection = serializeSelection(this.state.selection);
|
|
10755
10960
|
if (this.state.channels?.length) out.channels = serializeChannels(this.state.channels);
|
|
10961
|
+
if (this.state.paths?.length) out.paths = serializePaths(this.state.paths);
|
|
10756
10962
|
} finally {
|
|
10757
10963
|
if (root) {
|
|
10758
10964
|
this.state = current;
|
|
@@ -10797,6 +11003,10 @@ var ImageEditorController = class {
|
|
|
10797
11003
|
const channels = deserializeChannels(data.channels, this.naturalSize, problems);
|
|
10798
11004
|
if (channels.length) this.state.channels = channels;
|
|
10799
11005
|
else delete this.state.channels;
|
|
11006
|
+
const paths = readPaths(data.paths, problems);
|
|
11007
|
+
if (paths.length) this.state.paths = paths;
|
|
11008
|
+
else delete this.state.paths;
|
|
11009
|
+
this.state.activePathId = null;
|
|
10800
11010
|
if (problems.length) this.lastLoadProblems = [...this.lastLoadProblems, ...problems];
|
|
10801
11011
|
this.notify();
|
|
10802
11012
|
}
|
|
@@ -11773,7 +11983,7 @@ var DEPTH_MASK_CONTROLS = [
|
|
|
11773
11983
|
// src/image-editor/playback.ts
|
|
11774
11984
|
var IMAGE_PLAYBACK_KIND = "layer";
|
|
11775
11985
|
var PAINT = /^(paint_stroke|clone_stamp|heal_brush|spot_heal|dodge|burn|sponge|smudge|blur_stroke|sharpen_stroke|history_brush|set_clone_source|set_clone_transform|fill_pixels|clear_pixels|set_paint|set_retouch_options|load_mixer_brush|clean_mixer_brush)$/;
|
|
11776
|
-
var SELECT = /^(select_region|select_subject|select_by_color|select_all|deselect|invert_selection|select_rect|select_ellipse|select_polygon|quick_select|select_object|select_focus_area|select_sky|select_line|magic_wand|grow_selection|select_similar|reselect|select_layer_transparency|select_color_range|load_selection_from_image|load_selection_from_mask|set_selection_display|modify_selection|refine_selection|transform_selection|apply_selection_as_mask|layer_via_copy|stroke_selection|content_aware_fill|copy_pixels|cut_pixels|paste_pixels|save_selection|load_selection_from_channel|set_channel_properties|duplicate_channel|delete_channel|load_channel_from_image|set_quick_mask|path_to_selection|select_text_shape)$/;
|
|
11986
|
+
var SELECT = /^(make_work_path|add_path|set_path_geometry|rename_path|duplicate_path|delete_path|fill_path|stroke_path|select_region|select_subject|select_by_color|select_all|deselect|invert_selection|select_rect|select_ellipse|select_polygon|quick_select|select_object|select_focus_area|select_sky|select_line|magic_wand|grow_selection|select_similar|reselect|select_layer_transparency|select_color_range|load_selection_from_image|load_selection_from_mask|set_selection_display|modify_selection|refine_selection|transform_selection|apply_selection_as_mask|layer_via_copy|stroke_selection|content_aware_fill|copy_pixels|cut_pixels|paste_pixels|save_selection|load_selection_from_channel|set_channel_properties|duplicate_channel|delete_channel|load_channel_from_image|set_quick_mask|path_to_selection|select_text_shape)$/;
|
|
11777
11987
|
var ANNOTATE = /^(add_shape_layer|update_shape|add_shape_component|set_shape_component|remove_shape_component|merge_shape_components|add_text_layer|set_text|set_text_style|set_paragraph_style|set_text_frame|set_text_orientation|convert_text_to_shape)$/;
|
|
11778
11988
|
var CROP = /^(set_crop|crop_to_selection|reset_crop|set_rotation|flip_image|transform_layer|warp_layer|flip_layer|offset_layer)$/;
|
|
11779
11989
|
var ADJUST = /^(set_adjustments|add_adjustment_layer|update_adjustment_layer|remove_adjustment_layer|move_adjustment_layer)$/;
|
|
@@ -14497,6 +14707,9 @@ var SelectionGesture = class {
|
|
|
14497
14707
|
/** The last error (e.g. pixels unavailable for the wand), for the UI to show. */
|
|
14498
14708
|
error = null;
|
|
14499
14709
|
pending = Promise.resolve();
|
|
14710
|
+
/** Quick Selection while dragging: the selection before the stroke, how the stroke combines, the pixels. */
|
|
14711
|
+
quick = null;
|
|
14712
|
+
livePreviews = Promise.resolve();
|
|
14500
14713
|
get active() {
|
|
14501
14714
|
return this.start !== null || this.polygon !== null || this.magnetic !== null;
|
|
14502
14715
|
}
|
|
@@ -14504,6 +14717,46 @@ var SelectionGesture = class {
|
|
|
14504
14717
|
get settled() {
|
|
14505
14718
|
return this.pending;
|
|
14506
14719
|
}
|
|
14720
|
+
/** Resolves once no live Quick Selection preview is being computed. */
|
|
14721
|
+
get previewed() {
|
|
14722
|
+
return this.livePreviews;
|
|
14723
|
+
}
|
|
14724
|
+
/** Grows the Quick Selection preview to the stroke so far: one at a time, the newest points following. */
|
|
14725
|
+
growPreview() {
|
|
14726
|
+
const q = this.quick;
|
|
14727
|
+
if (!q) return;
|
|
14728
|
+
if (q.running) {
|
|
14729
|
+
q.dirty = true;
|
|
14730
|
+
return;
|
|
14731
|
+
}
|
|
14732
|
+
q.running = true;
|
|
14733
|
+
this.livePreviews = (async () => {
|
|
14734
|
+
do {
|
|
14735
|
+
q.dirty = false;
|
|
14736
|
+
const stroke = this.points.slice();
|
|
14737
|
+
const options = this.getOptions();
|
|
14738
|
+
try {
|
|
14739
|
+
const pixels = await q.pixels;
|
|
14740
|
+
if (!pixels || this.quick !== q) break;
|
|
14741
|
+
const { mask } = await this.controller.runSelectionJob(
|
|
14742
|
+
{
|
|
14743
|
+
op: "quick",
|
|
14744
|
+
stroke,
|
|
14745
|
+
size: options.quickSize ?? 30,
|
|
14746
|
+
grow: q.mode === "add",
|
|
14747
|
+
enhanceEdge: options.quickEnhance ?? false,
|
|
14748
|
+
selection: q.mode === "add" && q.base?.bounds ? serializeMask(q.base) : null
|
|
14749
|
+
},
|
|
14750
|
+
pixels
|
|
14751
|
+
);
|
|
14752
|
+
if (this.quick === q) this.controller.setSelectionPreview(combineSelections(q.base, mask, q.mode));
|
|
14753
|
+
} catch {
|
|
14754
|
+
break;
|
|
14755
|
+
}
|
|
14756
|
+
} while (q.dirty && this.quick === q);
|
|
14757
|
+
q.running = false;
|
|
14758
|
+
})();
|
|
14759
|
+
}
|
|
14507
14760
|
/** The anchors of a Magnetic Lasso being drawn (empty otherwise). */
|
|
14508
14761
|
get magneticAnchors() {
|
|
14509
14762
|
const m = this.magnetic;
|
|
@@ -14515,7 +14768,8 @@ var SelectionGesture = class {
|
|
|
14515
14768
|
if (this.polygon) return this.current ? [...this.polygon, this.current] : this.polygon.slice();
|
|
14516
14769
|
if (!this.start || !this.current) return null;
|
|
14517
14770
|
const { tool } = this.getOptions();
|
|
14518
|
-
if (tool === "
|
|
14771
|
+
if (tool === "quick") return null;
|
|
14772
|
+
if (tool === "lasso") return this.points.length > 1 ? this.points.slice() : null;
|
|
14519
14773
|
const rect = normalizeRect({
|
|
14520
14774
|
x: this.start.x,
|
|
14521
14775
|
y: this.start.y,
|
|
@@ -14628,6 +14882,18 @@ var SelectionGesture = class {
|
|
|
14628
14882
|
this.start = point;
|
|
14629
14883
|
this.current = point;
|
|
14630
14884
|
this.points = [point];
|
|
14885
|
+
if (options.tool === "quick") {
|
|
14886
|
+
const picked = selectionModeFromModifiers(modifiers, options.mode);
|
|
14887
|
+
const base = this.controller.getSelection();
|
|
14888
|
+
this.quick = {
|
|
14889
|
+
base,
|
|
14890
|
+
mode: picked === "replace" && base ? "add" : picked,
|
|
14891
|
+
pixels: this.controller.getSamplePixels({ sample: options.quickSampleAll === false ? "active-layer" : "composite" }).catch(() => null),
|
|
14892
|
+
running: false,
|
|
14893
|
+
dirty: false
|
|
14894
|
+
};
|
|
14895
|
+
this.growPreview();
|
|
14896
|
+
}
|
|
14631
14897
|
}
|
|
14632
14898
|
/** Pointer move; returns true when the draft changed (re-render). */
|
|
14633
14899
|
move(point, modifiers = {}) {
|
|
@@ -14654,6 +14920,7 @@ var SelectionGesture = class {
|
|
|
14654
14920
|
const last = this.points[this.points.length - 1];
|
|
14655
14921
|
if (Math.hypot(point.x - last.x, point.y - last.y) < 0.5) return false;
|
|
14656
14922
|
this.points.push(point);
|
|
14923
|
+
if (drawn === "quick") this.growPreview();
|
|
14657
14924
|
}
|
|
14658
14925
|
return true;
|
|
14659
14926
|
}
|
|
@@ -14689,7 +14956,8 @@ var SelectionGesture = class {
|
|
|
14689
14956
|
this.start = null;
|
|
14690
14957
|
this.current = null;
|
|
14691
14958
|
this.points = [];
|
|
14692
|
-
const strokeMode = mode === "replace" && this.controller.getSelection() ? "add" : mode;
|
|
14959
|
+
const strokeMode = this.quick?.mode ?? (mode === "replace" && this.controller.getSelection() ? "add" : mode);
|
|
14960
|
+
this.quick = null;
|
|
14693
14961
|
this.pending = this.controller.quickSelect([stroke], {
|
|
14694
14962
|
size: options.quickSize ?? 30,
|
|
14695
14963
|
mode: strokeMode,
|
|
@@ -14700,7 +14968,7 @@ var SelectionGesture = class {
|
|
|
14700
14968
|
(err) => {
|
|
14701
14969
|
this.error = err instanceof Error ? err.message : String(err);
|
|
14702
14970
|
}
|
|
14703
|
-
);
|
|
14971
|
+
).finally(() => this.controller.setSelectionPreview(void 0));
|
|
14704
14972
|
return false;
|
|
14705
14973
|
}
|
|
14706
14974
|
const path = this.draftPath;
|
|
@@ -14829,6 +15097,10 @@ var SelectionGesture = class {
|
|
|
14829
15097
|
}
|
|
14830
15098
|
/** Abandons a drag (or a polygonal lasso) without changing the selection. */
|
|
14831
15099
|
cancel() {
|
|
15100
|
+
if (this.quick) {
|
|
15101
|
+
this.quick = null;
|
|
15102
|
+
this.controller.setSelectionPreview(void 0);
|
|
15103
|
+
}
|
|
14832
15104
|
this.start = null;
|
|
14833
15105
|
this.current = null;
|
|
14834
15106
|
this.points = [];
|
|
@@ -16945,6 +17217,19 @@ function createImageShapeTools(controller) {
|
|
|
16945
17217
|
fillRule: { type: "string", enum: ["nonzero", "evenodd"], description: "Winding rule within a component (default nonzero)." }
|
|
16946
17218
|
};
|
|
16947
17219
|
const LAYER = { type: "string", minLength: 1, description: "The layer (see list_layers). Not a shape layer: its path already is its vector mask." };
|
|
17220
|
+
const PATH_ID = { type: "string", minLength: 1, description: "A document path id from list_paths." };
|
|
17221
|
+
const fromPathId = (args) => {
|
|
17222
|
+
if (args.pathId === void 0) return null;
|
|
17223
|
+
const own = Object.keys(PATH_PROPS).filter((k) => args[k] !== void 0);
|
|
17224
|
+
if (own.length) throw new Error(`Give pathId or ${own.join(" / ")}, not both.`);
|
|
17225
|
+
const path = controller.getPath(String(args.pathId));
|
|
17226
|
+
if (!path) throw new Error(`No path "${String(args.pathId)}". Call list_paths for ids.`);
|
|
17227
|
+
return { components: path.components.map((c) => ({ op: c.op, subpaths: c.subpaths })), ...path.fillRule ? { fillRule: path.fillRule } : {} };
|
|
17228
|
+
};
|
|
17229
|
+
const pathSummary = (id) => {
|
|
17230
|
+
const p = controller.getPath(id);
|
|
17231
|
+
return { id: p.id, name: p.name, work: Boolean(p.work), fillRule: p.fillRule ?? "nonzero", anchors: pathAnchorCount(p), bounds: pathBounds(p) };
|
|
17232
|
+
};
|
|
16948
17233
|
const TRACE_PROPS = {
|
|
16949
17234
|
tolerance: { type: "number", minimum: 0.1, maximum: 10, description: "How far (px) the path may stray from the selection edge (default 0.5; lower is tighter, more anchors)." },
|
|
16950
17235
|
cornerRoundness: { type: "number", minimum: 0, maximum: 1, description: "0: straight sides and sharp corners; 1: as smooth as the outline allows (default 0.5)." },
|
|
@@ -16976,6 +17261,7 @@ function createImageShapeTools(controller) {
|
|
|
16976
17261
|
type: "object",
|
|
16977
17262
|
$defs: DEFS2,
|
|
16978
17263
|
properties: {
|
|
17264
|
+
pathId: { ...PATH_ID, description: "A document path from list_paths, instead of shape / subpaths / components." },
|
|
16979
17265
|
...PATH_PROPS,
|
|
16980
17266
|
feather: { type: "number", minimum: 0, maximum: 1e3, description: "Feather radius in px (default 0)." },
|
|
16981
17267
|
antiAlias: { type: "boolean", description: "Soft edges (default true); false makes every pixel fully in or out." },
|
|
@@ -16986,7 +17272,7 @@ function createImageShapeTools(controller) {
|
|
|
16986
17272
|
annotations: { title: "Make a selection from a path", ...WRITE8 },
|
|
16987
17273
|
handler: (args) => {
|
|
16988
17274
|
const mode = args.mode;
|
|
16989
|
-
controller.pathToSelection(pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
|
|
17275
|
+
controller.pathToSelection(fromPathId(args) ?? pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
|
|
16990
17276
|
const sel = controller.getSelection();
|
|
16991
17277
|
return { empty: !sel, bounds: sel?.bounds ?? null, area: Math.round(sel ? selectionArea(sel) : 0) };
|
|
16992
17278
|
}
|
|
@@ -17008,7 +17294,8 @@ function createImageShapeTools(controller) {
|
|
|
17008
17294
|
$defs: DEFS2,
|
|
17009
17295
|
properties: {
|
|
17010
17296
|
layerId: LAYER,
|
|
17011
|
-
from: { type: "string", enum: ["path", "selection", "reveal-all", "hide-all"], description: "path (default when a shape, subpaths or
|
|
17297
|
+
from: { type: "string", enum: ["path", "selection", "reveal-all", "hide-all"], description: "path (default when a shape, subpaths, components or pathId are given), selection (trace the current selection), reveal-all or hide-all (an empty path)." },
|
|
17298
|
+
pathId: { ...PATH_ID, description: "A document path from list_paths to use as the mask (Paths \u203A Add Vector Mask), instead of shape / subpaths / components." },
|
|
17012
17299
|
...PATH_PROPS,
|
|
17013
17300
|
...TRACE_PROPS
|
|
17014
17301
|
},
|
|
@@ -17018,7 +17305,7 @@ function createImageShapeTools(controller) {
|
|
|
17018
17305
|
annotations: { title: "Add a vector mask", ...WRITE8 },
|
|
17019
17306
|
handler: (args) => {
|
|
17020
17307
|
const id = layerArg(args.layerId);
|
|
17021
|
-
const spec = pathSpec(args);
|
|
17308
|
+
const spec = fromPathId(args) ?? pathSpec(args);
|
|
17022
17309
|
const hasPath = spec.components?.length || spec.shape !== void 0 || spec.subpaths !== void 0;
|
|
17023
17310
|
const from = args.from ?? (hasPath ? "path" : "reveal-all");
|
|
17024
17311
|
if (from !== "selection" && TRACE_KEYS.some((k) => args[k] !== void 0)) throw new Error("tolerance, cornerRoundness and minArea apply only to from selection.");
|
|
@@ -17086,7 +17373,139 @@ function createImageShapeTools(controller) {
|
|
|
17086
17373
|
return { layerId: id, vectorMask: null };
|
|
17087
17374
|
}
|
|
17088
17375
|
};
|
|
17089
|
-
|
|
17376
|
+
const listPaths = {
|
|
17377
|
+
name: "list_paths",
|
|
17378
|
+
title: "List document paths",
|
|
17379
|
+
description: "Paths panel: the document's saved paths and its Work Path (paths kept with the document, on no layer), each with id, name, work (true for the Work Path, which the next make_work_path replaces), fill rule, anchor count and bounds, and which is active. Use the ids with path_to_selection, add_vector_mask, fill_path, stroke_path and the other path tools.",
|
|
17380
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
17381
|
+
annotations: { title: "List document paths", ...READ10 },
|
|
17382
|
+
handler: () => ({ paths: controller.getPaths().map((p) => pathSummary(p.id)), activePathId: controller.getState().activePathId ?? null })
|
|
17383
|
+
};
|
|
17384
|
+
const getPath2 = {
|
|
17385
|
+
name: "get_path",
|
|
17386
|
+
title: "Read a document path",
|
|
17387
|
+
description: "Reads a document path: its summary, svg (compact SVG path data) and components (op, subpaths of anchors with handles, in document pixels), ready to edit and pass back to set_path_geometry.",
|
|
17388
|
+
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
17389
|
+
annotations: { title: "Read a document path", ...READ10 },
|
|
17390
|
+
handler: ({ pathId }) => {
|
|
17391
|
+
const p = controller.getPath(String(pathId));
|
|
17392
|
+
if (!p) throw new Error(`No path "${String(pathId)}". Call list_paths for ids.`);
|
|
17393
|
+
return { path: { ...pathSummary(p.id), svg: pathSvgData(p), components: p.components } };
|
|
17394
|
+
}
|
|
17395
|
+
};
|
|
17396
|
+
const makeWorkPath = {
|
|
17397
|
+
name: "make_work_path",
|
|
17398
|
+
title: "Make a work path from the selection",
|
|
17399
|
+
description: "Paths \u203A Make Work Path: traces the selection's outline (within tolerance px) into the Work Path, replacing the last Work Path unless it was saved (rename_path saves it). Use it to keep a selection as an editable, resolution-independent outline. One undo step. Returns the path.",
|
|
17400
|
+
inputSchema: { type: "object", properties: { ...TRACE_PROPS }, additionalProperties: false },
|
|
17401
|
+
annotations: { title: "Make a work path from the selection", ...WRITE8 },
|
|
17402
|
+
handler: (args) => ({ path: pathSummary(controller.makeWorkPath(traceOptions(args)).id) })
|
|
17403
|
+
};
|
|
17404
|
+
const addPath = {
|
|
17405
|
+
name: "add_path",
|
|
17406
|
+
title: "Add a document path",
|
|
17407
|
+
description: "Adds a saved document path from a live shape, free subpaths or SVG path data, or components (document pixels), as add_shape_layer takes them. One undo step. Returns the path.",
|
|
17408
|
+
inputSchema: {
|
|
17409
|
+
type: "object",
|
|
17410
|
+
$defs: DEFS2,
|
|
17411
|
+
properties: { name: { type: "string", description: 'The path name (default "Path n").' }, ...PATH_PROPS },
|
|
17412
|
+
additionalProperties: false
|
|
17413
|
+
},
|
|
17414
|
+
annotations: { title: "Add a document path", ...WRITE8 },
|
|
17415
|
+
handler: (args) => {
|
|
17416
|
+
const spec = pathSpec(args);
|
|
17417
|
+
if (!spec.components?.length && spec.shape === void 0 && spec.subpaths === void 0) throw new Error("Give the path as shape, subpaths or components.");
|
|
17418
|
+
return { path: pathSummary(controller.addPath({ ...spec, name: args.name }).id) };
|
|
17419
|
+
}
|
|
17420
|
+
};
|
|
17421
|
+
const setPathGeometry = {
|
|
17422
|
+
name: "set_path_geometry",
|
|
17423
|
+
title: "Replace a document path",
|
|
17424
|
+
description: "Replaces a document path's geometry (shape, subpaths or components, document pixels); its name is kept. Read it with get_path first to change part of it. One undo step. Returns the path.",
|
|
17425
|
+
inputSchema: { type: "object", $defs: DEFS2, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
17426
|
+
annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT5 },
|
|
17427
|
+
handler: (args) => ({ path: pathSummary(controller.setPathGeometry(String(args.pathId), pathSpec(args)).id) })
|
|
17428
|
+
};
|
|
17429
|
+
const renamePath = {
|
|
17430
|
+
name: "rename_path",
|
|
17431
|
+
title: "Rename or save a path",
|
|
17432
|
+
description: "Renames a document path. Renaming the Work Path saves it (Paths \u203A Save Path), so make_work_path no longer replaces it. One undo step. Returns the path.",
|
|
17433
|
+
inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", minLength: 1, description: "The new name." } }, required: ["pathId", "name"], additionalProperties: false },
|
|
17434
|
+
annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT5 },
|
|
17435
|
+
handler: ({ pathId, name }) => ({ path: pathSummary(controller.renamePath(String(pathId), String(name)).id) })
|
|
17436
|
+
};
|
|
17437
|
+
const duplicatePath = {
|
|
17438
|
+
name: "duplicate_path",
|
|
17439
|
+
title: "Duplicate a path",
|
|
17440
|
+
description: 'Duplicates a document path as a saved path (default name "<name> copy"). One undo step. Returns the new path.',
|
|
17441
|
+
inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", description: "The copy's name." } }, required: ["pathId"], additionalProperties: false },
|
|
17442
|
+
annotations: { title: "Duplicate a path", ...WRITE8 },
|
|
17443
|
+
handler: ({ pathId, name }) => ({ path: pathSummary(controller.duplicatePath(String(pathId), name).id) })
|
|
17444
|
+
};
|
|
17445
|
+
const deletePath = {
|
|
17446
|
+
name: "delete_path",
|
|
17447
|
+
title: "Delete a path",
|
|
17448
|
+
description: "Deletes a document path (undo_image brings it back). Returns the remaining paths.",
|
|
17449
|
+
inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
|
|
17450
|
+
annotations: { title: "Delete a path", ...DESTRUCTIVE6 },
|
|
17451
|
+
handler: ({ pathId }) => {
|
|
17452
|
+
controller.deletePath(String(pathId));
|
|
17453
|
+
return { paths: controller.getPaths().map((p) => pathSummary(p.id)) };
|
|
17454
|
+
}
|
|
17455
|
+
};
|
|
17456
|
+
const PAINT_PROPS = {
|
|
17457
|
+
layerId: { type: "string", description: "The pixel layer to paint on (default the active layer)." },
|
|
17458
|
+
color: { type: "string", description: "A CSS colour such as #ff0000 (default the foreground colour)." },
|
|
17459
|
+
opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0..1 (default 1)." }
|
|
17460
|
+
};
|
|
17461
|
+
const fillPath = {
|
|
17462
|
+
name: "fill_path",
|
|
17463
|
+
title: "Fill a path",
|
|
17464
|
+
description: "Paths \u203A Fill Path: fills the area a document path encloses on a pixel layer with a colour. The selection is not changed. One undo step. Returns what was painted.",
|
|
17465
|
+
inputSchema: { type: "object", properties: { pathId: PATH_ID, ...PAINT_PROPS }, required: ["pathId"], additionalProperties: false },
|
|
17466
|
+
annotations: { title: "Fill a path", ...WRITE8 },
|
|
17467
|
+
handler: (args) => controller.fillPath(String(args.pathId), { layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
17468
|
+
};
|
|
17469
|
+
const strokePath = {
|
|
17470
|
+
name: "stroke_path",
|
|
17471
|
+
title: "Stroke a path",
|
|
17472
|
+
description: "Paths \u203A Stroke Path: strokes along a document path's outline on a pixel layer, width px wide and centred on it. The selection is not changed. One undo step. Returns what was painted.",
|
|
17473
|
+
inputSchema: {
|
|
17474
|
+
type: "object",
|
|
17475
|
+
properties: { pathId: PATH_ID, width: { type: "number", exclusiveMinimum: 0, maximum: 250, description: "Stroke width in px." }, ...PAINT_PROPS },
|
|
17476
|
+
required: ["pathId", "width"],
|
|
17477
|
+
additionalProperties: false
|
|
17478
|
+
},
|
|
17479
|
+
annotations: { title: "Stroke a path", ...WRITE8 },
|
|
17480
|
+
handler: (args) => controller.strokePath(String(args.pathId), { width: args.width, layerId: args.layerId, color: args.color, opacity: args.opacity })
|
|
17481
|
+
};
|
|
17482
|
+
return [
|
|
17483
|
+
get,
|
|
17484
|
+
add2,
|
|
17485
|
+
update,
|
|
17486
|
+
setComponent,
|
|
17487
|
+
addComponent,
|
|
17488
|
+
removeComponent,
|
|
17489
|
+
merge,
|
|
17490
|
+
getVectorMask,
|
|
17491
|
+
addVectorMask,
|
|
17492
|
+
setVectorMaskPath,
|
|
17493
|
+
setVectorMaskProps,
|
|
17494
|
+
rasterizeVectorMask,
|
|
17495
|
+
removeVectorMask,
|
|
17496
|
+
selectionToPath,
|
|
17497
|
+
pathToSelection2,
|
|
17498
|
+
listPaths,
|
|
17499
|
+
getPath2,
|
|
17500
|
+
makeWorkPath,
|
|
17501
|
+
addPath,
|
|
17502
|
+
setPathGeometry,
|
|
17503
|
+
renamePath,
|
|
17504
|
+
duplicatePath,
|
|
17505
|
+
deletePath,
|
|
17506
|
+
fillPath,
|
|
17507
|
+
strokePath
|
|
17508
|
+
];
|
|
17090
17509
|
}
|
|
17091
17510
|
|
|
17092
17511
|
// src/image-editor/type-tools.ts
|
|
@@ -17733,6 +18152,9 @@ var SelectAndMaskSession = class {
|
|
|
17733
18152
|
dragStart = null;
|
|
17734
18153
|
pixels = null;
|
|
17735
18154
|
previewPixels = null;
|
|
18155
|
+
/** The layers below the active one, composited (On Layers shows them where nothing is selected). */
|
|
18156
|
+
below = null;
|
|
18157
|
+
belowPreview = null;
|
|
17736
18158
|
base;
|
|
17737
18159
|
previewMask = null;
|
|
17738
18160
|
baseMask = null;
|
|
@@ -17764,10 +18186,24 @@ var SelectAndMaskSession = class {
|
|
|
17764
18186
|
this.emit();
|
|
17765
18187
|
return false;
|
|
17766
18188
|
}
|
|
18189
|
+
this.below = this.layersBelow();
|
|
17767
18190
|
this.rescale();
|
|
17768
18191
|
this.recompute();
|
|
17769
18192
|
return true;
|
|
17770
18193
|
}
|
|
18194
|
+
/** The visible layers under the active one, composited at full size, or null when there are none. */
|
|
18195
|
+
layersBelow() {
|
|
18196
|
+
const active = this.controller.getState().activeLayerId;
|
|
18197
|
+
const flat = flattenLayers(this.controller.getLayers()).filter((l) => l.type !== "group");
|
|
18198
|
+
const at = flat.findIndex((l) => l.id === active);
|
|
18199
|
+
const ids = (at > 0 ? flat.slice(0, at) : []).filter((l) => l.visible).map((l) => l.id);
|
|
18200
|
+
if (!ids.length) return null;
|
|
18201
|
+
try {
|
|
18202
|
+
return this.controller.compositePixels(void 0, { layerIds: ids });
|
|
18203
|
+
} catch {
|
|
18204
|
+
return null;
|
|
18205
|
+
}
|
|
18206
|
+
}
|
|
17771
18207
|
subscribe(listener) {
|
|
17772
18208
|
this.listeners.add(listener);
|
|
17773
18209
|
return () => this.listeners.delete(listener);
|
|
@@ -17800,6 +18236,7 @@ var SelectAndMaskSession = class {
|
|
|
17800
18236
|
const w = Math.max(1, Math.round(px2.width * s));
|
|
17801
18237
|
const h = Math.max(1, Math.round(px2.height * s));
|
|
17802
18238
|
this.previewPixels = scalePixels(px2, w, h);
|
|
18239
|
+
this.belowPreview = this.below ? scalePixels(this.below, w, h) : null;
|
|
17803
18240
|
this.baseMask = this.base?.bounds ? s === 1 ? this.base : resizeSelection(this.base, w, h) : null;
|
|
17804
18241
|
}
|
|
17805
18242
|
/**
|
|
@@ -17923,6 +18360,20 @@ var SelectAndMaskSession = class {
|
|
|
17923
18360
|
}
|
|
17924
18361
|
break;
|
|
17925
18362
|
}
|
|
18363
|
+
case "on-layers": {
|
|
18364
|
+
const under = this.belowPreview?.data;
|
|
18365
|
+
let ur = checker;
|
|
18366
|
+
let ug = checker;
|
|
18367
|
+
let ub = checker;
|
|
18368
|
+
if (under) {
|
|
18369
|
+
const ua = under[p + 3] / 255;
|
|
18370
|
+
ur = under[p] * ua + checker * (1 - ua);
|
|
18371
|
+
ug = under[p + 1] * ua + checker * (1 - ua);
|
|
18372
|
+
ub = under[p + 2] * ua + checker * (1 - ua);
|
|
18373
|
+
}
|
|
18374
|
+
o = [r + (ur - r) * hide, g + (ug - g) * hide, b + (ub - b) * hide];
|
|
18375
|
+
break;
|
|
18376
|
+
}
|
|
17926
18377
|
default:
|
|
17927
18378
|
o = [r + (checker - r) * hide, g + (checker - g) * hide, b + (checker - b) * hide];
|
|
17928
18379
|
}
|
|
@@ -20250,6 +20701,7 @@ export {
|
|
|
20250
20701
|
WGSL_SHADE,
|
|
20251
20702
|
WGSL_STEP,
|
|
20252
20703
|
WORKING_SPACE_OPTIONS,
|
|
20704
|
+
WORK_PATH_NAME,
|
|
20253
20705
|
WORK_SIZE,
|
|
20254
20706
|
WetGpuEngine,
|
|
20255
20707
|
WetMedium,
|
|
@@ -20715,6 +21167,7 @@ export {
|
|
|
20715
21167
|
newEffectId,
|
|
20716
21168
|
newLayerId,
|
|
20717
21169
|
newLayerOptions,
|
|
21170
|
+
newPathId,
|
|
20718
21171
|
normalizeAdjustmentLayer,
|
|
20719
21172
|
normalizeAdjustmentLayers,
|
|
20720
21173
|
normalizeAngle,
|
|
@@ -20771,8 +21224,11 @@ export {
|
|
|
20771
21224
|
parseVersionedDescriptor,
|
|
20772
21225
|
patchParagraphStyle,
|
|
20773
21226
|
patchTextStyle,
|
|
21227
|
+
pathAnchorCount,
|
|
21228
|
+
pathBounds,
|
|
20774
21229
|
pathStrokeCoverage,
|
|
20775
21230
|
pathStrokeDabs,
|
|
21231
|
+
pathSvgData,
|
|
20776
21232
|
pathToSelection,
|
|
20777
21233
|
perDabStrength,
|
|
20778
21234
|
photoFilterMatrix,
|
|
@@ -20825,9 +21281,11 @@ export {
|
|
|
20825
21281
|
readAdjustmentControls,
|
|
20826
21282
|
readDeepRegion,
|
|
20827
21283
|
readPaintSource,
|
|
21284
|
+
readPaths,
|
|
20828
21285
|
readPixel,
|
|
20829
21286
|
readPsd,
|
|
20830
21287
|
readRegion,
|
|
21288
|
+
readShapeComponents,
|
|
20831
21289
|
readSourceRegion,
|
|
20832
21290
|
rectSelection,
|
|
20833
21291
|
rectToQuad,
|
|
@@ -20916,6 +21374,7 @@ export {
|
|
|
20916
21374
|
serializeLayers,
|
|
20917
21375
|
serializeLayersExternal,
|
|
20918
21376
|
serializeMask,
|
|
21377
|
+
serializePaths,
|
|
20919
21378
|
serializePatterns,
|
|
20920
21379
|
serializeSelection,
|
|
20921
21380
|
setCloneTransformValue,
|