@pixerate/editor 0.213.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.
Files changed (38) hide show
  1. package/dist/{chunk-UOGKSVRQ.cjs → chunk-B46UQUDC.cjs} +770 -733
  2. package/dist/{chunk-W3TOZTL7.js → chunk-F7Z2MKY2.js} +115 -4
  3. package/dist/{chunk-YBJXCQTR.js → chunk-QXY4YTRI.js} +738 -701
  4. package/dist/{chunk-H65IBXFI.cjs → chunk-S55JFWDA.cjs} +350 -239
  5. package/dist/{chunk-QYLWG22N.cjs → chunk-SS53NNZO.cjs} +304 -1
  6. package/dist/{chunk-LQ5SALHK.js → chunk-U7C655AM.js} +5 -311
  7. package/dist/{chunk-L52VMQZS.cjs → chunk-UC3PWFM3.cjs} +68 -374
  8. package/dist/{chunk-L3G23N5Y.js → chunk-ZNA3IQZF.js} +304 -1
  9. package/dist/image-editor/controller.d.cts +44 -0
  10. package/dist/image-editor/controller.d.ts +44 -0
  11. package/dist/image-editor/index.cjs +1768 -1140
  12. package/dist/image-editor/index.d.cts +1 -0
  13. package/dist/image-editor/index.d.ts +1 -0
  14. package/dist/image-editor/index.js +660 -32
  15. package/dist/image-editor/layers/edge-color.d.cts +27 -0
  16. package/dist/image-editor/layers/edge-color.d.ts +27 -0
  17. package/dist/image-editor/layers/serialize.d.cts +13 -0
  18. package/dist/image-editor/layers/serialize.d.ts +13 -0
  19. package/dist/image-editor/selection/index.d.cts +1 -0
  20. package/dist/image-editor/selection/index.d.ts +1 -0
  21. package/dist/image-editor/selection/inspect.d.cts +70 -0
  22. package/dist/image-editor/selection/inspect.d.ts +70 -0
  23. package/dist/image-editor/selection-worker.cjs +4 -4
  24. package/dist/image-editor/selection-worker.js +2 -2
  25. package/dist/paint-editor/index.cjs +79 -79
  26. package/dist/paint-editor/index.js +3 -3
  27. package/dist/raster/compositor.d.cts +10 -1
  28. package/dist/raster/compositor.d.ts +10 -1
  29. package/dist/raster/deep-compositor.d.cts +1 -1
  30. package/dist/raster/deep-compositor.d.ts +1 -1
  31. package/dist/raster/index.cjs +4 -2
  32. package/dist/raster/index.js +3 -1
  33. package/dist/raster/layers.d.cts +16 -0
  34. package/dist/raster/layers.d.ts +16 -0
  35. package/package.json +1 -1
  36. package/skills/pixerate-image-editor/SKILL.md +9 -6
  37. package/skills/pixerate-image-editor/references/paths.md +12 -0
  38. package/skills/pixerate-image-selection-masking/SKILL.md +17 -17
@@ -469,63 +469,6 @@ function stableStringify(v) {
469
469
  return JSON.stringify(v);
470
470
  }
471
471
 
472
- // src/raster/curve.ts
473
- var CURVE_LUT_SIZE = 4096;
474
- var clamp01 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
475
- function curveLut(points, size = CURVE_LUT_SIZE) {
476
- const pts = points.filter((p) => Number.isFinite(p.input) && Number.isFinite(p.output)).map((p) => [p.input, p.output]).sort((a, b) => a[0] - b[0]);
477
- const dedup = [];
478
- for (const p of pts) {
479
- if (dedup.length && Math.abs(dedup[dedup.length - 1][0] - p[0]) < 1e-6) continue;
480
- dedup.push(p);
481
- }
482
- const out = new Float32Array(size);
483
- const n = dedup.length;
484
- if (n < 2) {
485
- for (let k = 0; k < size; k++) out[k] = k / (size - 1);
486
- return out;
487
- }
488
- const x = dedup.map((p) => p[0]);
489
- const y = dedup.map((p) => p[1]);
490
- const m2 = new Float64Array(n);
491
- if (n > 2) {
492
- const c = new Float64Array(n);
493
- const d = new Float64Array(n);
494
- for (let i = 1; i < n - 1; i++) {
495
- const h0 = x[i] - x[i - 1];
496
- const h1 = x[i + 1] - x[i];
497
- const a = h0 / 6;
498
- const b = (h0 + h1) / 3;
499
- const cc = h1 / 6;
500
- const r = (y[i + 1] - y[i]) / h1 - (y[i] - y[i - 1]) / h0;
501
- const denom = b - a * c[i - 1];
502
- c[i] = cc / denom;
503
- d[i] = (r - a * d[i - 1]) / denom;
504
- }
505
- for (let i = n - 2; i >= 1; i--) m2[i] = d[i] - c[i] * m2[i + 1];
506
- }
507
- let seg = 0;
508
- for (let k = 0; k < size; k++) {
509
- const xv = k / (size - 1);
510
- if (xv <= x[0]) {
511
- out[k] = clamp01(y[0]);
512
- continue;
513
- }
514
- if (xv >= x[n - 1]) {
515
- out[k] = clamp01(y[n - 1]);
516
- continue;
517
- }
518
- while (seg < n - 2 && xv > x[seg + 1]) seg++;
519
- const x0 = x[seg], x1 = x[seg + 1];
520
- const h = x1 - x0;
521
- const a = (x1 - xv) / h;
522
- const b = (xv - x0) / h;
523
- const v = a * y[seg] + b * y[seg + 1] + ((a * a * a - a) * m2[seg] + (b * b * b - b) * m2[seg + 1]) * (h * h) / 6;
524
- out[k] = clamp01(v);
525
- }
526
- return out;
527
- }
528
-
529
472
  // src/raster/effects/patterns.ts
530
473
  var PatternTile = class {
531
474
 
@@ -655,6 +598,63 @@ function hashNoise(x, y) {
655
598
  return (h & 65535) / 65536;
656
599
  }
657
600
 
601
+ // src/raster/curve.ts
602
+ var CURVE_LUT_SIZE = 4096;
603
+ var clamp01 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
604
+ function curveLut(points, size = CURVE_LUT_SIZE) {
605
+ const pts = points.filter((p) => Number.isFinite(p.input) && Number.isFinite(p.output)).map((p) => [p.input, p.output]).sort((a, b) => a[0] - b[0]);
606
+ const dedup = [];
607
+ for (const p of pts) {
608
+ if (dedup.length && Math.abs(dedup[dedup.length - 1][0] - p[0]) < 1e-6) continue;
609
+ dedup.push(p);
610
+ }
611
+ const out = new Float32Array(size);
612
+ const n = dedup.length;
613
+ if (n < 2) {
614
+ for (let k = 0; k < size; k++) out[k] = k / (size - 1);
615
+ return out;
616
+ }
617
+ const x = dedup.map((p) => p[0]);
618
+ const y = dedup.map((p) => p[1]);
619
+ const m2 = new Float64Array(n);
620
+ if (n > 2) {
621
+ const c = new Float64Array(n);
622
+ const d = new Float64Array(n);
623
+ for (let i = 1; i < n - 1; i++) {
624
+ const h0 = x[i] - x[i - 1];
625
+ const h1 = x[i + 1] - x[i];
626
+ const a = h0 / 6;
627
+ const b = (h0 + h1) / 3;
628
+ const cc = h1 / 6;
629
+ const r = (y[i + 1] - y[i]) / h1 - (y[i] - y[i - 1]) / h0;
630
+ const denom = b - a * c[i - 1];
631
+ c[i] = cc / denom;
632
+ d[i] = (r - a * d[i - 1]) / denom;
633
+ }
634
+ for (let i = n - 2; i >= 1; i--) m2[i] = d[i] - c[i] * m2[i + 1];
635
+ }
636
+ let seg = 0;
637
+ for (let k = 0; k < size; k++) {
638
+ const xv = k / (size - 1);
639
+ if (xv <= x[0]) {
640
+ out[k] = clamp01(y[0]);
641
+ continue;
642
+ }
643
+ if (xv >= x[n - 1]) {
644
+ out[k] = clamp01(y[n - 1]);
645
+ continue;
646
+ }
647
+ while (seg < n - 2 && xv > x[seg + 1]) seg++;
648
+ const x0 = x[seg], x1 = x[seg + 1];
649
+ const h = x1 - x0;
650
+ const a = (x1 - xv) / h;
651
+ const b = (xv - x0) / h;
652
+ const v = a * y[seg] + b * y[seg + 1] + ((a * a * a - a) * m2[seg] + (b * b * b - b) * m2[seg + 1]) * (h * h) / 6;
653
+ out[k] = clamp01(v);
654
+ }
655
+ return out;
656
+ }
657
+
658
658
  // src/raster/effects/render.ts
659
659
  var INSIDE_EPS = 0.5 / 255;
660
660
  var INF = 1e20;
@@ -1927,486 +1927,94 @@ function renderLayerEffects(effects, layer, backdrop, canvas, ctx) {
1927
1927
  });
1928
1928
  }
1929
1929
 
