@pixerate/editor 0.214.0 → 0.215.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-UOGKSVRQ.cjs → chunk-B46UQUDC.cjs} +770 -733
- package/dist/{chunk-W3TOZTL7.js → chunk-F7Z2MKY2.js} +115 -4
- package/dist/{chunk-YBJXCQTR.js → chunk-QXY4YTRI.js} +738 -701
- package/dist/{chunk-H65IBXFI.cjs → chunk-S55JFWDA.cjs} +350 -239
- package/dist/{chunk-QYLWG22N.cjs → chunk-SS53NNZO.cjs} +304 -1
- package/dist/{chunk-LQ5SALHK.js → chunk-U7C655AM.js} +5 -311
- package/dist/{chunk-L52VMQZS.cjs → chunk-UC3PWFM3.cjs} +68 -374
- package/dist/{chunk-L3G23N5Y.js → chunk-ZNA3IQZF.js} +304 -1
- package/dist/image-editor/controller.d.cts +29 -0
- package/dist/image-editor/controller.d.ts +29 -0
- package/dist/image-editor/index.cjs +1224 -1074
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +166 -16
- package/dist/image-editor/layers/edge-color.d.cts +27 -0
- package/dist/image-editor/layers/edge-color.d.ts +27 -0
- package/dist/image-editor/layers/serialize.d.cts +13 -0
- package/dist/image-editor/layers/serialize.d.ts +13 -0
- package/dist/image-editor/selection-worker.cjs +4 -4
- package/dist/image-editor/selection-worker.js +2 -2
- package/dist/paint-editor/index.cjs +79 -79
- package/dist/paint-editor/index.js +3 -3
- package/dist/raster/compositor.d.cts +10 -1
- package/dist/raster/compositor.d.ts +10 -1
- package/dist/raster/deep-compositor.d.cts +1 -1
- package/dist/raster/deep-compositor.d.ts +1 -1
- package/dist/raster/index.cjs +4 -2
- package/dist/raster/index.js +3 -1
- package/dist/raster/layers.d.cts +16 -0
- package/dist/raster/layers.d.ts +16 -0
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +8 -6
- package/skills/pixerate-image-editor/references/paths.md +12 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +8 -8
|
@@ -37,6 +37,7 @@ export * from './layers/smart.cjs';
|
|
|
37
37
|
export * from './smart-tools.cjs';
|
|
38
38
|
export * from './layers/shape.cjs';
|
|
39
39
|
export * from './layers/vector-mask.cjs';
|
|
40
|
+
export * from './layers/edge-color.cjs';
|
|
40
41
|
export * from './shape-tools.cjs';
|
|
41
42
|
export * from './layers/text.cjs';
|
|
42
43
|
export * from './layers/text-shapers.cjs';
|
|
@@ -37,6 +37,7 @@ export * from './layers/smart.js';
|
|
|
37
37
|
export * from './smart-tools.js';
|
|
38
38
|
export * from './layers/shape.js';
|
|
39
39
|
export * from './layers/vector-mask.js';
|
|
40
|
+
export * from './layers/edge-color.js';
|
|
40
41
|
export * from './shape-tools.js';
|
|
41
42
|
export * from './layers/text.js';
|
|
42
43
|
export * from './layers/text-shapers.js';
|
|
@@ -7,9 +7,7 @@ import {
|
|
|
7
7
|
} from "../chunk-DJBYJOHM.js";
|
|
8
8
|
import {
|
|
9
9
|
ColorGmm,
|
|
10
|
-
DEFAULT_REFINE_EDGE_PARAMS,
|
|
11
10
|
GAMMA,
|
|
12
|
-
GUIDED_FILTER_EPS,
|
|
13
11
|
GridGraph,
|
|
14
12
|
REFINE_EDIT_KINDS,
|
|
15
13
|
SelectionWorkerClient,
|
|
@@ -17,31 +15,22 @@ import {
|
|
|
17
15
|
WORK_SIZE,
|
|
18
16
|
applyRefineEdits,
|
|
19
17
|
boxBlur,
|
|
20
|
-
boxMean,
|
|
21
18
|
brushStrokeMask,
|
|
22
|
-
decontaminateColors,
|
|
23
19
|
deserializeMask,
|
|
24
|
-
edgeWidth,
|
|
25
20
|
ellipsePoints,
|
|
26
21
|
ellipseSelection,
|
|
27
22
|
findSky,
|
|
28
23
|
findSubject,
|
|
29
24
|
focusArea,
|
|
30
25
|
grabCutLabels,
|
|
31
|
-
guidePlanes,
|
|
32
|
-
guidedFilterColor,
|
|
33
26
|
keepMainPieces,
|
|
34
27
|
normalizeRect,
|
|
35
|
-
normalizeRefineEdgeParams,
|
|
36
28
|
otsuThreshold,
|
|
37
29
|
polygonCoverage,
|
|
38
30
|
polygonCoverageBox,
|
|
39
31
|
polygonSelection,
|
|
40
32
|
quickSelectStroke,
|
|
41
33
|
rectSelection,
|
|
42
|
-
refineCoverage,
|
|
43
|
-
refineEdgeHalo,
|
|
44
|
-
refineSelection,
|
|
45
34
|
runSelectionJob,
|
|
46
35
|
selectObjectIn,
|
|
47
36
|
serializeMask,
|
|
@@ -54,7 +43,7 @@ import {
|
|
|
54
43
|
workImage,
|
|
55
44
|
workLuma,
|
|
56
45
|
workPlanes
|
|
57
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-U7C655AM.js";
|
|
58
47
|
import {
|
|
59
48
|
ADJUSTMENT_KEYS,
|
|
60
49
|
ADJUSTMENT_KINDS,
|
|
@@ -72,6 +61,7 @@ import {
|
|
|
72
61
|
DEFAULT_MITER_LIMIT,
|
|
73
62
|
DEFAULT_TRANSFORM_VALUES,
|
|
74
63
|
DEVELOP_FILTER_ID,
|
|
64
|
+
EDGE_COLOR_RADIUS,
|
|
75
65
|
FREE_TRANSFORM_MODES,
|
|
76
66
|
HUE_RANGE_LABELS,
|
|
77
67
|
IDENTITY_MATRIX3,
|
|
@@ -127,6 +117,7 @@ import {
|
|
|
127
117
|
applyBoxBlur,
|
|
128
118
|
applyBoxBlurFloat,
|
|
129
119
|
applyDepthMask,
|
|
120
|
+
applyEdgeUnmix,
|
|
130
121
|
applyImageProjectionToContext,
|
|
131
122
|
applyLegacyAdjustments,
|
|
132
123
|
applyLegacyFloat,
|
|
@@ -175,6 +166,7 @@ import {
|
|
|
175
166
|
deserializeLayer,
|
|
176
167
|
deserializeLayers,
|
|
177
168
|
deserializePatterns,
|
|
169
|
+
despillEdge,
|
|
178
170
|
developFilter,
|
|
179
171
|
developFromAdjustments,
|
|
180
172
|
developTarget,
|
|
@@ -197,7 +189,9 @@ import {
|
|
|
197
189
|
getViewportMetrics,
|
|
198
190
|
getViewportProjection,
|
|
199
191
|
groupLayers,
|
|
192
|
+
hasEdgeUnmix,
|
|
200
193
|
hasResampledLegacyMask,
|
|
194
|
+
hasSoftBand,
|
|
201
195
|
hasSurface,
|
|
202
196
|
hasWarp,
|
|
203
197
|
hexToRgb,
|
|
@@ -248,6 +242,7 @@ import {
|
|
|
248
242
|
liveShapeSubpaths,
|
|
249
243
|
mapCropHandle,
|
|
250
244
|
mapSubpaths,
|
|
245
|
+
maskCoverageOverCanvas,
|
|
251
246
|
matrixFromCorners,
|
|
252
247
|
matrixFromParams,
|
|
253
248
|
mergeShapeComponents,
|
|
@@ -302,6 +297,7 @@ import {
|
|
|
302
297
|
rasterMaskFromLegacy,
|
|
303
298
|
rasterizeCoverage,
|
|
304
299
|
rasterizeSmartObject,
|
|
300
|
+
readEdgeColor,
|
|
305
301
|
readPsd,
|
|
306
302
|
readShapeComponents,
|
|
307
303
|
referencePoint,
|
|
@@ -404,34 +400,45 @@ import {
|
|
|
404
400
|
writePsd,
|
|
405
401
|
xyToTempTint,
|
|
406
402
|
xyToUv
|
|
407
|
-
} from "../chunk-
|
|
403
|
+
} from "../chunk-F7Z2MKY2.js";
|
|
408
404
|
import {
|
|
409
405
|
parseCssColor
|
|
410
406
|
} from "../chunk-3CI7FRMK.js";
|
|
411
407
|
import {
|
|
408
|
+
DEFAULT_REFINE_EDGE_PARAMS,
|
|
412
409
|
EMPTY_DISTANCE,
|
|
410
|
+
GUIDED_FILTER_EPS,
|
|
413
411
|
SELECTION_MODES,
|
|
414
412
|
SELECTION_MODIFY_OPS,
|
|
415
413
|
borderCoverage,
|
|
414
|
+
boxMean,
|
|
416
415
|
combineSelections,
|
|
417
416
|
computeSelectionBounds,
|
|
418
417
|
contractCoverage,
|
|
419
418
|
coverageToByte,
|
|
420
419
|
createSelectionMask,
|
|
421
420
|
decodeSelectionRle,
|
|
421
|
+
decontaminateColors,
|
|
422
422
|
deserializeSelection,
|
|
423
423
|
distanceTransform,
|
|
424
|
+
edgeWidth,
|
|
424
425
|
encodeSelectionRle,
|
|
425
426
|
expandCoverage,
|
|
426
427
|
featherCoverage,
|
|
427
428
|
fullSelection,
|
|
428
429
|
greyMorphology,
|
|
430
|
+
guidePlanes,
|
|
431
|
+
guidedFilterColor,
|
|
429
432
|
hashMaskContent,
|
|
430
433
|
invertSelection,
|
|
431
434
|
isSelectionEmpty,
|
|
432
435
|
isSelectionMode,
|
|
433
436
|
modifySelection,
|
|
437
|
+
normalizeRefineEdgeParams,
|
|
434
438
|
parseSelectionMode,
|
|
439
|
+
refineCoverage,
|
|
440
|
+
refineEdgeHalo,
|
|
441
|
+
refineSelection,
|
|
435
442
|
resizeSelection,
|
|
436
443
|
selectionArea,
|
|
437
444
|
selectionFromCoverage,
|
|
@@ -444,7 +451,7 @@ import {
|
|
|
444
451
|
serializeSelection,
|
|
445
452
|
shiftCoverage,
|
|
446
453
|
smoothCoverage
|
|
447
|
-
} from "../chunk-
|
|
454
|
+
} from "../chunk-ZNA3IQZF.js";
|
|
448
455
|
import {
|
|
449
456
|
EffectRendererPool
|
|
450
457
|
} from "../chunk-EHLOCVWB.js";
|
|
@@ -500,7 +507,7 @@ import {
|
|
|
500
507
|
validateLayerEffects,
|
|
501
508
|
warpSurface,
|
|
502
509
|
workingToSamples
|
|
503
|
-
} from "../chunk-
|
|
510
|
+
} from "../chunk-QXY4YTRI.js";
|
|
504
511
|
import {
|
|
505
512
|
applyHomography,
|
|
506
513
|
boxQuad,
|
|
@@ -2777,7 +2784,7 @@ function inspectMaskEdge(mask, image, options = {}) {
|
|
|
2777
2784
|
const worst = candidates.sort((p, q) => q.severity - p.severity).slice(0, 5).map(({ bounds, reason }) => ({ bounds, reason }));
|
|
2778
2785
|
const issues = [];
|
|
2779
2786
|
if (haloScore >= T2.halo)
|
|
2780
|
-
issues.push(`Halo (haloScore ${r3(haloScore)} \u2265 ${T2.halo}): background colour is left inside the edge. Contract the edge (modify_selection contract 1\u20132 px, or refine_selection shiftEdge -20 to -40), or
|
|
2787
|
+
issues.push(`Halo (haloScore ${r3(haloScore)} \u2265 ${T2.halo}): background colour is left inside the edge. Contract the edge (modify_selection contract 1\u20132 px, or refine_selection shiftEdge -20 to -40), or on a masked cutout set_edge_decontamination 80\u2013100.`);
|
|
2781
2788
|
if (edgeLength >= 16 && edgeAlignment < T2.alignment)
|
|
2782
2789
|
issues.push(`Off the image's edges (edgeAlignment ${r3(edgeAlignment)} < ${T2.alignment}): much of the edge does not follow edges in the image. Rebuild it with select_subject, select_object or quick_select, or refine_selection with a larger radius.`);
|
|
2783
2790
|
if (jaggedness >= T2.jaggedness) issues.push(`Jagged (jaggedness ${r3(jaggedness)} \u2265 ${T2.jaggedness}): the outline zigzags. Smooth it (refine_selection smooth 20\u201340, or modify_selection smooth).`);
|
|
@@ -6822,6 +6829,85 @@ var ImageEditorController = class {
|
|
|
6822
6829
|
this.commitLayers(next);
|
|
6823
6830
|
return { parentId: loc.parent?.id ?? null, index: loc.index };
|
|
6824
6831
|
}
|
|
6832
|
+
/** A layer's edge colour as percentages (see `setEdgeColor`). */
|
|
6833
|
+
getEdgeColor(id) {
|
|
6834
|
+
const layer = this.requireEdgeLayer(id);
|
|
6835
|
+
const e = layer.edge ?? {};
|
|
6836
|
+
const pct2 = (v) => Math.round((v ?? 0) * 1e3) / 10;
|
|
6837
|
+
const hex = (c) => "#" + c.map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
6838
|
+
return { layerId: layer.id, decontaminate: pct2(e.decontaminate), despill: pct2(e.despill), ambient: pct2(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
|
|
6839
|
+
}
|
|
6840
|
+
requireEdgeLayer(id) {
|
|
6841
|
+
const layer = this.getLayer(id);
|
|
6842
|
+
if (!layer) throw new LayerOperationError(`There is no layer "${id}" (see list_layers).`);
|
|
6843
|
+
if (layer.type === "group" || layer.type === "adjustment" || layer.type === "annotation")
|
|
6844
|
+
throw new LayerOperationError(`Edge colour works on pixel, shape, type and smart object layers; "${layer.name || id}" is a ${layer.type} layer.`);
|
|
6845
|
+
return layer;
|
|
6846
|
+
}
|
|
6847
|
+
/** Whether the layer's mask (painted and vector, with feather) has a soft band. */
|
|
6848
|
+
maskHasSoftBand(layer) {
|
|
6849
|
+
const { width, height } = this.naturalSize;
|
|
6850
|
+
const mask = effectiveLayerMask(layer, width, height);
|
|
6851
|
+
if (!mask || mask.enabled === false || mask.source) return false;
|
|
6852
|
+
const ox = layer.type === "pixel" ? layer.offset.x : 0;
|
|
6853
|
+
const oy = layer.type === "pixel" ? layer.offset.y : 0;
|
|
6854
|
+
return hasSoftBand(maskCoverageOverCanvas(mask, ox, oy, width, height));
|
|
6855
|
+
}
|
|
6856
|
+
/**
|
|
6857
|
+
* Edge colour on a layer's soft edge, applied when compositing (nothing is baked); amounts in
|
|
6858
|
+
* percent, 0 turns one off. `decontaminate` unmixes the old background (the pixels the mask
|
|
6859
|
+
* hides) from the edge and `despill` limits its hue there: both need a pixel layer whose mask
|
|
6860
|
+
* (painted or vector) has a soft band. `ambient` pulls the edge toward what is behind the layer
|
|
6861
|
+
* (`ambientColor` null: sampled live) or a fixed `#rrggbb`; it needs a soft mask or soft
|
|
6862
|
+
* pixels at the edge. Validates everything before changing anything; one undo step (none with
|
|
6863
|
+
* `commitToHistory` false, for the later moves of a slider drag). Returns the effective settings.
|
|
6864
|
+
*/
|
|
6865
|
+
setEdgeColor(id, change, commitToHistory = true) {
|
|
6866
|
+
const layer = this.requireEdgeLayer(id);
|
|
6867
|
+
const name = layer.name || id;
|
|
6868
|
+
const next = { ...layer.edge ?? {} };
|
|
6869
|
+
for (const k of ["decontaminate", "despill", "ambient"]) {
|
|
6870
|
+
const v = change[k];
|
|
6871
|
+
if (v === void 0) continue;
|
|
6872
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < 0 || v > 100) throw new LayerOperationError(`${k} must be a percentage from 0 to 100, got ${String(v)}.`);
|
|
6873
|
+
if (v > 0) next[k] = v / 100;
|
|
6874
|
+
else delete next[k];
|
|
6875
|
+
}
|
|
6876
|
+
if (change.ambientColor !== void 0) {
|
|
6877
|
+
if (change.ambientColor === null || change.ambientColor === "auto") delete next.ambientColor;
|
|
6878
|
+
else {
|
|
6879
|
+
const m = /^#([0-9a-f]{6})$/i.exec(String(change.ambientColor));
|
|
6880
|
+
if (!m) throw new LayerOperationError(`ambient colour must be "auto" or #rrggbb, got "${String(change.ambientColor)}".`);
|
|
6881
|
+
const n = parseInt(m[1], 16);
|
|
6882
|
+
next.ambientColor = [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
const unmix = (next.decontaminate ?? 0) > 0 || (next.despill ?? 0) > 0;
|
|
6886
|
+
const turningOn = (k) => (change[k] ?? 0) > 0;
|
|
6887
|
+
if (unmix && (turningOn("decontaminate") || turningOn("despill"))) {
|
|
6888
|
+
if (layer.type !== "pixel") throw new LayerOperationError(`Decontamination and despill need a pixel layer with a soft-edged mask; "${name}" is a ${layer.type} layer (rasterize it, or use ambient).`);
|
|
6889
|
+
if (!this.maskHasSoftBand(layer))
|
|
6890
|
+
throw new LayerOperationError(`"${name}" has no mask with a soft edge: decontamination and despill work in the partly hidden band of a layer mask. Add one with add_layer_mask from a refined selection (refine_selection), or feather the mask (set_layer_mask_properties feather).`);
|
|
6891
|
+
}
|
|
6892
|
+
if (turningOn("ambient") && !this.maskHasSoftBand(layer) && layer.type === "pixel") {
|
|
6893
|
+
const px2 = this.getLayerPixels(layer.id);
|
|
6894
|
+
let soft = false;
|
|
6895
|
+
if (px2) for (let i = 3; i < px2.data.length && !soft; i += 4) soft = px2.data[i] > 5 && px2.data[i] < 250;
|
|
6896
|
+
if (!soft) throw new LayerOperationError(`"${name}" has no soft edge (no soft-edged mask and no partly transparent pixels) for the edge cast to work on.`);
|
|
6897
|
+
}
|
|
6898
|
+
const edge = next.decontaminate || next.despill || next.ambient || next.ambientColor ? next : void 0;
|
|
6899
|
+
this.commitLayers(
|
|
6900
|
+
mapLayer(this.state.layers, layer.id, (l) => {
|
|
6901
|
+
const out = { ...l };
|
|
6902
|
+
if (edge) out.edge = edge;
|
|
6903
|
+
else delete out.edge;
|
|
6904
|
+
return out;
|
|
6905
|
+
}),
|
|
6906
|
+
void 0,
|
|
6907
|
+
commitToHistory
|
|
6908
|
+
);
|
|
6909
|
+
return this.getEdgeColor(layer.id);
|
|
6910
|
+
}
|
|
6825
6911
|
/**
|
|
6826
6912
|
* Changes name, visibility, opacity, fill, blend, clipping, locks or (groups) collapsed state, as
|
|
6827
6913
|
* one undo step (`commitToHistory = false` for the moves of a slider drag). Returns the layer.
|
|
@@ -11372,7 +11458,9 @@ var ImageEditorController = class {
|
|
|
11372
11458
|
return baked;
|
|
11373
11459
|
};
|
|
11374
11460
|
const prepare = async (layer) => {
|
|
11461
|
+
if (layer.edge?.ambient) add2("The live edge cast (set_edge_ambient) has no PSD equivalent and was left out", layer.name);
|
|
11375
11462
|
const p = await prepareLayer(layer);
|
|
11463
|
+
if (p?.edge) delete p.edge;
|
|
11376
11464
|
if (p?.blend === "pigment") add2("The Pigment blend mode has no PSD equivalent and was written as Normal", layer.name);
|
|
11377
11465
|
return p;
|
|
11378
11466
|
};
|
|
@@ -11448,6 +11536,14 @@ var ImageEditorController = class {
|
|
|
11448
11536
|
}
|
|
11449
11537
|
if (layer.filters?.some((f) => !f.enabled)) add2("Disabled layer filters were left out", layer.name);
|
|
11450
11538
|
delete out.filters;
|
|
11539
|
+
const unmixMask = hasEdgeUnmix(layer.edge) ? effectiveLayerMask(layer, width, height) : void 0;
|
|
11540
|
+
if (unmixMask && !unmixMask.source && unmixMask.enabled !== false) {
|
|
11541
|
+
add2("Edge decontamination and despill were baked into the pixels", layer.name);
|
|
11542
|
+
const { x: ox, y: oy } = layer.offset;
|
|
11543
|
+
const data = readRegion(out.surface, { x: -ox, y: -oy, width, height });
|
|
11544
|
+
applyEdgeUnmix(data, maskCoverageOverCanvas(unmixMask, ox, oy, width, height), width, height, layer.edge);
|
|
11545
|
+
out = { ...out, surface: surfaceFromPixels({ width, height, data }, 4, -ox, -oy) };
|
|
11546
|
+
}
|
|
11451
11547
|
const mask = bakeMask(layer);
|
|
11452
11548
|
if (mask) out.mask = mask;
|
|
11453
11549
|
else delete out.mask;
|
|
@@ -14809,6 +14905,49 @@ function createImageLayerTools(controller) {
|
|
|
14809
14905
|
return { view: shown?.mode ?? "off", layerId: shown?.layerId ?? null };
|
|
14810
14906
|
}
|
|
14811
14907
|
};
|
|
14908
|
+
const AMOUNT = (what) => ({ type: "number", minimum: 0, maximum: 100, description: `${what}, in percent 0-100; 0 turns it off.` });
|
|
14909
|
+
const EDGE_RETURNS = "Returns the layer's effective edge colour: { layerId, decontaminate, despill, ambient (percent), ambientSource }.";
|
|
14910
|
+
const getEdge = {
|
|
14911
|
+
name: "get_edge_color",
|
|
14912
|
+
title: "Read edge colour",
|
|
14913
|
+
description: `A layer's edge colour settings, applied when compositing: decontaminate, despill and ambient (percent) and ambientSource (auto or #rrggbb). ${EDGE_RETURNS}`,
|
|
14914
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID2 }, required: ["layerId"], additionalProperties: false },
|
|
14915
|
+
annotations: { title: "Read edge colour", ...READ2 },
|
|
14916
|
+
handler: ({ layerId }) => controller.getEdgeColor(String(layerId))
|
|
14917
|
+
};
|
|
14918
|
+
const setDecontaminate = {
|
|
14919
|
+
name: "set_edge_decontamination",
|
|
14920
|
+
title: "Decontaminate edge colour",
|
|
14921
|
+
description: `Removes the old background's colour from a cutout's soft edge at composite time (nothing is baked; change or turn it off any time): each partly hidden edge pixel is unmixed from the background next to it (the pixels the layer's mask hides). Needs a pixel layer whose mask (painted or vector) has a soft band, e.g. add_layer_mask from a refined selection. Check with inspect_mask_edge (haloScore) and capture_view. One undo step. ${EDGE_RETURNS}`,
|
|
14922
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID2, amount: AMOUNT("How much to replace edge colour with the subject's own (80-100 typical)") }, required: ["layerId", "amount"], additionalProperties: false },
|
|
14923
|
+
annotations: { title: "Decontaminate edge colour", ...WRITE_IDEMPOTENT2 },
|
|
14924
|
+
handler: ({ layerId, amount }) => controller.setEdgeColor(String(layerId), { decontaminate: amount })
|
|
14925
|
+
};
|
|
14926
|
+
const setDespill = {
|
|
14927
|
+
name: "set_edge_despill",
|
|
14928
|
+
title: "Despill edge colour",
|
|
14929
|
+
description: `Limits how much of the old background's hue a cutout's soft edge carries (a green-screen or coloured-wall fringe), at composite time: the edge colour's component toward the background's hue is taken out, luminance kept, most at the outer edge. A heuristic: it does not remove light that bounced onto the subject itself. Needs a pixel layer whose mask has a soft band. Pixels fully inside the mask never change. One undo step. ${EDGE_RETURNS}`,
|
|
14930
|
+
inputSchema: { type: "object", properties: { layerId: LAYER_ID2, amount: AMOUNT("How much of the background hue to take out (50-100 typical)") }, required: ["layerId", "amount"], additionalProperties: false },
|
|
14931
|
+
annotations: { title: "Despill edge colour", ...WRITE_IDEMPOTENT2 },
|
|
14932
|
+
handler: ({ layerId, amount }) => controller.setEdgeColor(String(layerId), { despill: amount })
|
|
14933
|
+
};
|
|
14934
|
+
const setAmbient = {
|
|
14935
|
+
name: "set_edge_ambient",
|
|
14936
|
+
title: "Cast the scene onto an edge",
|
|
14937
|
+
description: `Tints a cutout's soft edge with what is behind it now, live at composite time, so a subject moved onto a new background picks up its colour at the edge (more where the edge is more transparent). source auto samples the layers below as they change; #rrggbb uses a fixed colour. Works on soft-edged masks or partly transparent pixels (pixel, shape, type and smart object layers). One undo step. ${EDGE_RETURNS}`,
|
|
14938
|
+
inputSchema: {
|
|
14939
|
+
type: "object",
|
|
14940
|
+
properties: {
|
|
14941
|
+
layerId: LAYER_ID2,
|
|
14942
|
+
amount: AMOUNT("How far edge colour moves toward the background (20-50 typical)"),
|
|
14943
|
+
source: { type: "string", pattern: "^(auto|#[0-9a-fA-F]{6})$", description: "auto (default): what is behind the layer, sampled live; or a fixed #rrggbb." }
|
|
14944
|
+
},
|
|
14945
|
+
required: ["layerId", "amount"],
|
|
14946
|
+
additionalProperties: false
|
|
14947
|
+
},
|
|
14948
|
+
annotations: { title: "Cast the scene onto an edge", ...WRITE_IDEMPOTENT2 },
|
|
14949
|
+
handler: ({ layerId, amount, source }) => controller.setEdgeColor(String(layerId), { ambient: amount, ambientColor: source ?? "auto" })
|
|
14950
|
+
};
|
|
14812
14951
|
const maskProps = {
|
|
14813
14952
|
name: "set_layer_mask_properties",
|
|
14814
14953
|
title: "Set layer mask properties",
|
|
@@ -14951,6 +15090,10 @@ function createImageLayerTools(controller) {
|
|
|
14951
15090
|
removeMask,
|
|
14952
15091
|
maskView,
|
|
14953
15092
|
maskProps,
|
|
15093
|
+
getEdge,
|
|
15094
|
+
setDecontaminate,
|
|
15095
|
+
setDespill,
|
|
15096
|
+
setAmbient,
|
|
14954
15097
|
viaCopy,
|
|
14955
15098
|
rasterize,
|
|
14956
15099
|
addFilter,
|
|
@@ -21578,6 +21721,7 @@ export {
|
|
|
21578
21721
|
DIRECT_GAUSSIAN_MAX_SIGMA,
|
|
21579
21722
|
DRY_EPS,
|
|
21580
21723
|
DabWalker,
|
|
21724
|
+
EDGE_COLOR_RADIUS,
|
|
21581
21725
|
EFFECT_LAYER_USES,
|
|
21582
21726
|
EMPTY_DISTANCE,
|
|
21583
21727
|
EMPTY_MIXER_LOAD,
|
|
@@ -21820,6 +21964,7 @@ export {
|
|
|
21820
21964
|
applyBoxBlur,
|
|
21821
21965
|
applyBoxBlurFloat,
|
|
21822
21966
|
applyDepthMask,
|
|
21967
|
+
applyEdgeUnmix,
|
|
21823
21968
|
applyHomography,
|
|
21824
21969
|
applyImageProjectionToContext,
|
|
21825
21970
|
applyLegacyAdjustments,
|
|
@@ -21995,6 +22140,7 @@ export {
|
|
|
21995
22140
|
deserializeMask,
|
|
21996
22141
|
deserializePatterns,
|
|
21997
22142
|
deserializeSelection,
|
|
22143
|
+
despillEdge,
|
|
21998
22144
|
developFilter,
|
|
21999
22145
|
developFromAdjustments,
|
|
22000
22146
|
developTarget,
|
|
@@ -22090,8 +22236,10 @@ export {
|
|
|
22090
22236
|
handleQuickMaskKey,
|
|
22091
22237
|
handleSelectionShortcut,
|
|
22092
22238
|
hasActiveEffects,
|
|
22239
|
+
hasEdgeUnmix,
|
|
22093
22240
|
hasLayersBelow,
|
|
22094
22241
|
hasResampledLegacyMask,
|
|
22242
|
+
hasSoftBand,
|
|
22095
22243
|
hasSurface,
|
|
22096
22244
|
hasWarp,
|
|
22097
22245
|
hash2,
|
|
@@ -22221,6 +22369,7 @@ export {
|
|
|
22221
22369
|
mapLayer,
|
|
22222
22370
|
mapSubpaths,
|
|
22223
22371
|
maskBounds,
|
|
22372
|
+
maskCoverageOverCanvas,
|
|
22224
22373
|
maskFileName,
|
|
22225
22374
|
maskNameFromFile,
|
|
22226
22375
|
maskSummary,
|
|
@@ -22363,6 +22512,7 @@ export {
|
|
|
22363
22512
|
rasterizeSmartObject,
|
|
22364
22513
|
readAdjustmentControls,
|
|
22365
22514
|
readDeepRegion,
|
|
22515
|
+
readEdgeColor,
|
|
22366
22516
|
readPaintSource,
|
|
22367
22517
|
readPaths,
|
|
22368
22518
|
readPixel,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge colour on a layer's soft edge (`LayerEdgeColor`): decontamination and despill, run over the
|
|
3
|
+
* canvas by the compositor from the layer's own pixels and its mask, so nothing is baked. The live
|
|
4
|
+
* edge cast (`ambient`) needs what is behind the layer and runs in the compositor's blend step.
|
|
5
|
+
*/
|
|
6
|
+
import type { LayerEdgeColor, RasterMask } from '../../raster/layers.cjs';
|
|
7
|
+
/** How far (px) the old background's colour is looked for around the edge. */
|
|
8
|
+
export declare const EDGE_COLOR_RADIUS = 8;
|
|
9
|
+
/** True when decontamination or despill is on (they need the layer's mask). */
|
|
10
|
+
export declare function hasEdgeUnmix(edge: LayerEdgeColor | undefined): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* A mask's coverage (0..255) over the canvas, `width × height`, for a layer at `offset`: the
|
|
13
|
+
* painted mask with its feather (density only changes how much shows, not the matte).
|
|
14
|
+
*/
|
|
15
|
+
export declare function maskCoverageOverCanvas(mask: RasterMask, ox: number, oy: number, width: number, height: number): Uint8ClampedArray;
|
|
16
|
+
/** True when a coverage has a soft band (some pixels partly covered). */
|
|
17
|
+
export declare function hasSoftBand(coverage: ArrayLike<number>): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Despill: along a soft edge, takes out (by `amount`, 0..1) the part of each pixel's colour that
|
|
20
|
+
* points the way of the old background's hue (its local mean, from what is fully outside within
|
|
21
|
+
* `radius`). Luminance is kept, pixels fully in or out are unchanged, and the outer edge (more
|
|
22
|
+
* background) gets the most. It does not remove light that bounced onto the subject itself.
|
|
23
|
+
* Works in place on RGBA `rgba` with `coverage` (0..255) over the same `w × h`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function despillEdge(rgba: Uint8ClampedArray, coverage: ArrayLike<number>, w: number, h: number, amount: number, radius?: number): void;
|
|
26
|
+
/** Decontamination, then despill, of canvas RGBA `rgba` (`w × h`) in place, given the mask's coverage. */
|
|
27
|
+
export declare function applyEdgeUnmix(rgba: Uint8ClampedArray, coverage: ArrayLike<number>, w: number, h: number, edge: LayerEdgeColor): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge colour on a layer's soft edge (`LayerEdgeColor`): decontamination and despill, run over the
|
|
3
|
+
* canvas by the compositor from the layer's own pixels and its mask, so nothing is baked. The live
|
|
4
|
+
* edge cast (`ambient`) needs what is behind the layer and runs in the compositor's blend step.
|
|
5
|
+
*/
|
|
6
|
+
import type { LayerEdgeColor, RasterMask } from '../../raster/layers.js';
|
|
7
|
+
/** How far (px) the old background's colour is looked for around the edge. */
|
|
8
|
+
export declare const EDGE_COLOR_RADIUS = 8;
|
|
9
|
+
/** True when decontamination or despill is on (they need the layer's mask). */
|
|
10
|
+
export declare function hasEdgeUnmix(edge: LayerEdgeColor | undefined): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* A mask's coverage (0..255) over the canvas, `width × height`, for a layer at `offset`: the
|
|
13
|
+
* painted mask with its feather (density only changes how much shows, not the matte).
|
|
14
|
+
*/
|
|
15
|
+
export declare function maskCoverageOverCanvas(mask: RasterMask, ox: number, oy: number, width: number, height: number): Uint8ClampedArray;
|
|
16
|
+
/** True when a coverage has a soft band (some pixels partly covered). */
|
|
17
|
+
export declare function hasSoftBand(coverage: ArrayLike<number>): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Despill: along a soft edge, takes out (by `amount`, 0..1) the part of each pixel's colour that
|
|
20
|
+
* points the way of the old background's hue (its local mean, from what is fully outside within
|
|
21
|
+
* `radius`). Luminance is kept, pixels fully in or out are unchanged, and the outer edge (more
|
|
22
|
+
* background) gets the most. It does not remove light that bounced onto the subject itself.
|
|
23
|
+
* Works in place on RGBA `rgba` with `coverage` (0..255) over the same `w × h`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function despillEdge(rgba: Uint8ClampedArray, coverage: ArrayLike<number>, w: number, h: number, amount: number, radius?: number): void;
|
|
26
|
+
/** Decontamination, then despill, of canvas RGBA `rgba` (`w × h`) in place, given the mask's coverage. */
|
|
27
|
+
export declare function applyEdgeUnmix(rgba: Uint8ClampedArray, coverage: ArrayLike<number>, w: number, h: number, edge: LayerEdgeColor): void;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema version 3 of the image editor document: the layer tree, with pixel layers and painted
|
|
3
|
+
* masks stored as PNG assets (cropped to their content and placed by position), plus the
|
|
4
|
+
* document-level crop, transform, output opacity, migrated blur and selection.
|
|
5
|
+
*
|
|
6
|
+
* Encoding is synchronous and exact (see `png.ts`). Each surface's encoding is memoised, so
|
|
7
|
+
* saving an unchanged layer again costs nothing.
|
|
8
|
+
*/
|
|
9
|
+
import type { LayerEdgeColor } from '../../raster/layers.cjs';
|
|
1
10
|
import type { SerializedDocumentPath } from '../paths.cjs';
|
|
2
11
|
import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.cjs';
|
|
3
12
|
import type { SerializedSelection } from '../selection/mask.cjs';
|
|
@@ -36,6 +45,8 @@ interface SerializedLayerBase {
|
|
|
36
45
|
vectorMask?: SerializedVectorMask;
|
|
37
46
|
locks?: LayerLocks;
|
|
38
47
|
effects?: SerializedLayerEffects;
|
|
48
|
+
/** Edge colour amounts 0..1 and the cast colour (see `LayerEdgeColor`). */
|
|
49
|
+
edge?: LayerEdgeColor;
|
|
39
50
|
}
|
|
40
51
|
/** A stored vector mask: its components as JSON (document pixels) and its properties. */
|
|
41
52
|
export interface SerializedVectorMask {
|
|
@@ -271,6 +282,8 @@ export interface SerializeContext {
|
|
|
271
282
|
/** Stores a smart object's contents (once per id). Without it, smart objects cannot be written. */
|
|
272
283
|
addContents?(contents: SmartContents): void;
|
|
273
284
|
}
|
|
285
|
+
/** Stored edge colour, with amounts clamped to 0..1 (none when nothing is on). */
|
|
286
|
+
export declare function readEdgeColor(raw: unknown): LayerEdgeColor | undefined;
|
|
274
287
|
export declare function serializeEffects(effects: LayerEffects): SerializedLayerEffects;
|
|
275
288
|
/** Reads stored effects (leniently: broken effects are dropped), or `undefined`. */
|
|
276
289
|
export declare function deserializeEffects(raw: unknown): LayerEffects | undefined;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema version 3 of the image editor document: the layer tree, with pixel layers and painted
|
|
3
|
+
* masks stored as PNG assets (cropped to their content and placed by position), plus the
|
|
4
|
+
* document-level crop, transform, output opacity, migrated blur and selection.
|
|
5
|
+
*
|
|
6
|
+
* Encoding is synchronous and exact (see `png.ts`). Each surface's encoding is memoised, so
|
|
7
|
+
* saving an unchanged layer again costs nothing.
|
|
8
|
+
*/
|
|
9
|
+
import type { LayerEdgeColor } from '../../raster/layers.js';
|
|
1
10
|
import type { SerializedDocumentPath } from '../paths.js';
|
|
2
11
|
import type { Annotation, CropBox, DepthMaskOptions, ImageTransform } from '../types.js';
|
|
3
12
|
import type { SerializedSelection } from '../selection/mask.js';
|
|
@@ -36,6 +45,8 @@ interface SerializedLayerBase {
|
|
|
36
45
|
vectorMask?: SerializedVectorMask;
|
|
37
46
|
locks?: LayerLocks;
|
|
38
47
|
effects?: SerializedLayerEffects;
|
|
48
|
+
/** Edge colour amounts 0..1 and the cast colour (see `LayerEdgeColor`). */
|
|
49
|
+
edge?: LayerEdgeColor;
|
|
39
50
|
}
|
|
40
51
|
/** A stored vector mask: its components as JSON (document pixels) and its properties. */
|
|
41
52
|
export interface SerializedVectorMask {
|
|
@@ -271,6 +282,8 @@ export interface SerializeContext {
|
|
|
271
282
|
/** Stores a smart object's contents (once per id). Without it, smart objects cannot be written. */
|
|
272
283
|
addContents?(contents: SmartContents): void;
|
|
273
284
|
}
|
|
285
|
+
/** Stored edge colour, with amounts clamped to 0..1 (none when nothing is on). */
|
|
286
|
+
export declare function readEdgeColor(raw: unknown): LayerEdgeColor | undefined;
|
|
274
287
|
export declare function serializeEffects(effects: LayerEffects): SerializedLayerEffects;
|
|
275
288
|
/** Reads stored effects (leniently: broken effects are dropped), or `undefined`. */
|
|
276
289
|
export declare function deserializeEffects(raw: unknown): LayerEffects | undefined;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var _chunkUC3PWFM3cjs = require('../chunk-UC3PWFM3.cjs');
|
|
4
|
+
require('../chunk-SS53NNZO.cjs');
|
|
5
5
|
require('../chunk-K6PXS6DO.cjs');
|
|
6
6
|
require('../chunk-MQDIP4CF.cjs');
|
|
7
7
|
require('../chunk-474IQG74.cjs');
|
|
8
8
|
|
|
9
9
|
// src/image-editor/selection-worker.ts
|
|
10
10
|
if (typeof self !== "undefined" && typeof window === "undefined" && typeof self.postMessage === "function") {
|
|
11
|
-
|
|
11
|
+
_chunkUC3PWFM3cjs.startSelectionWorker.call(void 0, self);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
exports.startSelectionWorker =
|
|
15
|
+
exports.startSelectionWorker = _chunkUC3PWFM3cjs.startSelectionWorker;
|