@pixerate/editor 0.214.0 → 0.216.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 +41 -0
- package/dist/image-editor/controller.d.ts +41 -0
- package/dist/image-editor/index.cjs +1461 -1125
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +384 -48
- 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/index.d.cts +1 -0
- package/dist/image-editor/selection/index.d.ts +1 -0
- package/dist/image-editor/selection/inspect.d.cts +9 -0
- package/dist/image-editor/selection/inspect.d.ts +9 -0
- package/dist/image-editor/selection/uncertainty.d.cts +40 -0
- package/dist/image-editor/selection/uncertainty.d.ts +40 -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 +9 -7
- package/skills/pixerate-image-editor/references/paths.md +12 -0
- package/skills/pixerate-image-selection-masking/SKILL.md +11 -11
|
@@ -2,12 +2,14 @@ import {
|
|
|
2
2
|
parseCssColor
|
|
3
3
|
} from "./chunk-3CI7FRMK.js";
|
|
4
4
|
import {
|
|
5
|
+
boxMean,
|
|
5
6
|
createSelectionMask,
|
|
6
7
|
decodeSelectionRle,
|
|
8
|
+
decontaminateColors,
|
|
7
9
|
encodeSelectionRle,
|
|
8
10
|
hashMaskContent,
|
|
9
11
|
resizeSelection
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZNA3IQZF.js";
|
|
11
13
|
import {
|
|
12
14
|
DEFAULT_GLOBAL_LIGHT,
|
|
13
15
|
DeepCompositor,
|
|
@@ -43,7 +45,7 @@ import {
|
|
|
43
45
|
validateEffectGradient,
|
|
44
46
|
validateLayerEffects,
|
|
45
47
|
warpSurface
|
|
46
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-QXY4YTRI.js";
|
|
47
49
|
import {
|
|
48
50
|
affineFromHomography,
|
|
49
51
|
applyHomography,
|
|
@@ -3419,6 +3421,68 @@ function unionRect(a, b) {
|
|
|
3419
3421
|
return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
|
|
3420
3422
|
}
|
|
3421
3423
|
|
|
3424
|
+
// src/image-editor/layers/edge-color.ts
|
|
3425
|
+
var EDGE_COLOR_RADIUS = 8;
|
|
3426
|
+
function hasEdgeUnmix(edge) {
|
|
3427
|
+
return Boolean(edge && ((edge.decontaminate ?? 0) > 0 || (edge.despill ?? 0) > 0));
|
|
3428
|
+
}
|
|
3429
|
+
function maskCoverageOverCanvas(mask, ox, oy, width, height) {
|
|
3430
|
+
const bytes = readRegion(mask.surface, { x: -ox, y: -oy, width, height });
|
|
3431
|
+
const feather = mask.feather ?? 0;
|
|
3432
|
+
if (!(feather > 0)) return new Uint8ClampedArray(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
3433
|
+
const v = new Float32Array(bytes.length);
|
|
3434
|
+
for (let i = 0; i < v.length; i++) v[i] = bytes[i];
|
|
3435
|
+
const blurred = gaussianBlur(v, width, height, feather, "clamp");
|
|
3436
|
+
return Uint8ClampedArray.from(blurred);
|
|
3437
|
+
}
|
|
3438
|
+
function hasSoftBand(coverage) {
|
|
3439
|
+
for (let i = 0; i < coverage.length; i++) if (coverage[i] > 5 && coverage[i] < 250) return true;
|
|
3440
|
+
return false;
|
|
3441
|
+
}
|
|
3442
|
+
function despillEdge(rgba, coverage, w, h, amount, radius = EDGE_COLOR_RADIUS) {
|
|
3443
|
+
const k = Math.min(1, Math.max(0, amount));
|
|
3444
|
+
if (!(k > 0)) return;
|
|
3445
|
+
const n = w * h;
|
|
3446
|
+
const out = new Float32Array(n);
|
|
3447
|
+
for (let i = 0; i < n; i++) out[i] = coverage[i] <= 5 ? 1 : 0;
|
|
3448
|
+
const weight = boxMean(out, w, h, radius);
|
|
3449
|
+
const mean = [0, 1, 2].map((c) => {
|
|
3450
|
+
const v = new Float32Array(n);
|
|
3451
|
+
for (let i = 0; i < n; i++) v[i] = rgba[i * 4 + c] * out[i];
|
|
3452
|
+
return boxMean(v, w, h, radius);
|
|
3453
|
+
});
|
|
3454
|
+
const luma = (r, g, b) => 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
3455
|
+
for (let i = 0; i < n; i++) {
|
|
3456
|
+
const c = coverage[i];
|
|
3457
|
+
if (c <= 5 || c >= 250 || weight[i] <= 1e-6) continue;
|
|
3458
|
+
const br = mean[0][i] / weight[i];
|
|
3459
|
+
const bg = mean[1][i] / weight[i];
|
|
3460
|
+
const bb = mean[2][i] / weight[i];
|
|
3461
|
+
const bl = luma(br, bg, bb);
|
|
3462
|
+
let ux = br - bl;
|
|
3463
|
+
let uy = bg - bl;
|
|
3464
|
+
let uz = bb - bl;
|
|
3465
|
+
const len = Math.hypot(ux, uy, uz);
|
|
3466
|
+
if (len < 4) continue;
|
|
3467
|
+
ux /= len;
|
|
3468
|
+
uy /= len;
|
|
3469
|
+
uz /= len;
|
|
3470
|
+
const p = i * 4;
|
|
3471
|
+
const l = luma(rgba[p], rgba[p + 1], rgba[p + 2]);
|
|
3472
|
+
const along = (rgba[p] - l) * ux + (rgba[p + 1] - l) * uy + (rgba[p + 2] - l) * uz;
|
|
3473
|
+
if (along <= 0) continue;
|
|
3474
|
+
const s = k * Math.min(1, 2 * (1 - c / 255)) * along;
|
|
3475
|
+
rgba[p] -= s * ux;
|
|
3476
|
+
rgba[p + 1] -= s * uy;
|
|
3477
|
+
rgba[p + 2] -= s * uz;
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
function applyEdgeUnmix(rgba, coverage, w, h, edge) {
|
|
3481
|
+
const d = edge.decontaminate ?? 0;
|
|
3482
|
+
if (d > 0) rgba.set(decontaminateColors(rgba, coverage, w, h, d, EDGE_COLOR_RADIUS));
|
|
3483
|
+
despillEdge(rgba, coverage, w, h, edge.despill ?? 0);
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3422
3486
|
// src/image-editor/layers/compositor.ts
|
|
3423
3487
|
var legacyViewCache = /* @__PURE__ */ new WeakMap();
|
|
3424
3488
|
function adjustmentNodeAsLayer(node) {
|
|
@@ -3496,6 +3560,31 @@ function filterReach(filters) {
|
|
|
3496
3560
|
return r;
|
|
3497
3561
|
}
|
|
3498
3562
|
var filterSpecCache = /* @__PURE__ */ new WeakMap();
|
|
3563
|
+
var maskIds = /* @__PURE__ */ new WeakMap();
|
|
3564
|
+
var nextMaskId = 1;
|
|
3565
|
+
var edgeSpecCache = /* @__PURE__ */ new WeakMap();
|
|
3566
|
+
function edgeFilterSpec(layer) {
|
|
3567
|
+
const edge = layer.edge;
|
|
3568
|
+
const mask = layer.mask;
|
|
3569
|
+
if (!hasEdgeUnmix(edge) || !mask || mask.enabled === false || mask.source) return pixelFilterSpec(layer);
|
|
3570
|
+
const hit = edgeSpecCache.get(layer);
|
|
3571
|
+
if (hit) return hit;
|
|
3572
|
+
let id = maskIds.get(mask.surface);
|
|
3573
|
+
if (id === void 0) maskIds.set(mask.surface, id = nextMaskId++);
|
|
3574
|
+
const filters = pixelFilterSpec(layer);
|
|
3575
|
+
const ox = layer.offset.x;
|
|
3576
|
+
const oy = layer.offset.y;
|
|
3577
|
+
const spec = {
|
|
3578
|
+
key: `edge:${JSON.stringify([edge.decontaminate ?? 0, edge.despill ?? 0, id, ox, oy, mask.feather ?? 0])}|${filters?.key ?? ""}`,
|
|
3579
|
+
spatial: true,
|
|
3580
|
+
apply: (data, width, height) => {
|
|
3581
|
+
filters?.apply(data, width, height);
|
|
3582
|
+
applyEdgeUnmix(data, maskCoverageOverCanvas(mask, ox, oy, width, height), width, height, edge);
|
|
3583
|
+
}
|
|
3584
|
+
};
|
|
3585
|
+
edgeSpecCache.set(layer, spec);
|
|
3586
|
+
return spec;
|
|
3587
|
+
}
|
|
3499
3588
|
function pixelFilterSpec(layer) {
|
|
3500
3589
|
const list2 = layer.filters;
|
|
3501
3590
|
if (!list2?.length) return null;
|
|
@@ -3523,7 +3612,7 @@ var PHOTO_PROFILE = {
|
|
|
3523
3612
|
/** Annotation layers draw with their annotation's blend mode unless the layer sets one. */
|
|
3524
3613
|
contentBlend: (l) => l.type === "annotation" && l.blend === "normal" && l.annotation.blend ? l.annotation.blend : l.blend,
|
|
3525
3614
|
layerKey: (l) => l.type === "pixel" ? [l.filters ?? null, l.source ?? null] : l.type === "adjustment" ? [l.kind, l.params] : l.type === "annotation" ? l.annotation : void 0,
|
|
3526
|
-
pixelFilters: (l) => l.type === "pixel" ?
|
|
3615
|
+
pixelFilters: (l) => l.type === "pixel" ? edgeFilterSpec(l) : null,
|
|
3527
3616
|
/**
|
|
3528
3617
|
* A smart object draws its rendered pixels (contents → placement → smart filters) like a pixel
|
|
3529
3618
|
* layer, and a shape layer the pixels rendered from its paths.
|
|
@@ -3557,7 +3646,7 @@ function compositeDeep(layers, rect, sources, depth) {
|
|
|
3557
3646
|
const deep = new DeepCompositor(new LayerCompositor(), PHOTO_PROFILE, {
|
|
3558
3647
|
applyFilterRunDeep: (run, acc, _r, masks) => applyAdjustmentLayersFloat(acc, run.map(adjustmentNodeAsLayer), masks),
|
|
3559
3648
|
pixelFiltersDeep: (l) => {
|
|
3560
|
-
if (l.type !== "pixel") return null;
|
|
3649
|
+
if (l.type !== "pixel" || hasEdgeUnmix(l.edge)) return null;
|
|
3561
3650
|
const filters = (l.filters ?? []).filter(isActiveFilter);
|
|
3562
3651
|
if (!filters.length) return null;
|
|
3563
3652
|
return { reach: filterReach(filters), apply: (data, width, height, linear) => runLayerFiltersFloat(data, width, height, filters, linear) };
|
|
@@ -5136,8 +5225,21 @@ function baseFields(layer, ctx) {
|
|
|
5136
5225
|
if (layer.vectorMask) out.vectorMask = serializeVectorMask(layer.vectorMask);
|
|
5137
5226
|
if (layer.locks && Object.values(layer.locks).some(Boolean)) out.locks = { ...layer.locks };
|
|
5138
5227
|
if (layer.effects) out.effects = serializeEffects(layer.effects);
|
|
5228
|
+
if (layer.edge) out.edge = { ...layer.edge, ...layer.edge.ambientColor ? { ambientColor: [...layer.edge.ambientColor] } : {} };
|
|
5139
5229
|
return out;
|
|
5140
5230
|
}
|
|
5231
|
+
function readEdgeColor(raw) {
|
|
5232
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
5233
|
+
const r = raw;
|
|
5234
|
+
const out = {};
|
|
5235
|
+
for (const k of ["decontaminate", "despill", "ambient"]) {
|
|
5236
|
+
const v = r[k];
|
|
5237
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) out[k] = Math.min(1, v);
|
|
5238
|
+
}
|
|
5239
|
+
const c = r.ambientColor;
|
|
5240
|
+
if (Array.isArray(c) && c.length === 3 && c.every((v) => typeof v === "number" && Number.isFinite(v))) out.ambientColor = c.map((v) => Math.min(255, Math.max(0, Math.round(v))));
|
|
5241
|
+
return out.decontaminate || out.despill || out.ambient || out.ambientColor ? out : void 0;
|
|
5242
|
+
}
|
|
5141
5243
|
function serializeEffects(effects) {
|
|
5142
5244
|
const out = { enabled: effects.enabled, items: JSON.parse(JSON.stringify(effects.items)) };
|
|
5143
5245
|
if (effects.scale !== void 0 && effects.scale !== 1) out.scale = effects.scale;
|
|
@@ -5597,6 +5699,8 @@ function deserializeLayer(raw, ctx) {
|
|
|
5597
5699
|
blend: normalizeBlendMode(r.blend)
|
|
5598
5700
|
};
|
|
5599
5701
|
if (r.clipped === true) base.clipped = true;
|
|
5702
|
+
const edge = readEdgeColor(r.edge);
|
|
5703
|
+
if (edge) base.edge = edge;
|
|
5600
5704
|
const mask = readMask(r.mask, ctx, `Layer "${base.name || id}"`);
|
|
5601
5705
|
if (mask) base.mask = mask;
|
|
5602
5706
|
if (r.vectorMask && typeof r.vectorMask === "object" && r.type !== "shape") {
|
|
@@ -11551,6 +11655,12 @@ export {
|
|
|
11551
11655
|
followLayerMove,
|
|
11552
11656
|
vectorMaskBounds,
|
|
11553
11657
|
vectorMaskThumbnail,
|
|
11658
|
+
EDGE_COLOR_RADIUS,
|
|
11659
|
+
hasEdgeUnmix,
|
|
11660
|
+
maskCoverageOverCanvas,
|
|
11661
|
+
hasSoftBand,
|
|
11662
|
+
despillEdge,
|
|
11663
|
+
applyEdgeUnmix,
|
|
11554
11664
|
adjustmentNodeAsLayer,
|
|
11555
11665
|
depthMaskAlpha,
|
|
11556
11666
|
runLayerFilters,
|
|
@@ -11668,6 +11778,7 @@ export {
|
|
|
11668
11778
|
encodeSurface,
|
|
11669
11779
|
encodeDeepSurface,
|
|
11670
11780
|
decodeDeepSurface,
|
|
11781
|
+
readEdgeColor,
|
|
11671
11782
|
serializeEffects,
|
|
11672
11783
|
deserializeEffects,
|
|
11673
11784
|
readShapeComponents,
|