1930
- // src/raster/deep-compositor.ts
1931
- var isGroup = (l) => l.type === "group";
1932
- var DeepCompositor = class {
1933
- constructor(base, profile, deep, depth) {
1934
- this.base = base;
1935
- this.profile = profile;
1936
- this.deep = deep;
1937
- this.depth = depth;
1938
- this.linear = depth === 32;
1939
- }
1940
-
1941
-
1942
-
1943
-
1944
-
1945
-
1946
- /** The composite of `layers` over `rect` as float RGBA in the working space (`rect.width × rect.height × 4`). */
1947
- composite(layers, rect, sources) {
1948
- this.sources = sources;
1949
- const acc = new Float32Array(Math.max(0, rect.width * rect.height * 4));
1950
- if (rect.width > 0 && rect.height > 0) this.runSteps(this.buildSteps(layers), acc, true, rect);
1951
- return acc;
1952
- }
1953
- // --- Steps (as RasterCompositor.buildSteps) ------------------------------------
1954
- isPixel(l) {
1955
- return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _2 => _2.profile, 'access', _3 => _3.isPixelLike, 'optionalCall', _4 => _4(l)]), () => ( false)));
1956
- }
1957
- isFilter(l) {
1958
- return _nullishCoalesce(_optionalChain([this, 'access', _5 => _5.profile, 'access', _6 => _6.isFilterLayer, 'optionalCall', _7 => _7(l)]), () => ( false));
1959
- }
1960
- buildSteps(layers) {
1961
- const steps = [];
1962
- for (const layer of layers) {
1963
- const last = steps[steps.length - 1];
1964
- if (layer.clipped && last && (last.kind === "content" || last.kind === "group")) {
1965
- last.clipped.push(layer);
1966
- continue;
1967
- }
1968
- if (this.isFilter(layer)) {
1969
- if (last && last.kind === "adjust") last.layers.push(layer);
1970
- else steps.push({ kind: "adjust", layers: [layer] });
1971
- } else if (isGroup(layer)) steps.push({ kind: "group", layer, clipped: [], steps: this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) });
1972
- else steps.push({ kind: "content", layer, clipped: [] });
1930
+ // src/raster/compositor.ts
1931
+ var TILE_PIXELS = _chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE;
1932
+ var TILE_BYTES = TILE_PIXELS * 4;
1933
+ function applyEdgeAmbient(content, below, coverage, amount, color2, max) {
1934
+ const k = Math.min(1, Math.max(0, amount));
1935
+ if (!(k > 0)) return;
1936
+ const n = content.length / 4;
1937
+ for (let i = 0; i < n; i++) {
1938
+ const a = content[i * 4 + 3] / max * (coverage ? coverage[i] : 1);
1939
+ if (a <= 0 || a >= 1) continue;
1940
+ let r;
1941
+ let g;
1942
+ let b;
1943
+ if (color2) [r, g, b] = color2;
1944
+ else {
1945
+ if (!(below[i * 4 + 3] > 0)) continue;
1946
+ r = below[i * 4];
1947
+ g = below[i * 4 + 1];
1948
+ b = below[i * 4 + 2];
1973
1949
  }
1974
- return steps;
1950
+ const t = k * (1 - a);
1951
+ content[i * 4] += t * (r - content[i * 4]);
1952
+ content[i * 4 + 1] += t * (g - content[i * 4 + 1]);
1953
+ content[i * 4 + 2] += t * (b - content[i * 4 + 2]);
1975
1954
  }
1976
- runSteps(steps, acc, empty, r) {
1977
- for (const s of steps) empty = this.runStep(s, acc, empty, r);
1978
- return empty;
1955
+ }
1956
+ function sameSig(a, b) {
1957
+ if (!a || a.key !== b.key || a.refs.length !== b.refs.length) return false;
1958
+ for (let i = 0; i < a.refs.length; i++) if (a.refs[i] !== b.refs[i]) return false;
1959
+ return true;
1960
+ }
1961
+ function dirtyInTile(rects, tx, ty) {
1962
+ let x0 = Infinity;
1963
+ let y0 = Infinity;
1964
+ let x1 = -Infinity;
1965
+ let y1 = -Infinity;
1966
+ const ox = tx * _chunk474IQG74cjs.TILE;
1967
+ const oy = ty * _chunk474IQG74cjs.TILE;
1968
+ for (const r of rects) {
1969
+ const a = Math.max(ox, Math.floor(r.x));
1970
+ const b = Math.max(oy, Math.floor(r.y));
1971
+ const c = Math.min(ox + _chunk474IQG74cjs.TILE, Math.ceil(r.x + r.width));
1972
+ const d = Math.min(oy + _chunk474IQG74cjs.TILE, Math.ceil(r.y + r.height));
1973
+ if (c <= a || d <= b) continue;
1974
+ x0 = Math.min(x0, a);
1975
+ y0 = Math.min(y0, b);
1976
+ x1 = Math.max(x1, c);
1977
+ y1 = Math.max(y1, d);
1979
1978
  }
1980
- runStep(step, acc, empty, r) {
1981
- if (step.kind === "adjust") {
1982
- if (empty) return true;
1983
- this.applyFilterRun(step.layers, acc, r);
1984
- return false;
1979
+ return x0 === Infinity ? null : { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
1980
+ }
1981
+ function blendTile(dst, src, mode, alpha, coverage) {
1982
+ if (!(alpha > 0)) return;
1983
+ const normal = mode === "normal";
1984
+ const pigment = mode === "pigment";
1985
+ const lut = !normal && _chunkOLNIPTB3cjs.isSeparableBlendMode.call(void 0, mode) ? separableLut(mode) : null;
1986
+ const cb = [0, 0, 0];
1987
+ const cs = [0, 0, 0];
1988
+ const n = dst.length;
1989
+ for (let i = 0, p = 0; i < n; i += 4, p++) {
1990
+ const sa = src[i + 3];
1991
+ if (sa === 0) continue;
1992
+ const k = coverage ? alpha * coverage[p] : alpha;
1993
+ if (!(k > 0)) continue;
1994
+ if (normal && sa === 255 && k >= 1) {
1995
+ dst[i] = src[i];
1996
+ dst[i + 1] = src[i + 1];
1997
+ dst[i + 2] = src[i + 2];
1998
+ dst[i + 3] = 255;
1999
+ continue;
1985
2000
  }
1986
- const layer = step.layer;
1987
- if (!layer.visible) return empty;
1988
- const clipped = step.clipped.filter((l) => l.visible);
1989
- if ((step.kind === "content" || step.kind === "group") && this.deepEffects(layer)) return this.runEffects(layer, clipped, acc, r, step.kind === "group" ? step.steps : null) ? false : empty;
1990
- const coverage = this.renderedAlone(layer) ? null : this.base.maskCoverage(layer, r, this.sources);
1991
- if (coverage && coverage.every((v) => v <= 0)) return empty;
1992
- if (step.kind === "group" && !this.renderedAlone(layer)) {
1993
- if (layer.blend === "pass-through" && !clipped.length) {
1994
- if (layer.opacity >= 1 && !coverage) return this.runSteps(step.steps, acc, empty, r);
1995
- const before = acc.slice();
1996
- const stillEmpty = this.runSteps(step.steps, acc, empty, r);
1997
- lerp(acc, before, layer.opacity, coverage);
1998
- return empty && stillEmpty;
1999
- }
2000
- const buf2 = new Float32Array(acc.length);
2001
- if (this.runSteps(step.steps, buf2, true, r)) return empty;
2002
- this.applyClipped(clipped, buf2, r);
2003
- const mode2 = layer.blend === "pass-through" ? "normal" : layer.blend;
2004
- this.blend(acc, buf2, mode2, layer.opacity, coverage);
2005
- return false;
2001
+ const as = sa / 255 * k;
2002
+ const ab = dst[i + 3] / 255;
2003
+ const ao = as + ab * (1 - as);
2004
+ if (ao <= 0) {
2005
+ dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
2006
+ continue;
2006
2007
  }
2007
- const content = this.content(layer, r);
2008
- if (!content) return empty;
2009
- const alone = this.renderedAlone(layer);
2010
- const fill2 = !alone && this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1;
2011
- const mode = this.blendOf(layer);
2012
- if (!clipped.length) {
2013
- this.blend(acc, content, mode, layer.opacity * fill2, coverage);
2014
- return false;
2015
- }
2016
- const buf = new Float32Array(acc.length);
2017
- this.blend(buf, content, "normal", fill2, coverage);
2018
- this.applyClipped(clipped, buf, r);
2019
- this.blend(acc, buf, mode, layer.opacity, null);
2020
- return false;
2021
- }
2022
- /**
2023
- * A pixel layer with effects onto `acc` over `r`: its deep content (filters, mask, clipped
2024
- * layers) and the effects composited in float. Effect maps come from the 8-bit shape. At 32
2025
- * bits the effects composite in sRGB-encoded values (their colours and blends are defined
2026
- * there) and the result is decoded back. Returns whether anything was drawn.
2027
- */
2028
- runEffects(layer, clipped, acc, r, groupSteps = null) {
2029
- const fx = this.base.effectsInput(layer, r, this.sources);
2030
- if (!fx) return false;
2031
- const a = fx.rect;
2032
- let content;
2033
- if (groupSteps) {
2034
- content = new Float32Array(a.width * a.height * 4);
2035
- this.runSteps(groupSteps, content, true, a);
2036
- } else content = _nullishCoalesce(this.content(layer, a), () => ( new Float32Array(a.width * a.height * 4)));
2037
- const coverage = this.base.maskCoverage(layer, a, this.sources);
2038
- if (coverage) for (let i = 0; i < coverage.length; i++) content[i * 4 + 3] *= coverage[i];
2039
- if (clipped.length) this.applyClipped(clipped, content, a);
2040
- const sub = new Float32Array(a.width * a.height * 4);
2041
- for (let y = 0; y < a.height; y++) {
2042
- const s = ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4;
2043
- sub.set(acc.subarray(s, s + a.width * 4), y * a.width * 4);
2044
- }
2045
- if (this.linear) {
2046
- encodeInPlace(sub);
2047
- encodeInPlace(content);
2048
- }
2049
- compositeLayerEffects({ ...fx, backdrop: sub, content });
2050
- if (this.linear) decodeInPlace(sub);
2051
- for (let y = 0; y < a.height; y++) acc.set(sub.subarray(y * a.width * 4, (y + 1) * a.width * 4), ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4);
2052
- return true;
2053
- }
2054
- applyClipped(clipped, buf, r) {
2055
- let run = [];
2056
- const flush = () => {
2057
- if (run.length) this.applyFilterRun(run, buf, r);
2058
- run = [];
2059
- };
2060
- for (const c of clipped) {
2061
- if (this.isFilter(c)) {
2062
- run.push(c);
2063
- continue;
2064
- }
2065
- flush();
2066
- const alone = this.renderedAlone(c);
2067
- const coverage = alone ? null : this.base.maskCoverage(c, r, this.sources);
2068
- let src;
2069
- if (isGroup(c) && !alone) {
2070
- src = new Float32Array(buf.length);
2071
- if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), src, true, r)) continue;
2072
- } else src = this.content(c, r);
2073
- if (!src) continue;
2074
- const fill2 = !alone && this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
2075
- const keep = new Float32Array(buf.length >> 2);
2076
- for (let i = 3, p = 0; i < buf.length; i += 4, p++) keep[p] = buf[i];
2077
- this.blend(buf, src, c.blend === "pass-through" ? "normal" : this.blendOf(c), c.opacity * fill2, coverage);
2078
- for (let i = 3, p = 0; i < buf.length; i += 4, p++) buf[i] = keep[p];
2079
- }
2080
- flush();
2081
- }
2082
- applyFilterRun(layers, acc, r) {
2083
- const visible = [];
2084
- let masks;
2085
- for (const node of layers) {
2086
- if (!node.visible) continue;
2087
- const cov = this.base.maskCoverage(node, r, this.sources);
2088
- if (cov) {
2089
- if (cov.every((v) => v <= 0)) continue;
2090
- (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
2091
- }
2092
- visible.push(node);
2093
- }
2094
- if (!visible.length) return;
2095
- if (this.deep.applyFilterRunDeep) {
2096
- if (this.linear) mapColour(acc, _chunkOLNIPTB3cjs.srgbEncode);
2097
- this.deep.applyFilterRunDeep(visible, acc, r, masks, this.sources);
2098
- if (this.linear) mapColour(acc, _chunkOLNIPTB3cjs.srgbDecode);
2099
- return;
2100
- }
2101
- const bytes = this.to8(acc);
2102
- _optionalChain([this, 'access', _8 => _8.profile, 'access', _9 => _9.applyFilterRun, 'optionalCall', _10 => _10(visible, bytes, r, masks, this.sources)]);
2103
- acc.set(this.from8(bytes));
2104
- }
2105
- // --- Layer content ---------------------------------------------------------------
2106
- /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
2107
- /** A pixel(-like) layer or a group with effects: composited in float through `compositeLayerEffects`. */
2108
- deepEffects(layer) {
2109
- return hasActiveEffects(layer.effects) && !this.isFilter(layer) && (isGroup(layer) || this.isPixel(layer));
2110
- }
2111
- renderedAlone(layer) {
2112
- if (hasActiveEffects(layer.effects) && !this.isFilter(layer) && !this.deepEffects(layer)) return true;
2113
- if (this.isPixel(layer)) return Boolean(_optionalChain([this, 'access', _11 => _11.profile, 'access', _12 => _12.pixelFilters, 'optionalCall', _13 => _13(layer)])) && !_optionalChain([this, 'access', _14 => _14.deep, 'access', _15 => _15.pixelFiltersDeep, 'optionalCall', _16 => _16(layer)]);
2114
- return !isGroup(layer);
2115
- }
2116
- blendOf(layer) {
2117
- return _nullishCoalesce(_optionalChain([this, 'access', _17 => _17.profile, 'access', _18 => _18.contentBlend, 'optionalCall', _19 => _19(layer)]), () => ( layer.blend));
2118
- }
2119
- /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
2120
- content(layer, r) {
2121
- if (this.renderedAlone(layer)) {
2122
- const solo = { ...layer, blend: isGroup(layer) && layer.blend === "pass-through" ? "pass-through" : "normal", opacity: 1, clipped: false };
2123
- const bytes = this.base.composite([solo], r, this.sources);
2124
- return this.from8(bytes);
2125
- }
2126
- const surface = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
2127
- if (!surface) return null;
2128
- const ox = _nullishCoalesce(_optionalChain([layer, 'access', _20 => _20.offset, 'optionalAccess', _21 => _21.x]), () => ( 0));
2129
- const oy = _nullishCoalesce(_optionalChain([layer, 'access', _22 => _22.offset, 'optionalAccess', _23 => _23.y]), () => ( 0));
2130
- const filters = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([this, 'access', _24 => _24.deep, 'access', _25 => _25.pixelFiltersDeep, 'optionalCall', _26 => _26(layer)]), () => ( null)) : null;
2131
- if (!filters) return this.samples(surface, { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height });
2132
- const m = filters.reach;
2133
- const W = this.sources.width;
2134
- const H = this.sources.height;
2135
- const x0 = m ? Math.max(0, r.x - m) : r.x;
2136
- const y0 = m ? Math.max(0, r.y - m) : r.y;
2137
- const x1 = m ? Math.min(W, r.x + r.width + m) : r.x + r.width;
2138
- const y1 = m ? Math.min(H, r.y + r.height + m) : r.y + r.height;
2139
- if (x1 <= x0 || y1 <= y0) return new Float32Array(r.width * r.height * 4);
2140
- const big = { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
2141
- const data = this.samples(surface, { ...big, x: big.x - ox, y: big.y - oy });
2142
- filters.apply(data, big.width, big.height, this.linear);
2143
- if (big.x === r.x && big.y === r.y && big.width === r.width && big.height === r.height) return data;
2144
- const out = new Float32Array(r.width * r.height * 4);
2145
- for (let y = 0; y < r.height; y++) {
2146
- const sy = r.y + y - big.y;
2147
- if (sy < 0 || sy >= big.height) continue;
2148
- for (let x = 0; x < r.width; x++) {
2149
- const sx = r.x + x - big.x;
2150
- if (sx < 0 || sx >= big.width) continue;
2151
- const s = (sy * big.width + sx) * 4;
2152
- const d = (y * r.width + x) * 4;
2153
- out[d] = data[s];
2154
- out[d + 1] = data[s + 1];
2155
- out[d + 2] = data[s + 2];
2156
- out[d + 3] = data[s + 3];
2157
- }
2158
- }
2159
- return out;
2160
- }
2161
- /** A surface's samples over `rect` (layer space) in the working space. */
2162
- samples(surface, rect) {
2163
- const samples = _chunkOLNIPTB3cjs.readDeepRegion.call(void 0, surface, rect, this.depth);
2164
- if (samples instanceof Float32Array) return samples;
2165
- const out = new Float32Array(samples.length);
2166
- for (let i = 0; i < samples.length; i++) out[i] = samples[i] / 65535;
2167
- return out;
2168
- }
2169
- /** 8-bit RGBA to the working space. */
2170
- from8(bytes) {
2171
- if (this.linear) return _chunkOLNIPTB3cjs.to32From8.call(void 0, bytes, 4);
2172
- const out = new Float32Array(bytes.length);
2173
- for (let i = 0; i < bytes.length; i++) out[i] = bytes[i] / 255;
2174
- return out;
2175
- }
2176
- /** The working space to 8-bit RGBA. */
2177
- to8(acc) {
2178
- const out = new Uint8ClampedArray(acc.length);
2179
- for (let i = 0; i < acc.length; i += 4) {
2180
- for (let c = 0; c < 3; c++) out[i + c] = Math.round((this.linear ? _chunkOLNIPTB3cjs.srgbEncode.call(void 0, acc[i + c]) : acc[i + c]) * 255);
2181
- out[i + 3] = Math.round(acc[i + 3] * 255);
2182
- }
2183
- return out;
2184
- }
2185
- // --- Blending --------------------------------------------------------------------
2186
- /** `src` over `dst` with `mode` at `alpha` × coverage (straight alpha, float), as `blendTile`. */
2187
- blend(dst, src, mode, alpha, coverage) {
2188
- if (!(alpha > 0)) return;
2189
- const normal = mode === "normal";
2190
- const pigment = mode === "pigment";
2191
- const cb = [0, 0, 0];
2192
- const cs = [0, 0, 0];
2193
- const mix = [0, 0, 0];
2194
- for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
2195
- const sa = src[i + 3];
2196
- if (!(sa > 0)) continue;
2197
- const k = coverage ? alpha * coverage[p] : alpha;
2198
- if (!(k > 0)) continue;
2199
- const as = Math.min(1, sa * k);
2200
- const ab = dst[i + 3];
2201
- const ao = as + ab * (1 - as);
2202
- if (ao <= 0) {
2203
- dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
2204
- continue;
2205
- }
2206
- if (normal && as >= 1) {
2207
- dst[i] = src[i];
2208
- dst[i + 1] = src[i + 1];
2209
- dst[i + 2] = src[i + 2];
2210
- dst[i + 3] = 1;
2211
- continue;
2212
- }
2213
- for (let c = 0; c < 3; c++) {
2214
- cb[c] = dst[i + c];
2215
- cs[c] = src[i + c];
2216
- }
2217
- if (pigment) {
2218
- if (this.linear) for (let c = 0; c < 3; c++) cb[c] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, cb[c]), cs[c] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, cs[c]);
2219
- _chunkOLNIPTB3cjs.mixPigmentRgb.call(void 0, cb, cs, as / ao, mix);
2220
- for (let c = 0; c < 3; c++) dst[i + c] = this.linear ? _chunkOLNIPTB3cjs.srgbDecode.call(void 0, mix[c]) : mix[c];
2221
- dst[i + 3] = ao;
2222
- continue;
2223
- }
2224
- const m = normal ? cs : _chunkOLNIPTB3cjs.blendRgb.call(void 0, mode, cb, cs);
2225
- const wb = (1 - as) * ab;
2226
- const ws = (1 - ab) * as;
2227
- const wm = as * ab;
2228
- for (let c = 0; c < 3; c++) dst[i + c] = (wb * cb[c] + ws * cs[c] + wm * m[c]) / ao;
2229
- dst[i + 3] = ao;
2230
- }
2231
- }
2232
- };
2233
- function lerp(dst, before, alpha, coverage) {
2234
- for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
2235
- const k = coverage ? alpha * coverage[p] : alpha;
2236
- if (k >= 1) continue;
2237
- for (let c = 0; c < 4; c++) dst[i + c] = before[i + c] + (dst[i + c] - before[i + c]) * k;
2238
- }
2239
- }
2240
- function mapColour(data, f) {
2241
- for (let i = 0; i < data.length; i += 4) {
2242
- data[i] = f(data[i]);
2243
- data[i + 1] = f(data[i + 1]);
2244
- data[i + 2] = f(data[i + 2]);
2245
- }
2246
- }
2247
- function workingToSamples(data, depth) {
2248
- if (depth === 32) return data;
2249
- const out = new Uint16Array(data.length);
2250
- for (let i = 0; i < data.length; i++) {
2251
- const v = data[i];
2252
- out[i] = v > 0 ? v < 1 ? Math.round(v * 65535) : 65535 : 0;
2253
- }
2254
- return out;
2255
- }
2256
- function encodeInPlace(d) {
2257
- for (let i = 0; i < d.length; i += 4) {
2258
- d[i] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i]);
2259
- d[i + 1] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i + 1]);
2260
- d[i + 2] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i + 2]);
2261
- }
2262
- }
2263
- function decodeInPlace(d) {
2264
- for (let i = 0; i < d.length; i += 4) {
2265
- d[i] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i]);
2266
- d[i + 1] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i + 1]);
2267
- d[i + 2] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i + 2]);
2268
- }
2269
- }
2270
-
2271
- // src/raster/layers.ts
2272
- var childrenOf = (l) => l.type === "group" ? _nullishCoalesce(l.children, () => ( null)) : null;
2273
- function flattenLayers(layers) {
2274
- const out = [];
2275
- const walk = (list) => {
2276
- for (const l of list) {
2277
- out.push(l);
2278
- const c = childrenOf(l);
2279
- if (c) walk(c);
2280
- }
2281
- };
2282
- walk(layers);
2283
- return out;
2284
- }
2285
- function findLayer(layers, id) {
2286
- const walk = (list, parent, path) => {
2287
- for (let i = 0; i < list.length; i++) {
2288
- const l = list[i];
2289
- if (l.id === id) return { layer: l, parent, index: i, path };
2290
- const c = childrenOf(l);
2291
- if (c) {
2292
- const g = l;
2293
- const hit = walk(c, g, [...path, g]);
2294
- if (hit) return hit;
2295
- }
2296
- }
2297
- return null;
2298
- };
2299
- return walk(layers, null, []);
2300
- }
2301
- function mapLayer(layers, id, fn) {
2302
- let changed = false;
2303
- const walk = (list) => {
2304
- let out = null;
2305
- for (let i = 0; i < list.length; i++) {
2306
- const l = list[i];
2307
- let next = l;
2308
- if (l.id === id) {
2309
- next = fn(l);
2310
- changed = true;
2311
- } else {
2312
- const c = childrenOf(l);
2313
- if (c) {
2314
- const children = walk(c);
2315
- if (children !== c) next = { ...l, children };
2316
- }
2317
- }
2318
- if (next !== l) {
2319
- if (!out) out = list.slice(0, i);
2320
- if (next) out.push(next);
2321
- } else if (out) out.push(l);
2322
- }
2323
- return _nullishCoalesce(out, () => ( list));
2324
- };
2325
- const result = walk(layers);
2326
- return changed ? result : layers;
2327
- }
2328
- function insertLayer(layers, layer, parentId, index) {
2329
- const put = (list) => {
2330
- const at = index === void 0 ? list.length : Math.max(0, Math.min(list.length, index));
2331
- const next = list.slice();
2332
- next.splice(at, 0, layer);
2333
- return next;
2334
- };
2335
- if (!parentId) return put(layers);
2336
- return mapLayer(layers, parentId, (g) => {
2337
- const c = childrenOf(g);
2338
- return c ? { ...g, children: put(c) } : g;
2339
- });
2340
- }
2341
- function isLayerLocked(layer, what) {
2342
- return Boolean(_optionalChain([layer, 'access', _27 => _27.locks, 'optionalAccess', _28 => _28.all]) || _optionalChain([layer, 'access', _29 => _29.locks, 'optionalAccess', _30 => _30[what]]));
2343
- }
2344
-
2345
- // src/raster/compositor.ts
2346
- var TILE_PIXELS = _chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE;
2347
- var TILE_BYTES = TILE_PIXELS * 4;
2348
- function sameSig(a, b) {
2349
- if (!a || a.key !== b.key || a.refs.length !== b.refs.length) return false;
2350
- for (let i = 0; i < a.refs.length; i++) if (a.refs[i] !== b.refs[i]) return false;
2351
- return true;
2352
- }
2353
- function dirtyInTile(rects, tx, ty) {
2354
- let x0 = Infinity;
2355
- let y0 = Infinity;
2356
- let x1 = -Infinity;
2357
- let y1 = -Infinity;
2358
- const ox = tx * _chunk474IQG74cjs.TILE;
2359
- const oy = ty * _chunk474IQG74cjs.TILE;
2360
- for (const r of rects) {
2361
- const a = Math.max(ox, Math.floor(r.x));
2362
- const b = Math.max(oy, Math.floor(r.y));
2363
- const c = Math.min(ox + _chunk474IQG74cjs.TILE, Math.ceil(r.x + r.width));
2364
- const d = Math.min(oy + _chunk474IQG74cjs.TILE, Math.ceil(r.y + r.height));
2365
- if (c <= a || d <= b) continue;
2366
- x0 = Math.min(x0, a);
2367
- y0 = Math.min(y0, b);
2368
- x1 = Math.max(x1, c);
2369
- y1 = Math.max(y1, d);
2370
- }
2371
- return x0 === Infinity ? null : { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
2372
- }
2373
- function blendTile(dst, src, mode, alpha, coverage) {
2374
- if (!(alpha > 0)) return;
2375
- const normal = mode === "normal";
2376
- const pigment = mode === "pigment";
2377
- const lut = !normal && _chunkOLNIPTB3cjs.isSeparableBlendMode.call(void 0, mode) ? separableLut(mode) : null;
2378
- const cb = [0, 0, 0];
2379
- const cs = [0, 0, 0];
2380
- const n = dst.length;
2381
- for (let i = 0, p = 0; i < n; i += 4, p++) {
2382
- const sa = src[i + 3];
2383
- if (sa === 0) continue;
2384
- const k = coverage ? alpha * coverage[p] : alpha;
2385
- if (!(k > 0)) continue;
2386
- if (normal && sa === 255 && k >= 1) {
2387
- dst[i] = src[i];
2388
- dst[i + 1] = src[i + 1];
2389
- dst[i + 2] = src[i + 2];
2390
- dst[i + 3] = 255;
2391
- continue;
2392
- }
2393
- const as = sa / 255 * k;
2394
- const ab = dst[i + 3] / 255;
2395
- const ao = as + ab * (1 - as);
2396
- if (ao <= 0) {
2397
- dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
2398
- continue;
2399
- }
2400
- const d0 = dst[i];
2401
- const d1 = dst[i + 1];
2402
- const d2 = dst[i + 2];
2403
- if (pigment) {
2404
- _chunkOLNIPTB3cjs.mixPigment8.call(void 0, d0, d1, d2, src[i], src[i + 1], src[i + 2], as / ao, cb);
2405
- dst[i] = Math.round(cb[0] * 255);
2406
- dst[i + 1] = Math.round(cb[1] * 255);
2407
- dst[i + 2] = Math.round(cb[2] * 255);
2408
- dst[i + 3] = Math.round(ao * 255);
2409
- continue;
2008
+ const d0 = dst[i];
2009
+ const d1 = dst[i + 1];
2010
+ const d2 = dst[i + 2];
2011
+ if (pigment) {
2012
+ _chunkOLNIPTB3cjs.mixPigment8.call(void 0, d0, d1, d2, src[i], src[i + 1], src[i + 2], as / ao, cb);
2013
+ dst[i] = Math.round(cb[0] * 255);
2014
+ dst[i + 1] = Math.round(cb[1] * 255);
2015
+ dst[i + 2] = Math.round(cb[2] * 255);
2016
+ dst[i + 3] = Math.round(ao * 255);
2017
+ continue;
2410
2018
  }
2411
2019
  const b0 = d0 / 255;
2412
2020
  const b1 = d1 / 255;
@@ -2470,7 +2078,7 @@ function lerpTile(dst, before, alpha, coverage) {
2470
2078
  }
2471
2079
  }
2472
2080
  var ZERO_TILE = new Uint8ClampedArray(TILE_BYTES);
2473
- var isGroup2 = (l) => l.type === "group";
2081
+ var isGroup = (l) => l.type === "group";
2474
2082
  var maskDepths = /* @__PURE__ */ new WeakMap();
2475
2083
  function maskDepth(surface) {
2476
2084
  let d = maskDepths.get(surface);
@@ -2562,7 +2170,7 @@ var RasterCompositor = (_class = class {
2562
2170
  const dirty = grow > 0 ? options.dirty.map((d) => inflateRect(d, grow)) : options.dirty;
2563
2171
  for (const { tx, ty } of _chunk474IQG74cjs.tilesInRect.call(void 0, rect)) {
2564
2172
  stats.tiles++;
2565
- const before = _optionalChain([this, 'access', _31 => _31.tiles, 'access', _32 => _32.get, 'call', _33 => _33(_chunk474IQG74cjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _34 => _34.result]);
2173
+ const before = _optionalChain([this, 'access', _2 => _2.tiles, 'access', _3 => _3.get, 'call', _4 => _4(_chunk474IQG74cjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _5 => _5.result]);
2566
2174
  const data = this.compositeTile(layers, steps, tx, ty, stats, dirty ? dirtyInTile(dirty, tx, ty) : null);
2567
2175
  onTile(tx, ty, data, data !== before);
2568
2176
  }
@@ -2603,7 +2211,7 @@ var RasterCompositor = (_class = class {
2603
2211
  return {
2604
2212
  rect,
2605
2213
  maps,
2606
- blend: isGroup2(layer) ? layer.blend === "pass-through" ? "normal" : layer.blend : this.contentBlend(layer),
2214
+ blend: isGroup(layer) ? layer.blend === "pass-through" ? "normal" : layer.blend : this.contentBlend(layer),
2607
2215
  opacity: layer.opacity,
2608
2216
  fillOpacity: this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1,
2609
2217
  canvas: { x: 0, y: 0, width: this.sources.width, height: this.sources.height },
@@ -2613,10 +2221,10 @@ var RasterCompositor = (_class = class {
2613
2221
  // --- Steps -------------------------------------------------------------------
2614
2222
  /** Pixel layers, and the layer kinds the profile composites like them. */
2615
2223
  isPixel(l) {
2616
- return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _35 => _35.profile, 'access', _36 => _36.isPixelLike, 'optionalCall', _37 => _37(l)]), () => ( false)));
2224
+ return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _6 => _6.profile, 'access', _7 => _7.isPixelLike, 'optionalCall', _8 => _8(l)]), () => ( false)));
2617
2225
  }
2618
2226
  isFilter(l) {
2619
- return _nullishCoalesce(_optionalChain([this, 'access', _38 => _38.profile, 'access', _39 => _39.isFilterLayer, 'optionalCall', _40 => _40(l)]), () => ( false));
2227
+ return _nullishCoalesce(_optionalChain([this, 'access', _9 => _9.profile, 'access', _10 => _10.isFilterLayer, 'optionalCall', _11 => _11(l)]), () => ( false));
2620
2228
  }
2621
2229
  /**
2622
2230
  * Groups a layer list into compositing steps: clipped layers join the nearest unclipped
@@ -2635,7 +2243,7 @@ var RasterCompositor = (_class = class {
2635
2243
  if (this.isFilter(layer)) {
2636
2244
  if (last && last.kind === "adjust") last.layers.push(layer);
2637
2245
  else steps.push({ kind: "adjust", layers: [layer] });
2638
- } else if (isGroup2(layer)) {
2246
+ } else if (isGroup(layer)) {
2639
2247
  steps.push({ kind: "group", layer, clipped: [], steps: this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) });
2640
2248
  } else {
2641
2249
  steps.push({ kind: "content", layer, clipped: [] });
@@ -2646,7 +2254,7 @@ var RasterCompositor = (_class = class {
2646
2254
  }
2647
2255
  /** The index of the top-level step that holds layer `id` (searching groups and clipped layers), or -1. */
2648
2256
  stepIndexOf(steps, id) {
2649
- const holds = (l) => l.id === id || isGroup2(l) && (_nullishCoalesce(l.children, () => ( []))).some(holds);
2257
+ const holds = (l) => l.id === id || isGroup(l) && (_nullishCoalesce(l.children, () => ( []))).some(holds);
2650
2258
  return steps.findIndex((s) => s.kind === "adjust" ? s.layers.some(holds) : holds(s.layer) || s.clipped.some(holds));
2651
2259
  }
2652
2260
  /** Properties of a layer that change pixels, minus its surfaces (memoised per object). */
@@ -2655,9 +2263,10 @@ var RasterCompositor = (_class = class {
2655
2263
  if (key !== void 0) return key;
2656
2264
  const mask = layer.mask ? [layer.mask.enabled !== false, _nullishCoalesce(layer.mask.density, () => ( 1)), _nullishCoalesce(layer.mask.feather, () => ( 0)), layer.mask.defaultValue, _nullishCoalesce(layer.mask.source, () => ( null))] : null;
2657
2265
  const base = [layer.type, layer.id, layer.visible, layer.opacity, layer.blend, Boolean(layer.clipped), mask];
2658
- if (this.isPixel(layer)) base.push(_nullishCoalesce(_optionalChain([layer, 'access', _41 => _41.offset, 'optionalAccess', _42 => _42.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _43 => _43.offset, 'optionalAccess', _44 => _44.y]), () => ( 0)), _nullishCoalesce(layer.fillOpacity, () => ( 1)));
2266
+ if (this.isPixel(layer)) base.push(_nullishCoalesce(_optionalChain([layer, 'access', _12 => _12.offset, 'optionalAccess', _13 => _13.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _14 => _14.offset, 'optionalAccess', _15 => _15.y]), () => ( 0)), _nullishCoalesce(layer.fillOpacity, () => ( 1)));
2659
2267
  if (this.hasEffects(layer)) base.push(effectsFingerprint(layer.effects));
2660
- const extra = _optionalChain([this, 'access', _45 => _45.profile, 'access', _46 => _46.layerKey, 'optionalCall', _47 => _47(layer)]);
2268
+ if (layer.edge) base.push(layer.edge);
2269
+ const extra = _optionalChain([this, 'access', _16 => _16.profile, 'access', _17 => _17.layerKey, 'optionalCall', _18 => _18(layer)]);
2661
2270
  if (extra !== void 0) base.push(extra);
2662
2271
  key = JSON.stringify(base);
2663
2272
  this.propsKeyCache.set(layer, key);
@@ -2794,7 +2403,7 @@ var RasterCompositor = (_class = class {
2794
2403
  }
2795
2404
  layerSig(layer, tx, ty) {
2796
2405
  if (this.isFilter(layer)) return { key: this.propsKey(layer), refs: this.maskRefs(layer, tx, ty, 0, 0) };
2797
- if (isGroup2(layer)) return this.groupSig(layer, this.buildSteps(_nullishCoalesce(layer.children, () => ( []))), tx, ty);
2406
+ if (isGroup(layer)) return this.groupSig(layer, this.buildSteps(_nullishCoalesce(layer.children, () => ( []))), tx, ty);
2798
2407
  return this.contentSig(layer, tx, ty);
2799
2408
  }
2800
2409
  groupSig(group, steps, tx, ty) {
@@ -2824,7 +2433,7 @@ var RasterCompositor = (_class = class {
2824
2433
  const refs = [surface.defaultValue];
2825
2434
  const r = { x: tx * _chunk474IQG74cjs.TILE - dx, y: ty * _chunk474IQG74cjs.TILE - dy, width: _chunk474IQG74cjs.TILE, height: _chunk474IQG74cjs.TILE };
2826
2435
  for (const t of _chunk474IQG74cjs.tilesInRect.call(void 0, r)) refs.push(_nullishCoalesce(surface.getTile(t.tx, t.ty), () => ( null)));
2827
- refs.push(...this.maskRefs(layer, tx, ty, _nullishCoalesce(_optionalChain([layer, 'access', _48 => _48.offset, 'optionalAccess', _49 => _49.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _50 => _50.offset, 'optionalAccess', _51 => _51.y]), () => ( 0))));
2436
+ refs.push(...this.maskRefs(layer, tx, ty, _nullishCoalesce(_optionalChain([layer, 'access', _19 => _19.offset, 'optionalAccess', _20 => _20.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _21 => _21.offset, 'optionalAccess', _22 => _22.y]), () => ( 0))));
2828
2437
  return { key, refs };
2829
2438
  }
2830
2439
  // --- Layer effects ------------------------------------------------------------
@@ -2854,7 +2463,7 @@ var RasterCompositor = (_class = class {
2854
2463
  this.fxContext = {
2855
2464
  light: _nullishCoalesce(sources.globalLight, () => ( DEFAULT_GLOBAL_LIGHT)),
2856
2465
  pattern: (id) => {
2857
- const p = _nullishCoalesce(_optionalChain([sources, 'access', _52 => _52.pattern, 'optionalCall', _53 => _53(id)]), () => ( builtinPattern(id)));
2466
+ const p = _nullishCoalesce(_optionalChain([sources, 'access', _23 => _23.pattern, 'optionalCall', _24 => _24(id)]), () => ( builtinPattern(id)));
2858
2467
  if (!p || !(p.width > 0 && p.height > 0) || p.data.length < p.width * p.height * 4) return null;
2859
2468
  let t = tiles.get(p);
2860
2469
  if (!t) {
@@ -2884,7 +2493,7 @@ var RasterCompositor = (_class = class {
2884
2493
  shapeSigs(layer, region) {
2885
2494
  const sigs = /* @__PURE__ */ new Map();
2886
2495
  if (region.width <= 0 || region.height <= 0) return sigs;
2887
- const steps = isGroup2(layer) ? this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) : null;
2496
+ const steps = isGroup(layer) ? this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) : null;
2888
2497
  for (const t of _chunk474IQG74cjs.tilesInRect.call(void 0, region)) {
2889
2498
  sigs.set(_chunk474IQG74cjs.tileKey.call(void 0, t.tx, t.ty), steps ? this.plainGroupSig(layer, steps, t.tx, t.ty) : this.plainContentSig(layer, t.tx, t.ty));
2890
2499
  }
@@ -2906,7 +2515,7 @@ var RasterCompositor = (_class = class {
2906
2515
  * laid out over the layer's bounds.
2907
2516
  */
2908
2517
  effectSig(layer, tx, ty) {
2909
- const key = (isGroup2(layer) ? "Gfx" : "Cfx") + this.propsKey(layer) + this.lightKey();
2518
+ const key = (isGroup(layer) ? "Gfx" : "Cfx") + this.propsKey(layer) + this.lightKey();
2910
2519
  const region = this.effectRegion(layer);
2911
2520
  const m = effectsMargin(layer.effects);
2912
2521
  if (effectsAreLocal(activeEffectItems(layer.effects))) {
@@ -2982,7 +2591,7 @@ var RasterCompositor = (_class = class {
2982
2591
  * without filters or a feathered or parametric mask (those spread a change beyond it).
2983
2592
  */
2984
2593
  dirtyCoversShape(layer) {
2985
- if (!this.isPixel(layer) || _optionalChain([this, 'access', _54 => _54.profile, 'access', _55 => _55.pixelFilters, 'optionalCall', _56 => _56(layer)])) return false;
2594
+ if (!this.isPixel(layer) || _optionalChain([this, 'access', _25 => _25.profile, 'access', _26 => _26.pixelFilters, 'optionalCall', _27 => _27(layer)])) return false;
2986
2595
  const mask = layer.mask;
2987
2596
  return !mask || mask.enabled === false || !mask.source && !((_nullishCoalesce(mask.feather, () => ( 0))) > 0);
2988
2597
  }
@@ -2999,7 +2608,7 @@ var RasterCompositor = (_class = class {
2999
2608
  /** A content or group layer's own pixels over `r` with its mask applied to alpha, or `null` when empty. */
3000
2609
  ownPixels(layer, r) {
3001
2610
  let rgba;
3002
- if (isGroup2(layer)) {
2611
+ if (isGroup(layer)) {
3003
2612
  const buf = new Uint8ClampedArray(r.width * r.height * 4);
3004
2613
  rgba = this.runSteps(this.buildSteps(_nullishCoalesce(layer.children, () => ( []))), buf, true, r) ? null : buf;
3005
2614
  } else {
@@ -3033,7 +2642,7 @@ var RasterCompositor = (_class = class {
3033
2642
  const content = _nullishCoalesce(this.ownPixels(layer, a), () => ( new Uint8ClampedArray(a.width * a.height * 4)));
3034
2643
  if (clipped.length) this.applyClipped(clipped, content, a);
3035
2644
  const keep = keepAlpha ? sub.filter((_, i) => (i & 3) === 3) : null;
3036
- const blend2 = isGroup2(layer) ? layer.blend === "pass-through" ? "normal" : layer.blend : this.contentBlend(layer);
2645
+ const blend2 = isGroup(layer) ? layer.blend === "pass-through" ? "normal" : layer.blend : this.contentBlend(layer);
3037
2646
  compositeLayerEffects({
3038
2647
  backdrop: sub,
3039
2648
  content,
@@ -3070,10 +2679,10 @@ var RasterCompositor = (_class = class {
3070
2679
  */
3071
2680
  layerPixels(layer) {
3072
2681
  const raw = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
3073
- const ox = _nullishCoalesce(_optionalChain([layer, 'access', _57 => _57.offset, 'optionalAccess', _58 => _58.x]), () => ( 0));
3074
- const oy = _nullishCoalesce(_optionalChain([layer, 'access', _59 => _59.offset, 'optionalAccess', _60 => _60.y]), () => ( 0));
3075
- const filters = _nullishCoalesce(_optionalChain([this, 'access', _61 => _61.profile, 'access', _62 => _62.pixelFilters, 'optionalCall', _63 => _63(layer)]), () => ( null));
3076
- if (!_optionalChain([filters, 'optionalAccess', _64 => _64.spatial])) return { surface: raw, dx: ox, dy: oy, perPixel: filters };
2682
+ const ox = _nullishCoalesce(_optionalChain([layer, 'access', _28 => _28.offset, 'optionalAccess', _29 => _29.x]), () => ( 0));
2683
+ const oy = _nullishCoalesce(_optionalChain([layer, 'access', _30 => _30.offset, 'optionalAccess', _31 => _31.y]), () => ( 0));
2684
+ const filters = _nullishCoalesce(_optionalChain([this, 'access', _32 => _32.profile, 'access', _33 => _33.pixelFilters, 'optionalCall', _34 => _34(layer)]), () => ( null));
2685
+ if (!_optionalChain([filters, 'optionalAccess', _35 => _35.spatial])) return { surface: raw, dx: ox, dy: oy, perPixel: filters };
3077
2686
  const fkey = `${ox},${oy}:${filters.key}`;
3078
2687
  let byKey = this.filteredCache.get(raw);
3079
2688
  if (!byKey) {
@@ -3090,7 +2699,7 @@ var RasterCompositor = (_class = class {
3090
2699
  }
3091
2700
  /** RGBA of a content layer over `r` (document space, inside one tile), or `null` when it has nothing there. */
3092
2701
  contentTile(layer, r) {
3093
- if (!this.isPixel(layer)) return _nullishCoalesce(_optionalChain([this, 'access', _65 => _65.profile, 'access', _66 => _66.contentTile, 'optionalCall', _67 => _67(layer, r, this.sources)]), () => ( null));
2702
+ if (!this.isPixel(layer)) return _nullishCoalesce(_optionalChain([this, 'access', _36 => _36.profile, 'access', _37 => _37.contentTile, 'optionalCall', _38 => _38(layer, r, this.sources)]), () => ( null));
3094
2703
  const { surface, dx, dy, perPixel } = this.layerPixels(layer);
3095
2704
  const src = { x: r.x - dx, y: r.y - dy, width: r.width, height: r.height };
3096
2705
  const covered = _chunk474IQG74cjs.tilesInRect.call(void 0, src).map((t) => surface.getTile(t.tx, t.ty));
@@ -3105,7 +2714,7 @@ var RasterCompositor = (_class = class {
3105
2714
  let byKey = this.contentCache.get(anchor);
3106
2715
  const refsKey = `${r.x},${r.y}:${fkey}`;
3107
2716
  if (aligned) {
3108
- const hit = _optionalChain([byKey, 'optionalAccess', _68 => _68.get, 'call', _69 => _69(refsKey)]);
2717
+ const hit = _optionalChain([byKey, 'optionalAccess', _39 => _39.get, 'call', _40 => _40(refsKey)]);
3109
2718
  if (hit) return hit;
3110
2719
  }
3111
2720
  const data = _chunk474IQG74cjs.readRegion.call(void 0, surface, src);
@@ -3119,93 +2728,283 @@ var RasterCompositor = (_class = class {
3119
2728
  }
3120
2729
  return data;
3121
2730
  }
3122
- // --- Masks -------------------------------------------------------------------
3123
- planeKey(mask, ox, oy) {
3124
- const W = this.sources.width;
3125
- const H = this.sources.height;
3126
- let id = this.planeIds.get(mask.surface);
3127
- if (id === void 0) {
3128
- id = this.nextPlaneId++;
3129
- this.planeIds.set(mask.surface, id);
3130
- }
3131
- return `${id}:${ox},${oy}:${W}x${H}:${_nullishCoalesce(mask.feather, () => ( 0))}:${_nullishCoalesce(mask.density, () => ( 1))}:${mask.source ? JSON.stringify(mask.source) : ""}`;
2731
+ // --- Masks -------------------------------------------------------------------
2732
+ planeKey(mask, ox, oy) {
2733
+ const W = this.sources.width;
2734
+ const H = this.sources.height;
2735
+ let id = this.planeIds.get(mask.surface);
2736
+ if (id === void 0) {
2737
+ id = this.nextPlaneId++;
2738
+ this.planeIds.set(mask.surface, id);
2739
+ }
2740
+ return `${id}:${ox},${oy}:${W}x${H}:${_nullishCoalesce(mask.feather, () => ( 0))}:${_nullishCoalesce(mask.density, () => ( 1))}:${mask.source ? JSON.stringify(mask.source) : ""}`;
2741
+ }
2742
+ /** Canvas-sized coverage of a feathered or parametric mask (cached). */
2743
+ planeFor(mask, ox, oy) {
2744
+ const key = this.planeKey(mask, ox, oy);
2745
+ let plane = this.planeCache.get(key);
2746
+ if (plane) {
2747
+ this.planeCache.delete(key);
2748
+ this.planeCache.set(key, plane);
2749
+ return plane;
2750
+ }
2751
+ const W = this.sources.width;
2752
+ const H = this.sources.height;
2753
+ let v = new Float32Array(W * H);
2754
+ if (mask.source) {
2755
+ const generated = _nullishCoalesce(_optionalChain([this, 'access', _41 => _41.profile, 'access', _42 => _42.maskSourcePlane, 'optionalCall', _43 => _43(mask.source, W, H, this.sources)]), () => ( null));
2756
+ if (!generated || generated.length !== W * H) v.fill(1);
2757
+ else v.set(generated);
2758
+ } else {
2759
+ const bytes = _chunk474IQG74cjs.readRegion.call(void 0, mask.surface, { x: -ox, y: -oy, width: W, height: H });
2760
+ for (let i = 0; i < v.length; i++) v[i] = bytes[i] / 255;
2761
+ }
2762
+ const feather = _nullishCoalesce(mask.feather, () => ( 0));
2763
+ if (feather > 0) v = _chunkK6PXS6DOcjs.gaussianBlur.call(void 0, v, W, H, feather, "clamp");
2764
+ const density = _nullishCoalesce(mask.density, () => ( 1));
2765
+ if (density !== 1) for (let i = 0; i < v.length; i++) v[i] = 1 - density * (1 - v[i]);
2766
+ plane = { data: v, width: W, height: H };
2767
+ this.planeCache.set(key, plane);
2768
+ while (this.planeCache.size > 8) this.planeCache.delete(this.planeCache.keys().next().value);
2769
+ return plane;
2770
+ }
2771
+ maskTile(layer, r) {
2772
+ const mask = layer.mask;
2773
+ if (!mask || mask.enabled === false) return null;
2774
+ const ox = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _44 => _44.offset, 'optionalAccess', _45 => _45.x]), () => ( 0)) : 0;
2775
+ const oy = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _46 => _46.offset, 'optionalAccess', _47 => _47.y]), () => ( 0)) : 0;
2776
+ const n = r.width * r.height;
2777
+ const out = new Float32Array(n);
2778
+ const density = _nullishCoalesce(mask.density, () => ( 1));
2779
+ if (mask.source || (_nullishCoalesce(mask.feather, () => ( 0))) > 0) {
2780
+ const plane = this.planeFor(mask, ox, oy);
2781
+ const W = plane.width;
2782
+ const H = plane.height;
2783
+ const outside = mask.source ? 1 : 1 - density * (1 - mask.defaultValue / 255);
2784
+ out.fill(outside);
2785
+ const x0 = Math.max(0, r.x);
2786
+ const y0 = Math.max(0, r.y);
2787
+ const x1 = Math.min(W, r.x + r.width);
2788
+ const y1 = Math.min(H, r.y + r.height);
2789
+ for (let y = y0; y < y1; y++) {
2790
+ const s = y * W;
2791
+ const d = (y - r.y) * r.width - r.x;
2792
+ for (let x = x0; x < x1; x++) out[d + x] = plane.data[s + x];
2793
+ }
2794
+ } else {
2795
+ const rect = { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height };
2796
+ let all = true;
2797
+ if (maskDepth(mask.surface) !== 8) {
2798
+ const d = _chunkOLNIPTB3cjs.readDeepRegion.call(void 0, mask.surface, rect, 32);
2799
+ for (let i = 0; i < n; i++) {
2800
+ const v = d[i] <= 0 ? 0 : d[i] >= 1 ? 1 : d[i];
2801
+ out[i] = v;
2802
+ if (v !== 1) all = false;
2803
+ }
2804
+ } else {
2805
+ const bytes = _chunk474IQG74cjs.readRegion.call(void 0, mask.surface, rect);
2806
+ for (let i = 0; i < n; i++) {
2807
+ out[i] = bytes[i] / 255;
2808
+ if (bytes[i] !== 255) all = false;
2809
+ }
2810
+ }
2811
+ if (all) return null;
2812
+ if (density !== 1) for (let i = 0; i < n; i++) out[i] = 1 - density * (1 - out[i]);
2813
+ }
2814
+ return out;
2815
+ }
2816
+ // --- Running steps ---------------------------------------------------------
2817
+ /** Runs one step onto `acc`; returns whether `acc` is still empty. */
2818
+ runStep(step, acc, empty, r) {
2819
+ if (step.kind === "adjust") {
2820
+ if (empty) return true;
2821
+ this.applyFilterRun(step.layers, acc, r);
2822
+ return false;
2823
+ }
2824
+ const layer = step.layer;
2825
+ if (!layer.visible) return empty;
2826
+ const clipped = step.clipped.filter((l) => l.visible);
2827
+ if (this.hasEffects(layer)) return this.runEffectStep(layer, clipped, acc, empty, r);
2828
+ const coverage = this.maskTile(layer, r);
2829
+ if (coverage && coverage.every((v) => v <= 0)) return empty;
2830
+ if (step.kind === "group") {
2831
+ if (layer.blend === "pass-through" && !clipped.length) {
2832
+ if (layer.opacity >= 1 && !coverage) return this.runSteps(step.steps, acc, empty, r);
2833
+ const before = new Uint8ClampedArray(acc);
2834
+ const stillEmpty = this.runSteps(step.steps, acc, empty, r);
2835
+ lerpTile(acc, before, layer.opacity, coverage);
2836
+ return empty && stillEmpty;
2837
+ }
2838
+ const buf2 = new Uint8ClampedArray(acc.length);
2839
+ if (this.runSteps(step.steps, buf2, true, r)) return empty;
2840
+ this.applyClipped(clipped, buf2, r);
2841
+ const mode = layer.blend === "pass-through" ? "normal" : layer.blend;
2842
+ return this.blendOnto(acc, buf2, empty, mode, layer.opacity, coverage);
2843
+ }
2844
+ let content = this.contentTile(step.layer, r);
2845
+ if (!content) return empty;
2846
+ const ambient = _nullishCoalesce(_optionalChain([layer, 'access', _48 => _48.edge, 'optionalAccess', _49 => _49.ambient]), () => ( 0));
2847
+ if (ambient > 0 && (!empty || _optionalChain([layer, 'access', _50 => _50.edge, 'optionalAccess', _51 => _51.ambientColor]))) {
2848
+ content = new Uint8ClampedArray(content);
2849
+ applyEdgeAmbient(content, acc, coverage, ambient, _nullishCoalesce(_optionalChain([layer, 'access', _52 => _52.edge, 'optionalAccess', _53 => _53.ambientColor]), () => ( null)), 255);
2850
+ }
2851
+ const fill2 = this.isPixel(step.layer) ? _nullishCoalesce(step.layer.fillOpacity, () => ( 1)) : 1;
2852
+ const blend2 = this.contentBlend(step.layer);
2853
+ if (!clipped.length) return this.blendOnto(acc, content, empty, blend2, layer.opacity * fill2, coverage);
2854
+ const buf = new Uint8ClampedArray(acc.length);
2855
+ blendTile(buf, content, "normal", fill2, coverage);
2856
+ this.applyClipped(clipped, buf, r);
2857
+ return this.blendOnto(acc, buf, empty, blend2, layer.opacity, null);
2858
+ }
2859
+ runSteps(steps, acc, empty, r) {
2860
+ for (const s of steps) empty = this.runStep(s, acc, empty, r);
2861
+ return empty;
2862
+ }
2863
+ contentBlend(layer) {
2864
+ return _nullishCoalesce(_optionalChain([this, 'access', _54 => _54.profile, 'access', _55 => _55.contentBlend, 'optionalCall', _56 => _56(layer)]), () => ( layer.blend));
2865
+ }
2866
+ blendOnto(acc, src, empty, mode, alpha, coverage) {
2867
+ if (!(alpha > 0)) return empty;
2868
+ if (empty && mode === "normal" && alpha >= 1 && !coverage) {
2869
+ acc.set(src);
2870
+ return false;
2871
+ }
2872
+ blendTile(acc, src, mode, alpha, coverage);
2873
+ return false;
2874
+ }
2875
+ applyClipped(clipped, buf, r) {
2876
+ let run = [];
2877
+ const flush = () => {
2878
+ if (run.length) this.applyFilterRun(run, buf, r);
2879
+ run = [];
2880
+ };
2881
+ for (const c of clipped) {
2882
+ if (this.isFilter(c)) {
2883
+ run.push(c);
2884
+ continue;
2885
+ }
2886
+ flush();
2887
+ if (this.hasEffects(c) && !isGroup(c)) {
2888
+ this.compositeEffects(c, [], buf, r, true);
2889
+ continue;
2890
+ }
2891
+ const coverage = this.maskTile(c, r);
2892
+ if (isGroup(c)) {
2893
+ const inner = new Uint8ClampedArray(buf.length);
2894
+ if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), inner, true, r)) continue;
2895
+ const mode = c.blend === "pass-through" ? "normal" : c.blend;
2896
+ blendAtop(buf, inner, mode, c.opacity, coverage);
2897
+ continue;
2898
+ }
2899
+ const content = this.contentTile(c, r);
2900
+ if (!content) continue;
2901
+ const fill2 = this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
2902
+ blendAtop(buf, content, this.contentBlend(c), c.opacity * fill2, coverage);
2903
+ }
2904
+ flush();
2905
+ }
2906
+ applyFilterRun(layers, acc, r) {
2907
+ const visible = [];
2908
+ let masks;
2909
+ for (const node of layers) {
2910
+ if (!node.visible) continue;
2911
+ const cov = this.maskTile(node, r);
2912
+ if (cov) {
2913
+ if (cov.every((v) => v <= 0)) continue;
2914
+ (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
2915
+ }
2916
+ visible.push(node);
2917
+ }
2918
+ if (visible.length) _optionalChain([this, 'access', _57 => _57.profile, 'access', _58 => _58.applyFilterRun, 'optionalCall', _59 => _59(visible, acc, r, masks, this.sources)]);
2919
+ }
2920
+ }, _class);
2921
+ function filterOverCanvas(surface, ox, oy, filters, width, height) {
2922
+ if (width <= 0 || height <= 0) return _chunk474IQG74cjs.emptySurface.call(void 0, 4);
2923
+ const data = _chunk474IQG74cjs.readRegion.call(void 0, surface, { x: -ox, y: -oy, width, height });
2924
+ filters.apply(data, width, height);
2925
+ return _chunk474IQG74cjs.surfaceFromPixels.call(void 0, { width, height, data }, 4, 0, 0);
2926
+ }
2927
+ function copyRect(data, r, a) {
2928
+ const out = new Uint8ClampedArray(a.width * a.height * 4);
2929
+ for (let y = 0; y < a.height; y++) {
2930
+ const s = ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4;
2931
+ out.set(data.subarray(s, s + a.width * 4), y * a.width * 4);
2932
+ }
2933
+ return out;
2934
+ }
2935
+ function pasteRect(data, r, part, a) {
2936
+ for (let y = 0; y < a.height; y++) data.set(part.subarray(y * a.width * 4, (y + 1) * a.width * 4), ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4);
2937
+ }
2938
+ function sameRect(a, b) {
2939
+ return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
2940
+ }
2941
+ function inflateRect(r, m) {
2942
+ return { x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m };
2943
+ }
2944
+ function intersectRect(a, b) {
2945
+ const x0 = Math.max(a.x, b.x);
2946
+ const y0 = Math.max(a.y, b.y);
2947
+ const x1 = Math.min(a.x + a.width, b.x + b.width);
2948
+ const y1 = Math.min(a.y + a.height, b.y + b.height);
2949
+ return x1 <= x0 || y1 <= y0 ? { x: x0, y: y0, width: 0, height: 0 } : { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
2950
+ }
2951
+ function changedTiles(a, b) {
2952
+ const out = [];
2953
+ for (const [k, t] of b.tiles) if (a.tiles.get(k) !== t) out.push(k);
2954
+ for (const k of a.tiles.keys()) if (!b.tiles.has(k)) out.push(k);
2955
+ return out;
2956
+ }
2957
+
2958
+ // src/raster/deep-compositor.ts
2959
+ var isGroup2 = (l) => l.type === "group";
2960
+ var DeepCompositor = class {
2961
+ constructor(base, profile, deep, depth) {
2962
+ this.base = base;
2963
+ this.profile = profile;
2964
+ this.deep = deep;
2965
+ this.depth = depth;
2966
+ this.linear = depth === 32;
2967
+ }
2968
+
2969
+
2970
+
2971
+
2972
+
2973
+
2974
+ /** The composite of `layers` over `rect` as float RGBA in the working space (`rect.width × rect.height × 4`). */
2975
+ composite(layers, rect, sources) {
2976
+ this.sources = sources;
2977
+ const acc = new Float32Array(Math.max(0, rect.width * rect.height * 4));
2978
+ if (rect.width > 0 && rect.height > 0) this.runSteps(this.buildSteps(layers), acc, true, rect);
2979
+ return acc;
2980
+ }
2981
+ // --- Steps (as RasterCompositor.buildSteps) ------------------------------------
2982
+ isPixel(l) {
2983
+ return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _60 => _60.profile, 'access', _61 => _61.isPixelLike, 'optionalCall', _62 => _62(l)]), () => ( false)));
3132
2984
  }
3133
- /** Canvas-sized coverage of a feathered or parametric mask (cached). */
3134
- planeFor(mask, ox, oy) {
3135
- const key = this.planeKey(mask, ox, oy);
3136
- let plane = this.planeCache.get(key);
3137
- if (plane) {
3138
- this.planeCache.delete(key);
3139
- this.planeCache.set(key, plane);
3140
- return plane;
3141
- }
3142
- const W = this.sources.width;
3143
- const H = this.sources.height;
3144
- let v = new Float32Array(W * H);
3145
- if (mask.source) {
3146
- const generated = _nullishCoalesce(_optionalChain([this, 'access', _70 => _70.profile, 'access', _71 => _71.maskSourcePlane, 'optionalCall', _72 => _72(mask.source, W, H, this.sources)]), () => ( null));
3147
- if (!generated || generated.length !== W * H) v.fill(1);
3148
- else v.set(generated);
3149
- } else {
3150
- const bytes = _chunk474IQG74cjs.readRegion.call(void 0, mask.surface, { x: -ox, y: -oy, width: W, height: H });
3151
- for (let i = 0; i < v.length; i++) v[i] = bytes[i] / 255;
3152
- }
3153
- const feather = _nullishCoalesce(mask.feather, () => ( 0));
3154
- if (feather > 0) v = _chunkK6PXS6DOcjs.gaussianBlur.call(void 0, v, W, H, feather, "clamp");
3155
- const density = _nullishCoalesce(mask.density, () => ( 1));
3156
- if (density !== 1) for (let i = 0; i < v.length; i++) v[i] = 1 - density * (1 - v[i]);
3157
- plane = { data: v, width: W, height: H };
3158
- this.planeCache.set(key, plane);
3159
- while (this.planeCache.size > 8) this.planeCache.delete(this.planeCache.keys().next().value);
3160
- return plane;
2985
+ isFilter(l) {
2986
+ return _nullishCoalesce(_optionalChain([this, 'access', _63 => _63.profile, 'access', _64 => _64.isFilterLayer, 'optionalCall', _65 => _65(l)]), () => ( false));
3161
2987
  }
3162
- maskTile(layer, r) {
3163
- const mask = layer.mask;
3164
- if (!mask || mask.enabled === false) return null;
3165
- const ox = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _73 => _73.offset, 'optionalAccess', _74 => _74.x]), () => ( 0)) : 0;
3166
- const oy = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _75 => _75.offset, 'optionalAccess', _76 => _76.y]), () => ( 0)) : 0;
3167
- const n = r.width * r.height;
3168
- const out = new Float32Array(n);
3169
- const density = _nullishCoalesce(mask.density, () => ( 1));
3170
- if (mask.source || (_nullishCoalesce(mask.feather, () => ( 0))) > 0) {
3171
- const plane = this.planeFor(mask, ox, oy);
3172
- const W = plane.width;
3173
- const H = plane.height;
3174
- const outside = mask.source ? 1 : 1 - density * (1 - mask.defaultValue / 255);
3175
- out.fill(outside);
3176
- const x0 = Math.max(0, r.x);
3177
- const y0 = Math.max(0, r.y);
3178
- const x1 = Math.min(W, r.x + r.width);
3179
- const y1 = Math.min(H, r.y + r.height);
3180
- for (let y = y0; y < y1; y++) {
3181
- const s = y * W;
3182
- const d = (y - r.y) * r.width - r.x;
3183
- for (let x = x0; x < x1; x++) out[d + x] = plane.data[s + x];
3184
- }
3185
- } else {
3186
- const rect = { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height };
3187
- let all = true;
3188
- if (maskDepth(mask.surface) !== 8) {
3189
- const d = _chunkOLNIPTB3cjs.readDeepRegion.call(void 0, mask.surface, rect, 32);
3190
- for (let i = 0; i < n; i++) {
3191
- const v = d[i] <= 0 ? 0 : d[i] >= 1 ? 1 : d[i];
3192
- out[i] = v;
3193
- if (v !== 1) all = false;
3194
- }
3195
- } else {
3196
- const bytes = _chunk474IQG74cjs.readRegion.call(void 0, mask.surface, rect);
3197
- for (let i = 0; i < n; i++) {
3198
- out[i] = bytes[i] / 255;
3199
- if (bytes[i] !== 255) all = false;
3200
- }
2988
+ buildSteps(layers) {
2989
+ const steps = [];
2990
+ for (const layer of layers) {
2991
+ const last = steps[steps.length - 1];
2992
+ if (layer.clipped && last && (last.kind === "content" || last.kind === "group")) {
2993
+ last.clipped.push(layer);
2994
+ continue;
3201
2995
  }
3202
- if (all) return null;
3203
- if (density !== 1) for (let i = 0; i < n; i++) out[i] = 1 - density * (1 - out[i]);
2996
+ if (this.isFilter(layer)) {
2997
+ if (last && last.kind === "adjust") last.layers.push(layer);
2998
+ else steps.push({ kind: "adjust", layers: [layer] });
2999
+ } else if (isGroup2(layer)) steps.push({ kind: "group", layer, clipped: [], steps: this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) });
3000
+ else steps.push({ kind: "content", layer, clipped: [] });
3204
3001
  }
3205
- return out;
3002
+ return steps;
3003
+ }
3004
+ runSteps(steps, acc, empty, r) {
3005
+ for (const s of steps) empty = this.runStep(s, acc, empty, r);
3006
+ return empty;
3206
3007
  }
3207
- // --- Running steps ---------------------------------------------------------
3208
- /** Runs one step onto `acc`; returns whether `acc` is still empty. */
3209
3008
  runStep(step, acc, empty, r) {
3210
3009
  if (step.kind === "adjust") {
3211
3010
  if (empty) return true;
@@ -3215,131 +3014,368 @@ var RasterCompositor = (_class = class {
3215
3014
  const layer = step.layer;
3216
3015
  if (!layer.visible) return empty;
3217
3016
  const clipped = step.clipped.filter((l) => l.visible);
3218
- if (this.hasEffects(layer)) return this.runEffectStep(layer, clipped, acc, empty, r);
3219
- const coverage = this.maskTile(layer, r);
3017
+ if ((step.kind === "content" || step.kind === "group") && this.deepEffects(layer)) return this.runEffects(layer, clipped, acc, r, step.kind === "group" ? step.steps : null) ? false : empty;
3018
+ const coverage = this.renderedAlone(layer) ? null : this.base.maskCoverage(layer, r, this.sources);
3220
3019
  if (coverage && coverage.every((v) => v <= 0)) return empty;
3221
- if (step.kind === "group") {
3020
+ if (step.kind === "group" && !this.renderedAlone(layer)) {
3222
3021
  if (layer.blend === "pass-through" && !clipped.length) {
3223
3022
  if (layer.opacity >= 1 && !coverage) return this.runSteps(step.steps, acc, empty, r);
3224
- const before = new Uint8ClampedArray(acc);
3023
+ const before = acc.slice();
3225
3024
  const stillEmpty = this.runSteps(step.steps, acc, empty, r);
3226
- lerpTile(acc, before, layer.opacity, coverage);
3025
+ lerp(acc, before, layer.opacity, coverage);
3227
3026
  return empty && stillEmpty;
3228
3027
  }
3229
- const buf2 = new Uint8ClampedArray(acc.length);
3230
- if (this.runSteps(step.steps, buf2, true, r)) return empty;
3231
- this.applyClipped(clipped, buf2, r);
3232
- const mode = layer.blend === "pass-through" ? "normal" : layer.blend;
3233
- return this.blendOnto(acc, buf2, empty, mode, layer.opacity, coverage);
3028
+ const buf2 = new Float32Array(acc.length);
3029
+ if (this.runSteps(step.steps, buf2, true, r)) return empty;
3030
+ this.applyClipped(clipped, buf2, r);
3031
+ const mode2 = layer.blend === "pass-through" ? "normal" : layer.blend;
3032
+ this.blend(acc, buf2, mode2, layer.opacity, coverage);
3033
+ return false;
3034
+ }
3035
+ const content = this.content(layer, r);
3036
+ if (!content) return empty;
3037
+ const ambient = _nullishCoalesce(_optionalChain([layer, 'access', _66 => _66.edge, 'optionalAccess', _67 => _67.ambient]), () => ( 0));
3038
+ if (ambient > 0) {
3039
+ const c = _optionalChain([layer, 'access', _68 => _68.edge, 'optionalAccess', _69 => _69.ambientColor]);
3040
+ const color2 = c ? c.map((v) => this.linear ? _chunkOLNIPTB3cjs.srgbDecode.call(void 0, v / 255) : v / 255) : null;
3041
+ if (color2 || !empty) applyEdgeAmbient(content, acc, coverage, ambient, color2, 1);
3042
+ }
3043
+ const alone = this.renderedAlone(layer);
3044
+ const fill2 = !alone && this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1;
3045
+ const mode = this.blendOf(layer);
3046
+ if (!clipped.length) {
3047
+ this.blend(acc, content, mode, layer.opacity * fill2, coverage);
3048
+ return false;
3049
+ }
3050
+ const buf = new Float32Array(acc.length);
3051
+ this.blend(buf, content, "normal", fill2, coverage);
3052
+ this.applyClipped(clipped, buf, r);
3053
+ this.blend(acc, buf, mode, layer.opacity, null);
3054
+ return false;
3055
+ }
3056
+ /**
3057
+ * A pixel layer with effects onto `acc` over `r`: its deep content (filters, mask, clipped
3058
+ * layers) and the effects composited in float. Effect maps come from the 8-bit shape. At 32
3059
+ * bits the effects composite in sRGB-encoded values (their colours and blends are defined
3060
+ * there) and the result is decoded back. Returns whether anything was drawn.
3061
+ */
3062
+ runEffects(layer, clipped, acc, r, groupSteps = null) {
3063
+ const fx = this.base.effectsInput(layer, r, this.sources);
3064
+ if (!fx) return false;
3065
+ const a = fx.rect;
3066
+ let content;
3067
+ if (groupSteps) {
3068
+ content = new Float32Array(a.width * a.height * 4);
3069
+ this.runSteps(groupSteps, content, true, a);
3070
+ } else content = _nullishCoalesce(this.content(layer, a), () => ( new Float32Array(a.width * a.height * 4)));
3071
+ const coverage = this.base.maskCoverage(layer, a, this.sources);
3072
+ if (coverage) for (let i = 0; i < coverage.length; i++) content[i * 4 + 3] *= coverage[i];
3073
+ if (clipped.length) this.applyClipped(clipped, content, a);
3074
+ const sub = new Float32Array(a.width * a.height * 4);
3075
+ for (let y = 0; y < a.height; y++) {
3076
+ const s = ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4;
3077
+ sub.set(acc.subarray(s, s + a.width * 4), y * a.width * 4);
3078
+ }
3079
+ if (this.linear) {
3080
+ encodeInPlace(sub);
3081
+ encodeInPlace(content);
3082
+ }
3083
+ compositeLayerEffects({ ...fx, backdrop: sub, content });
3084
+ if (this.linear) decodeInPlace(sub);
3085
+ for (let y = 0; y < a.height; y++) acc.set(sub.subarray(y * a.width * 4, (y + 1) * a.width * 4), ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4);
3086
+ return true;
3087
+ }
3088
+ applyClipped(clipped, buf, r) {
3089
+ let run = [];
3090
+ const flush = () => {
3091
+ if (run.length) this.applyFilterRun(run, buf, r);
3092
+ run = [];
3093
+ };
3094
+ for (const c of clipped) {
3095
+ if (this.isFilter(c)) {
3096
+ run.push(c);
3097
+ continue;
3098
+ }
3099
+ flush();
3100
+ const alone = this.renderedAlone(c);
3101
+ const coverage = alone ? null : this.base.maskCoverage(c, r, this.sources);
3102
+ let src;
3103
+ if (isGroup2(c) && !alone) {
3104
+ src = new Float32Array(buf.length);
3105
+ if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), src, true, r)) continue;
3106
+ } else src = this.content(c, r);
3107
+ if (!src) continue;
3108
+ const fill2 = !alone && this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
3109
+ const keep = new Float32Array(buf.length >> 2);
3110
+ for (let i = 3, p = 0; i < buf.length; i += 4, p++) keep[p] = buf[i];
3111
+ this.blend(buf, src, c.blend === "pass-through" ? "normal" : this.blendOf(c), c.opacity * fill2, coverage);
3112
+ for (let i = 3, p = 0; i < buf.length; i += 4, p++) buf[i] = keep[p];
3113
+ }
3114
+ flush();
3115
+ }
3116
+ applyFilterRun(layers, acc, r) {
3117
+ const visible = [];
3118
+ let masks;
3119
+ for (const node of layers) {
3120
+ if (!node.visible) continue;
3121
+ const cov = this.base.maskCoverage(node, r, this.sources);
3122
+ if (cov) {
3123
+ if (cov.every((v) => v <= 0)) continue;
3124
+ (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
3125
+ }
3126
+ visible.push(node);
3127
+ }
3128
+ if (!visible.length) return;
3129
+ if (this.deep.applyFilterRunDeep) {
3130
+ if (this.linear) mapColour(acc, _chunkOLNIPTB3cjs.srgbEncode);
3131
+ this.deep.applyFilterRunDeep(visible, acc, r, masks, this.sources);
3132
+ if (this.linear) mapColour(acc, _chunkOLNIPTB3cjs.srgbDecode);
3133
+ return;
3134
+ }
3135
+ const bytes = this.to8(acc);
3136
+ _optionalChain([this, 'access', _70 => _70.profile, 'access', _71 => _71.applyFilterRun, 'optionalCall', _72 => _72(visible, bytes, r, masks, this.sources)]);
3137
+ acc.set(this.from8(bytes));
3138
+ }
3139
+ // --- Layer content ---------------------------------------------------------------
3140
+ /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
3141
+ /** A pixel(-like) layer or a group with effects: composited in float through `compositeLayerEffects`. */
3142
+ deepEffects(layer) {
3143
+ return hasActiveEffects(layer.effects) && !this.isFilter(layer) && (isGroup2(layer) || this.isPixel(layer));
3144
+ }
3145
+ renderedAlone(layer) {
3146
+ if (hasActiveEffects(layer.effects) && !this.isFilter(layer) && !this.deepEffects(layer)) return true;
3147
+ if (this.isPixel(layer)) return Boolean(_optionalChain([this, 'access', _73 => _73.profile, 'access', _74 => _74.pixelFilters, 'optionalCall', _75 => _75(layer)])) && !_optionalChain([this, 'access', _76 => _76.deep, 'access', _77 => _77.pixelFiltersDeep, 'optionalCall', _78 => _78(layer)]);
3148
+ return !isGroup2(layer);
3149
+ }
3150
+ blendOf(layer) {
3151
+ return _nullishCoalesce(_optionalChain([this, 'access', _79 => _79.profile, 'access', _80 => _80.contentBlend, 'optionalCall', _81 => _81(layer)]), () => ( layer.blend));
3152
+ }
3153
+ /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
3154
+ content(layer, r) {
3155
+ if (this.renderedAlone(layer)) {
3156
+ const edge = _optionalChain([layer, 'access', _82 => _82.edge, 'optionalAccess', _83 => _83.ambient]) ? { ...layer.edge, ambient: 0 } : layer.edge;
3157
+ const solo = { ...layer, blend: isGroup2(layer) && layer.blend === "pass-through" ? "pass-through" : "normal", opacity: 1, clipped: false, edge };
3158
+ const bytes = this.base.composite([solo], r, this.sources);
3159
+ return this.from8(bytes);
3160
+ }
3161
+ const surface = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
3162
+ if (!surface) return null;
3163
+ const ox = _nullishCoalesce(_optionalChain([layer, 'access', _84 => _84.offset, 'optionalAccess', _85 => _85.x]), () => ( 0));
3164
+ const oy = _nullishCoalesce(_optionalChain([layer, 'access', _86 => _86.offset, 'optionalAccess', _87 => _87.y]), () => ( 0));
3165
+ const filters = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([this, 'access', _88 => _88.deep, 'access', _89 => _89.pixelFiltersDeep, 'optionalCall', _90 => _90(layer)]), () => ( null)) : null;
3166
+ if (!filters) return this.samples(surface, { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height });
3167
+ const m = filters.reach;
3168
+ const W = this.sources.width;
3169
+ const H = this.sources.height;
3170
+ const x0 = m ? Math.max(0, r.x - m) : r.x;
3171
+ const y0 = m ? Math.max(0, r.y - m) : r.y;
3172
+ const x1 = m ? Math.min(W, r.x + r.width + m) : r.x + r.width;
3173
+ const y1 = m ? Math.min(H, r.y + r.height + m) : r.y + r.height;
3174
+ if (x1 <= x0 || y1 <= y0) return new Float32Array(r.width * r.height * 4);
3175
+ const big = { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
3176
+ const data = this.samples(surface, { ...big, x: big.x - ox, y: big.y - oy });
3177
+ filters.apply(data, big.width, big.height, this.linear);
3178
+ if (big.x === r.x && big.y === r.y && big.width === r.width && big.height === r.height) return data;
3179
+ const out = new Float32Array(r.width * r.height * 4);
3180
+ for (let y = 0; y < r.height; y++) {
3181
+ const sy = r.y + y - big.y;
3182
+ if (sy < 0 || sy >= big.height) continue;
3183
+ for (let x = 0; x < r.width; x++) {
3184
+ const sx = r.x + x - big.x;
3185
+ if (sx < 0 || sx >= big.width) continue;
3186
+ const s = (sy * big.width + sx) * 4;
3187
+ const d = (y * r.width + x) * 4;
3188
+ out[d] = data[s];
3189
+ out[d + 1] = data[s + 1];
3190
+ out[d + 2] = data[s + 2];
3191
+ out[d + 3] = data[s + 3];
3192
+ }
3234
3193
  }
3235
- const content = this.contentTile(step.layer, r);
3236
- if (!content) return empty;
3237
- const fill2 = this.isPixel(step.layer) ? _nullishCoalesce(step.layer.fillOpacity, () => ( 1)) : 1;
3238
- const blend2 = this.contentBlend(step.layer);
3239
- if (!clipped.length) return this.blendOnto(acc, content, empty, blend2, layer.opacity * fill2, coverage);
3240
- const buf = new Uint8ClampedArray(acc.length);
3241
- blendTile(buf, content, "normal", fill2, coverage);
3242
- this.applyClipped(clipped, buf, r);
3243
- return this.blendOnto(acc, buf, empty, blend2, layer.opacity, null);
3194
+ return out;
3244
3195
  }
3245
- runSteps(steps, acc, empty, r) {
3246
- for (const s of steps) empty = this.runStep(s, acc, empty, r);
3247
- return empty;
3196
+ /** A surface's samples over `rect` (layer space) in the working space. */
3197
+ samples(surface, rect) {
3198
+ const samples = _chunkOLNIPTB3cjs.readDeepRegion.call(void 0, surface, rect, this.depth);
3199
+ if (samples instanceof Float32Array) return samples;
3200
+ const out = new Float32Array(samples.length);
3201
+ for (let i = 0; i < samples.length; i++) out[i] = samples[i] / 65535;
3202
+ return out;
3248
3203
  }
3249
- contentBlend(layer) {
3250
- return _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.profile, 'access', _78 => _78.contentBlend, 'optionalCall', _79 => _79(layer)]), () => ( layer.blend));
3204
+ /** 8-bit RGBA to the working space. */
3205
+ from8(bytes) {
3206
+ if (this.linear) return _chunkOLNIPTB3cjs.to32From8.call(void 0, bytes, 4);
3207
+ const out = new Float32Array(bytes.length);
3208
+ for (let i = 0; i < bytes.length; i++) out[i] = bytes[i] / 255;
3209
+ return out;
3251
3210
  }
3252
- blendOnto(acc, src, empty, mode, alpha, coverage) {
3253
- if (!(alpha > 0)) return empty;
3254
- if (empty && mode === "normal" && alpha >= 1 && !coverage) {
3255
- acc.set(src);
3256
- return false;
3211
+ /** The working space to 8-bit RGBA. */
3212
+ to8(acc) {
3213
+ const out = new Uint8ClampedArray(acc.length);
3214
+ for (let i = 0; i < acc.length; i += 4) {
3215
+ for (let c = 0; c < 3; c++) out[i + c] = Math.round((this.linear ? _chunkOLNIPTB3cjs.srgbEncode.call(void 0, acc[i + c]) : acc[i + c]) * 255);
3216
+ out[i + 3] = Math.round(acc[i + 3] * 255);
3257
3217
  }
3258
- blendTile(acc, src, mode, alpha, coverage);
3259
- return false;
3218
+ return out;
3260
3219
  }
3261
- applyClipped(clipped, buf, r) {
3262
- let run = [];
3263
- const flush = () => {
3264
- if (run.length) this.applyFilterRun(run, buf, r);
3265
- run = [];
3266
- };
3267
- for (const c of clipped) {
3268
- if (this.isFilter(c)) {
3269
- run.push(c);
3220
+ // --- Blending --------------------------------------------------------------------
3221
+ /** `src` over `dst` with `mode` at `alpha` × coverage (straight alpha, float), as `blendTile`. */
3222
+ blend(dst, src, mode, alpha, coverage) {
3223
+ if (!(alpha > 0)) return;
3224
+ const normal = mode === "normal";
3225
+ const pigment = mode === "pigment";
3226
+ const cb = [0, 0, 0];
3227
+ const cs = [0, 0, 0];
3228
+ const mix = [0, 0, 0];
3229
+ for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
3230
+ const sa = src[i + 3];
3231
+ if (!(sa > 0)) continue;
3232
+ const k = coverage ? alpha * coverage[p] : alpha;
3233
+ if (!(k > 0)) continue;
3234
+ const as = Math.min(1, sa * k);
3235
+ const ab = dst[i + 3];
3236
+ const ao = as + ab * (1 - as);
3237
+ if (ao <= 0) {
3238
+ dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
3270
3239
  continue;
3271
3240
  }
3272
- flush();
3273
- if (this.hasEffects(c) && !isGroup2(c)) {
3274
- this.compositeEffects(c, [], buf, r, true);
3241
+ if (normal && as >= 1) {
3242
+ dst[i] = src[i];
3243
+ dst[i + 1] = src[i + 1];
3244
+ dst[i + 2] = src[i + 2];
3245
+ dst[i + 3] = 1;
3275
3246
  continue;
3276
3247
  }
3277
- const coverage = this.maskTile(c, r);
3278
- if (isGroup2(c)) {
3279
- const inner = new Uint8ClampedArray(buf.length);
3280
- if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), inner, true, r)) continue;
3281
- const mode = c.blend === "pass-through" ? "normal" : c.blend;
3282
- blendAtop(buf, inner, mode, c.opacity, coverage);
3248
+ for (let c = 0; c < 3; c++) {
3249
+ cb[c] = dst[i + c];
3250
+ cs[c] = src[i + c];
3251
+ }
3252
+ if (pigment) {
3253
+ if (this.linear) for (let c = 0; c < 3; c++) cb[c] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, cb[c]), cs[c] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, cs[c]);
3254
+ _chunkOLNIPTB3cjs.mixPigmentRgb.call(void 0, cb, cs, as / ao, mix);
3255
+ for (let c = 0; c < 3; c++) dst[i + c] = this.linear ? _chunkOLNIPTB3cjs.srgbDecode.call(void 0, mix[c]) : mix[c];
3256
+ dst[i + 3] = ao;
3283
3257
  continue;
3284
3258
  }
3285
- const content = this.contentTile(c, r);
3286
- if (!content) continue;
3287
- const fill2 = this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
3288
- blendAtop(buf, content, this.contentBlend(c), c.opacity * fill2, coverage);
3259
+ const m = normal ? cs : _chunkOLNIPTB3cjs.blendRgb.call(void 0, mode, cb, cs);
3260
+ const wb = (1 - as) * ab;
3261
+ const ws = (1 - ab) * as;
3262
+ const wm = as * ab;
3263
+ for (let c = 0; c < 3; c++) dst[i + c] = (wb * cb[c] + ws * cs[c] + wm * m[c]) / ao;
3264
+ dst[i + 3] = ao;
3289
3265
  }
3290
- flush();
3291
3266
  }
3292
- applyFilterRun(layers, acc, r) {
3293
- const visible = [];
3294
- let masks;
3295
- for (const node of layers) {
3296
- if (!node.visible) continue;
3297
- const cov = this.maskTile(node, r);
3298
- if (cov) {
3299
- if (cov.every((v) => v <= 0)) continue;
3300
- (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
3301
- }
3302
- visible.push(node);
3303
- }
3304
- if (visible.length) _optionalChain([this, 'access', _80 => _80.profile, 'access', _81 => _81.applyFilterRun, 'optionalCall', _82 => _82(visible, acc, r, masks, this.sources)]);
3267
+ };
3268
+ function lerp(dst, before, alpha, coverage) {
3269
+ for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
3270
+ const k = coverage ? alpha * coverage[p] : alpha;
3271
+ if (k >= 1) continue;
3272
+ for (let c = 0; c < 4; c++) dst[i + c] = before[i + c] + (dst[i + c] - before[i + c]) * k;
3305
3273
  }
3306
- }, _class);
3307
- function filterOverCanvas(surface, ox, oy, filters, width, height) {
3308
- if (width <= 0 || height <= 0) return _chunk474IQG74cjs.emptySurface.call(void 0, 4);
3309
- const data = _chunk474IQG74cjs.readRegion.call(void 0, surface, { x: -ox, y: -oy, width, height });
3310
- filters.apply(data, width, height);
3311
- return _chunk474IQG74cjs.surfaceFromPixels.call(void 0, { width, height, data }, 4, 0, 0);
3312
3274
  }
3313
- function copyRect(data, r, a) {
3314
- const out = new Uint8ClampedArray(a.width * a.height * 4);
3315
- for (let y = 0; y < a.height; y++) {
3316
- const s = ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4;
3317
- out.set(data.subarray(s, s + a.width * 4), y * a.width * 4);
3275
+ function mapColour(data, f) {
3276
+ for (let i = 0; i < data.length; i += 4) {
3277
+ data[i] = f(data[i]);
3278
+ data[i + 1] = f(data[i + 1]);
3279
+ data[i + 2] = f(data[i + 2]);
3318
3280
  }
3319
- return out;
3320
- }
3321
- function pasteRect(data, r, part, a) {
3322
- for (let y = 0; y < a.height; y++) data.set(part.subarray(y * a.width * 4, (y + 1) * a.width * 4), ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4);
3323
3281
  }
3324
- function sameRect(a, b) {
3325
- return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
3282
+ function workingToSamples(data, depth) {
3283
+ if (depth === 32) return data;
3284
+ const out = new Uint16Array(data.length);
3285
+ for (let i = 0; i < data.length; i++) {
3286
+ const v = data[i];
3287
+ out[i] = v > 0 ? v < 1 ? Math.round(v * 65535) : 65535 : 0;
3288
+ }
3289
+ return out;
3326
3290
  }
3327
- function inflateRect(r, m) {
3328
- return { x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m };
3291
+ function encodeInPlace(d) {
3292
+ for (let i = 0; i < d.length; i += 4) {
3293
+ d[i] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i]);
3294
+ d[i + 1] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i + 1]);
3295
+ d[i + 2] = _chunkOLNIPTB3cjs.srgbEncode.call(void 0, d[i + 2]);
3296
+ }
3329
3297
  }
3330
- function intersectRect(a, b) {
3331
- const x0 = Math.max(a.x, b.x);
3332
- const y0 = Math.max(a.y, b.y);
3333
- const x1 = Math.min(a.x + a.width, b.x + b.width);
3334
- const y1 = Math.min(a.y + a.height, b.y + b.height);
3335
- return x1 <= x0 || y1 <= y0 ? { x: x0, y: y0, width: 0, height: 0 } : { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
3298
+ function decodeInPlace(d) {
3299
+ for (let i = 0; i < d.length; i += 4) {
3300
+ d[i] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i]);
3301
+ d[i + 1] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i + 1]);
3302
+ d[i + 2] = _chunkOLNIPTB3cjs.srgbDecode.call(void 0, d[i + 2]);
3303
+ }
3336
3304
  }
3337
- function changedTiles(a, b) {
3305
+
3306
+ // src/raster/layers.ts
3307
+ var childrenOf = (l) => l.type === "group" ? _nullishCoalesce(l.children, () => ( null)) : null;
3308
+ function flattenLayers(layers) {
3338
3309
  const out = [];
3339
- for (const [k, t] of b.tiles) if (a.tiles.get(k) !== t) out.push(k);
3340
- for (const k of a.tiles.keys()) if (!b.tiles.has(k)) out.push(k);
3310
+ const walk = (list) => {
3311
+ for (const l of list) {
3312
+ out.push(l);
3313
+ const c = childrenOf(l);
3314
+ if (c) walk(c);
3315
+ }
3316
+ };
3317
+ walk(layers);
3341
3318
  return out;
3342
3319
  }
3320
+ function findLayer(layers, id) {
3321
+ const walk = (list, parent, path) => {
3322
+ for (let i = 0; i < list.length; i++) {
3323
+ const l = list[i];
3324
+ if (l.id === id) return { layer: l, parent, index: i, path };
3325
+ const c = childrenOf(l);
3326
+ if (c) {
3327
+ const g = l;
3328
+ const hit = walk(c, g, [...path, g]);
3329
+ if (hit) return hit;
3330
+ }
3331
+ }
3332
+ return null;
3333
+ };
3334
+ return walk(layers, null, []);
3335
+ }
3336
+ function mapLayer(layers, id, fn) {
3337
+ let changed = false;
3338
+ const walk = (list) => {
3339
+ let out = null;
3340
+ for (let i = 0; i < list.length; i++) {
3341
+ const l = list[i];
3342
+ let next = l;
3343
+ if (l.id === id) {
3344
+ next = fn(l);
3345
+ changed = true;
3346
+ } else {
3347
+ const c = childrenOf(l);
3348
+ if (c) {
3349
+ const children = walk(c);
3350
+ if (children !== c) next = { ...l, children };
3351
+ }
3352
+ }
3353
+ if (next !== l) {
3354
+ if (!out) out = list.slice(0, i);
3355
+ if (next) out.push(next);
3356
+ } else if (out) out.push(l);
3357
+ }
3358
+ return _nullishCoalesce(out, () => ( list));
3359
+ };
3360
+ const result = walk(layers);
3361
+ return changed ? result : layers;
3362
+ }
3363
+ function insertLayer(layers, layer, parentId, index) {
3364
+ const put = (list) => {
3365
+ const at = index === void 0 ? list.length : Math.max(0, Math.min(list.length, index));
3366
+ const next = list.slice();
3367
+ next.splice(at, 0, layer);
3368
+ return next;
3369
+ };
3370
+ if (!parentId) return put(layers);
3371
+ return mapLayer(layers, parentId, (g) => {
3372
+ const c = childrenOf(g);
3373
+ return c ? { ...g, children: put(c) } : g;
3374
+ });
3375
+ }
3376
+ function isLayerLocked(layer, what) {
3377
+ return Boolean(_optionalChain([layer, 'access', _91 => _91.locks, 'optionalAccess', _92 => _92.all]) || _optionalChain([layer, 'access', _93 => _93.locks, 'optionalAccess', _94 => _94[what]]));
3378
+ }
3343
3379
 
3344
3380
  // src/raster/transform.ts
3345
3381
  var INTERPOLATIONS = ["nearest", "bilinear", "bicubic"];
@@ -4218,4 +4254,5 @@ function compositeSurfaceOver(base, top) {
4218
4254
 
4219
4255
 
4220
4256
 
4221
- exports.DEFAULT_GLOBAL_LIGHT = DEFAULT_GLOBAL_LIGHT; exports.LAYER_EFFECT_KINDS = LAYER_EFFECT_KINDS; exports.layerEffectLabel = layerEffectLabel; exports.isLayerEffectKind = isLayerEffectKind; exports.defaultEffectGradient = defaultEffectGradient; exports.newEffectId = newEffectId; exports.defaultLayerEffect = defaultLayerEffect; exports.hasActiveEffects = hasActiveEffects; exports.MAX_EFFECT_REACH = MAX_EFFECT_REACH; exports.effectReach = effectReach; exports.effectsMargin = effectsMargin; exports.effectsScale = effectsScale; exports.scaleLayerEffect = scaleLayerEffect; exports.parseEffectColor = parseEffectColor; exports.effectColorHex = effectColorHex; exports.LayerEffectError = LayerEffectError; exports.validateEffectGradient = validateEffectGradient; exports.layerEffectFields = layerEffectFields; exports.validateLayerEffect = validateLayerEffect; exports.mergeLayerEffect = mergeLayerEffect; exports.validateLayerEffects = validateLayerEffects; exports.normalizeLayerEffects = normalizeLayerEffects; exports.effectsFingerprint = effectsFingerprint; exports.CURVE_LUT_SIZE = CURVE_LUT_SIZE; exports.curveLut = curveLut; exports.PatternTile = PatternTile; exports.PatternPlacement = PatternPlacement; exports.builtinPatternIds = builtinPatternIds; exports.builtinPattern = builtinPattern; exports.hashNoise = hashNoise; exports.STROKE_CHAMFER_MAX = STROKE_CHAMFER_MAX; exports.contourLut = contourLut; exports.activeEffectItems = activeEffectItems; exports.effectsAreLocal = effectsAreLocal; exports.buildEffectMaps = buildEffectMaps; exports.patchEffectMaps = patchEffectMaps; exports.gradientT = gradientT; exports.effectFillColors = effectFillColors; exports.compositeLayerEffects = compositeLayerEffects; exports.renderLayerEffects = renderLayerEffects; exports.DeepCompositor = DeepCompositor; exports.workingToSamples = workingToSamples; exports.flattenLayers = flattenLayers; exports.findLayer = findLayer; exports.mapLayer = mapLayer; exports.insertLayer = insertLayer; exports.isLayerLocked = isLayerLocked; exports.blendTile = blendTile; exports.RasterCompositor = RasterCompositor; exports.changedTiles = changedTiles; exports.INTERPOLATIONS = INTERPOLATIONS; exports.isInterpolation = isInterpolation; exports.MAX_TRANSFORM_PIXELS = MAX_TRANSFORM_PIXELS; exports.TransformTooLargeError = TransformTooLargeError; exports.keysWeight = keysWeight; exports.reduceSurface = reduceSurface; exports.transformedBounds = transformedBounds; exports.transformSurface = transformSurface; exports.warpSurface = warpSurface; exports.compositeSurfaceOver = compositeSurfaceOver;
4257
+
4258
+ exports.DEFAULT_GLOBAL_LIGHT = DEFAULT_GLOBAL_LIGHT; exports.LAYER_EFFECT_KINDS = LAYER_EFFECT_KINDS; exports.layerEffectLabel = layerEffectLabel; exports.isLayerEffectKind = isLayerEffectKind; exports.defaultEffectGradient = defaultEffectGradient; exports.newEffectId = newEffectId; exports.defaultLayerEffect = defaultLayerEffect; exports.hasActiveEffects = hasActiveEffects; exports.MAX_EFFECT_REACH = MAX_EFFECT_REACH; exports.effectReach = effectReach; exports.effectsMargin = effectsMargin; exports.effectsScale = effectsScale; exports.scaleLayerEffect = scaleLayerEffect; exports.parseEffectColor = parseEffectColor; exports.effectColorHex = effectColorHex; exports.LayerEffectError = LayerEffectError; exports.validateEffectGradient = validateEffectGradient; exports.layerEffectFields = layerEffectFields; exports.validateLayerEffect = validateLayerEffect; exports.mergeLayerEffect = mergeLayerEffect; exports.validateLayerEffects = validateLayerEffects; exports.normalizeLayerEffects = normalizeLayerEffects; exports.effectsFingerprint = effectsFingerprint; exports.PatternTile = PatternTile; exports.PatternPlacement = PatternPlacement; exports.builtinPatternIds = builtinPatternIds; exports.builtinPattern = builtinPattern; exports.hashNoise = hashNoise; exports.CURVE_LUT_SIZE = CURVE_LUT_SIZE; exports.curveLut = curveLut; exports.STROKE_CHAMFER_MAX = STROKE_CHAMFER_MAX; exports.contourLut = contourLut; exports.activeEffectItems = activeEffectItems; exports.effectsAreLocal = effectsAreLocal; exports.buildEffectMaps = buildEffectMaps; exports.patchEffectMaps = patchEffectMaps; exports.gradientT = gradientT; exports.effectFillColors = effectFillColors; exports.compositeLayerEffects = compositeLayerEffects; exports.renderLayerEffects = renderLayerEffects; exports.applyEdgeAmbient = applyEdgeAmbient; exports.blendTile = blendTile; exports.RasterCompositor = RasterCompositor; exports.changedTiles = changedTiles; exports.DeepCompositor = DeepCompositor; exports.workingToSamples = workingToSamples; exports.flattenLayers = flattenLayers; exports.findLayer = findLayer; exports.mapLayer = mapLayer; exports.insertLayer = insertLayer; exports.isLayerLocked = isLayerLocked; exports.INTERPOLATIONS = INTERPOLATIONS; exports.isInterpolation = isInterpolation; exports.MAX_TRANSFORM_PIXELS = MAX_TRANSFORM_PIXELS; exports.TransformTooLargeError = TransformTooLargeError; exports.keysWeight = keysWeight; exports.reduceSurface = reduceSurface; exports.transformedBounds = transformedBounds; exports.transformSurface = transformSurface; exports.warpSurface = warpSurface; exports.compositeSurfaceOver = compositeSurfaceOver;