@pixerate/editor 0.121.0 → 0.122.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 (36) hide show
  1. package/THIRD_PARTY_NOTICES.md +1 -1
  2. package/dist/{chunk-GLOOH65Y.cjs → chunk-4PUPGALM.cjs} +196 -103
  3. package/dist/chunk-4PUPGALM.cjs.map +1 -0
  4. package/dist/{chunk-4I54JSJ6.js → chunk-CLTTLLWA.js} +1089 -981
  5. package/dist/chunk-CLTTLLWA.js.map +1 -0
  6. package/dist/{chunk-LL3RAN55.cjs → chunk-DFFBJV3U.cjs} +1839 -1731
  7. package/dist/chunk-DFFBJV3U.cjs.map +1 -0
  8. package/dist/{chunk-E6N5KLMA.js → chunk-IX3YKUVK.js} +96 -3
  9. package/dist/chunk-IX3YKUVK.js.map +1 -0
  10. package/dist/{render-B05K68_h.d.ts → deep-DLwKZDFr.d.ts} +143 -134
  11. package/dist/{render-DnAbIKcs.d.cts → deep-QS3ppbMX.d.cts} +143 -134
  12. package/dist/{export-D2D8hb_u.d.ts → export-VmTofKIk.d.ts} +11 -4
  13. package/dist/{export-fP2hZYjm.d.cts → export-jKKj8Fg8.d.cts} +11 -4
  14. package/dist/image-editor/index.cjs +678 -672
  15. package/dist/image-editor/index.cjs.map +1 -1
  16. package/dist/image-editor/index.d.cts +17 -5
  17. package/dist/image-editor/index.d.ts +17 -5
  18. package/dist/image-editor/index.js +8 -2
  19. package/dist/image-editor/index.js.map +1 -1
  20. package/dist/paint-editor/index.cjs +68 -68
  21. package/dist/paint-editor/index.d.cts +2 -2
  22. package/dist/paint-editor/index.d.ts +2 -2
  23. package/dist/paint-editor/index.js +2 -2
  24. package/dist/raster/index.cjs +2 -2
  25. package/dist/raster/index.d.cts +29 -7
  26. package/dist/raster/index.d.ts +29 -7
  27. package/dist/raster/index.js +1 -1
  28. package/package.json +1 -1
  29. package/skills/pixerate-canvas/SKILL.md +23 -1
  30. package/skills/pixerate-image-editor/SKILL.md +7 -1
  31. package/skills/pixerate-image-editor/references/photoshop-files.md +4 -3
  32. package/skills/pixerate-paint-editor/SKILL.md +32 -7
  33. package/dist/chunk-4I54JSJ6.js.map +0 -1
  34. package/dist/chunk-E6N5KLMA.js.map +0 -1
  35. package/dist/chunk-GLOOH65Y.cjs.map +0 -1
  36. package/dist/chunk-LL3RAN55.cjs.map +0 -1
@@ -464,1884 +464,1972 @@ function stableStringify(v) {
464
464
  return JSON.stringify(v);
465
465
  }
466
466
 
467
- // src/raster/deep-compositor.ts
468
- var isGroup = (l) => l.type === "group";
469
- var DeepCompositor = class {
470
- constructor(base, profile, deep, depth) {
471
- this.base = base;
472
- this.profile = profile;
473
- this.deep = deep;
474
- this.depth = depth;
475
- this.linear = depth === 32;
476
- }
477
-
478
-
479
-
480
-
481
-
482
-
483
- /** The composite of `layers` over `rect` as float RGBA in the working space (`rect.width × rect.height × 4`). */
484
- composite(layers, rect, sources) {
485
- this.sources = sources;
486
- const acc = new Float32Array(Math.max(0, rect.width * rect.height * 4));
487
- if (rect.width > 0 && rect.height > 0) this.runSteps(this.buildSteps(layers), acc, true, rect);
488
- return acc;
489
- }
490
- // --- Steps (as RasterCompositor.buildSteps) ------------------------------------
491
- isPixel(l) {
492
- return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _2 => _2.profile, 'access', _3 => _3.isPixelLike, 'optionalCall', _4 => _4(l)]), () => ( false)));
467
+ // src/raster/curve.ts
468
+ var CURVE_LUT_SIZE = 4096;
469
+ var clamp01 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
470
+ function curveLut(points, size = CURVE_LUT_SIZE) {
471
+ 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]);
472
+ const dedup = [];
473
+ for (const p of pts) {
474
+ if (dedup.length && Math.abs(dedup[dedup.length - 1][0] - p[0]) < 1e-6) continue;
475
+ dedup.push(p);
493
476
  }
494
- isFilter(l) {
495
- return _nullishCoalesce(_optionalChain([this, 'access', _5 => _5.profile, 'access', _6 => _6.isFilterLayer, 'optionalCall', _7 => _7(l)]), () => ( false));
477
+ const out = new Float32Array(size);
478
+ const n = dedup.length;
479
+ if (n < 2) {
480
+ for (let k = 0; k < size; k++) out[k] = k / (size - 1);
481
+ return out;
496
482
  }
497
- buildSteps(layers) {
498
- const steps = [];
499
- for (const layer of layers) {
500
- const last = steps[steps.length - 1];
501
- if (layer.clipped && last && (last.kind === "content" || last.kind === "group")) {
502
- last.clipped.push(layer);
503
- continue;
504
- }
505
- if (this.isFilter(layer)) {
506
- if (last && last.kind === "adjust") last.layers.push(layer);
507
- else steps.push({ kind: "adjust", layers: [layer] });
508
- } else if (isGroup(layer)) steps.push({ kind: "group", layer, clipped: [], steps: this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) });
509
- else steps.push({ kind: "content", layer, clipped: [] });
483
+ const x = dedup.map((p) => p[0]);
484
+ const y = dedup.map((p) => p[1]);
485
+ const m2 = new Float64Array(n);
486
+ if (n > 2) {
487
+ const c = new Float64Array(n);
488
+ const d = new Float64Array(n);
489
+ for (let i = 1; i < n - 1; i++) {
490
+ const h0 = x[i] - x[i - 1];
491
+ const h1 = x[i + 1] - x[i];
492
+ const a = h0 / 6;
493
+ const b = (h0 + h1) / 3;
494
+ const cc = h1 / 6;
495
+ const r = (y[i + 1] - y[i]) / h1 - (y[i] - y[i - 1]) / h0;
496
+ const denom = b - a * c[i - 1];
497
+ c[i] = cc / denom;
498
+ d[i] = (r - a * d[i - 1]) / denom;
510
499
  }
511
- return steps;
512
- }
513
- runSteps(steps, acc, empty, r) {
514
- for (const s of steps) empty = this.runStep(s, acc, empty, r);
515
- return empty;
500
+ for (let i = n - 2; i >= 1; i--) m2[i] = d[i] - c[i] * m2[i + 1];
516
501
  }
517
- runStep(step, acc, empty, r) {
518
- if (step.kind === "adjust") {
519
- if (empty) return true;
520
- this.applyFilterRun(step.layers, acc, r);
521
- return false;
522
- }
523
- const layer = step.layer;
524
- if (!layer.visible) return empty;
525
- const clipped = step.clipped.filter((l) => l.visible);
526
- const coverage = this.renderedAlone(layer) ? null : this.base.maskCoverage(layer, r, this.sources);
527
- if (coverage && coverage.every((v) => v <= 0)) return empty;
528
- if (step.kind === "group" && !this.renderedAlone(layer)) {
529
- if (layer.blend === "pass-through" && !clipped.length) {
530
- if (layer.opacity >= 1 && !coverage) return this.runSteps(step.steps, acc, empty, r);
531
- const before = acc.slice();
532
- const stillEmpty = this.runSteps(step.steps, acc, empty, r);
533
- lerp(acc, before, layer.opacity, coverage);
534
- return empty && stillEmpty;
535
- }
536
- const buf2 = new Float32Array(acc.length);
537
- if (this.runSteps(step.steps, buf2, true, r)) return empty;
538
- this.applyClipped(clipped, buf2, r);
539
- const mode2 = layer.blend === "pass-through" ? "normal" : layer.blend;
540
- this.blend(acc, buf2, mode2, layer.opacity, coverage);
541
- return false;
502
+ let seg = 0;
503
+ for (let k = 0; k < size; k++) {
504
+ const xv = k / (size - 1);
505
+ if (xv <= x[0]) {
506
+ out[k] = clamp01(y[0]);
507
+ continue;
542
508
  }
543
- const content = this.content(layer, r);
544
- if (!content) return empty;
545
- const alone = this.renderedAlone(layer);
546
- const fill2 = !alone && this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1;
547
- const mode = this.blendOf(layer);
548
- if (!clipped.length) {
549
- this.blend(acc, content, mode, layer.opacity * fill2, coverage);
550
- return false;
509
+ if (xv >= x[n - 1]) {
510
+ out[k] = clamp01(y[n - 1]);
511
+ continue;
551
512
  }
552
- const buf = new Float32Array(acc.length);
553
- this.blend(buf, content, "normal", fill2, coverage);
554
- this.applyClipped(clipped, buf, r);
555
- this.blend(acc, buf, mode, layer.opacity, null);
556
- return false;
513
+ while (seg < n - 2 && xv > x[seg + 1]) seg++;
514
+ const x0 = x[seg], x1 = x[seg + 1];
515
+ const h = x1 - x0;
516
+ const a = (x1 - xv) / h;
517
+ const b = (xv - x0) / h;
518
+ 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;
519
+ out[k] = clamp01(v);
557
520
  }
558
- applyClipped(clipped, buf, r) {
559
- let run = [];
560
- const flush = () => {
561
- if (run.length) this.applyFilterRun(run, buf, r);
562
- run = [];
563
- };
564
- for (const c of clipped) {
565
- if (this.isFilter(c)) {
566
- run.push(c);
567
- continue;
568
- }
569
- flush();
570
- const alone = this.renderedAlone(c);
571
- const coverage = alone ? null : this.base.maskCoverage(c, r, this.sources);
572
- let src;
573
- if (isGroup(c) && !alone) {
574
- src = new Float32Array(buf.length);
575
- if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), src, true, r)) continue;
576
- } else src = this.content(c, r);
577
- if (!src) continue;
578
- const fill2 = !alone && this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
579
- const keep = new Float32Array(buf.length >> 2);
580
- for (let i = 3, p = 0; i < buf.length; i += 4, p++) keep[p] = buf[i];
581
- this.blend(buf, src, c.blend === "pass-through" ? "normal" : this.blendOf(c), c.opacity * fill2, coverage);
582
- for (let i = 3, p = 0; i < buf.length; i += 4, p++) buf[i] = keep[p];
521
+ return out;
522
+ }
523
+
524
+ // src/raster/effects/patterns.ts
525
+ var PatternTile = class {
526
+
527
+
528
+
529
+ constructor(p) {
530
+ this.w = Math.max(1, p.width | 0);
531
+ this.h = Math.max(1, p.height | 0);
532
+ const n = this.w * this.h;
533
+ this.px = new Float32Array(n * 4);
534
+ for (let i = 0; i < n; i++) {
535
+ const a = (_nullishCoalesce(p.data[i * 4 + 3], () => ( 0))) / 255;
536
+ this.px[i * 4] = (_nullishCoalesce(p.data[i * 4], () => ( 0))) / 255 * a;
537
+ this.px[i * 4 + 1] = (_nullishCoalesce(p.data[i * 4 + 1], () => ( 0))) / 255 * a;
538
+ this.px[i * 4 + 2] = (_nullishCoalesce(p.data[i * 4 + 2], () => ( 0))) / 255 * a;
539
+ this.px[i * 4 + 3] = a;
583
540
  }
584
- flush();
585
541
  }
586
- applyFilterRun(layers, acc, r) {
587
- const visible = [];
588
- let masks;
589
- for (const node of layers) {
590
- if (!node.visible) continue;
591
- const cov = this.base.maskCoverage(node, r, this.sources);
592
- if (cov) {
593
- if (cov.every((v) => v <= 0)) continue;
594
- (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
542
+ /** Bilinear wrapping sample at tile coordinates (pixel centres at `i + 0.5`), straight alpha into `out`. */
543
+ sample(u, v, out) {
544
+ u -= 0.5;
545
+ v -= 0.5;
546
+ const x0 = Math.floor(u);
547
+ const y0 = Math.floor(v);
548
+ const fx = u - x0;
549
+ const fy = v - y0;
550
+ let r = 0;
551
+ let g = 0;
552
+ let b = 0;
553
+ let a = 0;
554
+ for (let dy = 0; dy < 2; dy++) {
555
+ const wy2 = dy ? fy : 1 - fy;
556
+ if (wy2 === 0) continue;
557
+ const yi = ((y0 + dy) % this.h + this.h) % this.h;
558
+ for (let dx = 0; dx < 2; dx++) {
559
+ const wx2 = dx ? fx : 1 - fx;
560
+ if (wx2 === 0) continue;
561
+ const xi = ((x0 + dx) % this.w + this.w) % this.w;
562
+ const k = wx2 * wy2;
563
+ const i = (yi * this.w + xi) * 4;
564
+ r += this.px[i] * k;
565
+ g += this.px[i + 1] * k;
566
+ b += this.px[i + 2] * k;
567
+ a += this.px[i + 3] * k;
595
568
  }
596
- visible.push(node);
597
569
  }
598
- if (!visible.length) return;
599
- if (this.deep.applyFilterRunDeep) {
600
- if (this.linear) mapColour(acc, _chunk7ISPWEJAcjs.srgbEncode);
601
- this.deep.applyFilterRunDeep(visible, acc, r, masks, this.sources);
602
- if (this.linear) mapColour(acc, _chunk7ISPWEJAcjs.srgbDecode);
570
+ if (a <= 0) {
571
+ out[0] = out[1] = out[2] = out[3] = 0;
603
572
  return;
604
573
  }
605
- const bytes = this.to8(acc);
606
- _optionalChain([this, 'access', _8 => _8.profile, 'access', _9 => _9.applyFilterRun, 'optionalCall', _10 => _10(visible, bytes, r, masks, this.sources)]);
607
- acc.set(this.from8(bytes));
574
+ out[0] = r / a;
575
+ out[1] = g / a;
576
+ out[2] = b / a;
577
+ out[3] = Math.min(1, a);
608
578
  }
609
- // --- Layer content ---------------------------------------------------------------
610
- /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
611
- renderedAlone(layer) {
612
- if (hasActiveEffects(layer.effects) && !this.isFilter(layer)) return true;
613
- if (this.isPixel(layer)) return Boolean(_optionalChain([this, 'access', _11 => _11.profile, 'access', _12 => _12.pixelFilters, 'optionalCall', _13 => _13(layer)]));
614
- return !isGroup(layer);
579
+ };
580
+ var PatternPlacement = class {
581
+
582
+
583
+
584
+
585
+
586
+ /** `anchor`: the layer's top-left (used when `link`); `phase` in px; `scale` a fraction; `angle` degrees counter-clockwise. */
587
+ constructor(anchor, link, phase, scale, angle) {
588
+ const bx = link ? anchor.x : 0;
589
+ const by = link ? anchor.y : 0;
590
+ this.ox = bx + phase.x;
591
+ this.oy = by + phase.y;
592
+ this.inv = Number.isFinite(scale) && scale > 1e-3 ? 1 / scale : 1;
593
+ const a = (Number.isFinite(angle) ? angle : 0) * Math.PI / 180;
594
+ this.c = Math.cos(a);
595
+ this.s = Math.sin(a);
615
596
  }
616
- blendOf(layer) {
617
- return _nullishCoalesce(_optionalChain([this, 'access', _14 => _14.profile, 'access', _15 => _15.contentBlend, 'optionalCall', _16 => _16(layer)]), () => ( layer.blend));
597
+ /** Tile coordinates of the document point `(x, y)` into `out[0..1]`. */
598
+ map(x, y, out) {
599
+ const dx = x - this.ox;
600
+ const dy = y - this.oy;
601
+ out[0] = (dx * this.c - dy * this.s) * this.inv;
602
+ out[1] = (dx * this.s + dy * this.c) * this.inv;
618
603
  }
619
- /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
620
- content(layer, r) {
621
- if (this.renderedAlone(layer)) {
622
- const solo = { ...layer, blend: isGroup(layer) && layer.blend === "pass-through" ? "pass-through" : "normal", opacity: 1, clipped: false };
623
- const bytes = this.base.composite([solo], r, this.sources);
624
- return this.from8(bytes);
625
- }
626
- const surface = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
627
- if (!surface) return null;
628
- const ox = _nullishCoalesce(_optionalChain([layer, 'access', _17 => _17.offset, 'optionalAccess', _18 => _18.x]), () => ( 0));
629
- const oy = _nullishCoalesce(_optionalChain([layer, 'access', _19 => _19.offset, 'optionalAccess', _20 => _20.y]), () => ( 0));
630
- const samples = _chunk7ISPWEJAcjs.readDeepRegion.call(void 0, surface, { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height }, this.depth);
631
- if (samples instanceof Float32Array) return samples;
632
- const out = new Float32Array(samples.length);
633
- for (let i = 0; i < samples.length; i++) out[i] = samples[i] / 65535;
634
- return out;
635
- }
636
- /** 8-bit RGBA to the working space. */
637
- from8(bytes) {
638
- if (this.linear) return _chunk7ISPWEJAcjs.to32From8.call(void 0, bytes, 4);
639
- const out = new Float32Array(bytes.length);
640
- for (let i = 0; i < bytes.length; i++) out[i] = bytes[i] / 255;
641
- return out;
642
- }
643
- /** The working space to 8-bit RGBA. */
644
- to8(acc) {
645
- const out = new Uint8ClampedArray(acc.length);
646
- for (let i = 0; i < acc.length; i += 4) {
647
- for (let c = 0; c < 3; c++) out[i + c] = Math.round((this.linear ? _chunk7ISPWEJAcjs.srgbEncode.call(void 0, acc[i + c]) : acc[i + c]) * 255);
648
- out[i + 3] = Math.round(acc[i + 3] * 255);
604
+ };
605
+ var BUILTINS = {
606
+ checker: { name: "Checker", size: 16, paint: (x, y) => x < 8 !== y < 8 ? [204, 204, 204, 255] : [255, 255, 255, 255] },
607
+ stripes: { name: "Diagonal Stripes", size: 16, paint: (x, y) => (x + y) % 16 < 8 ? [40, 40, 40, 255] : [235, 235, 235, 255] },
608
+ dots: {
609
+ name: "Dots",
610
+ size: 12,
611
+ paint: (x, y) => {
612
+ const d = Math.hypot(x + 0.5 - 6, y + 0.5 - 6);
613
+ const a = Math.max(0, Math.min(1, 3.5 - d));
614
+ return [Math.round(255 - a * 215), Math.round(255 - a * 215), Math.round(255 - a * 215), 255];
649
615
  }
650
- return out;
651
- }
652
- // --- Blending --------------------------------------------------------------------
653
- /** `src` over `dst` with `mode` at `alpha` × coverage (straight alpha, float), as `blendTile`. */
654
- blend(dst, src, mode, alpha, coverage) {
655
- if (!(alpha > 0)) return;
656
- const normal = mode === "normal";
657
- const pigment = mode === "pigment";
658
- const cb = [0, 0, 0];
659
- const cs = [0, 0, 0];
660
- const mix = [0, 0, 0];
661
- for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
662
- const sa = src[i + 3];
663
- if (!(sa > 0)) continue;
664
- const k = coverage ? alpha * coverage[p] : alpha;
665
- if (!(k > 0)) continue;
666
- const as = Math.min(1, sa * k);
667
- const ab = dst[i + 3];
668
- const ao = as + ab * (1 - as);
669
- if (ao <= 0) {
670
- dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
671
- continue;
672
- }
673
- if (normal && as >= 1) {
674
- dst[i] = src[i];
675
- dst[i + 1] = src[i + 1];
676
- dst[i + 2] = src[i + 2];
677
- dst[i + 3] = 1;
678
- continue;
679
- }
680
- for (let c = 0; c < 3; c++) {
681
- cb[c] = dst[i + c];
682
- cs[c] = src[i + c];
683
- }
684
- if (pigment) {
685
- if (this.linear) for (let c = 0; c < 3; c++) cb[c] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, cb[c]), cs[c] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, cs[c]);
686
- _chunk7ISPWEJAcjs.mixPigmentRgb.call(void 0, cb, cs, as / ao, mix);
687
- for (let c = 0; c < 3; c++) dst[i + c] = this.linear ? _chunk7ISPWEJAcjs.srgbDecode.call(void 0, mix[c]) : mix[c];
688
- dst[i + 3] = ao;
689
- continue;
690
- }
691
- const m = normal ? cs : _chunk7ISPWEJAcjs.blendRgb.call(void 0, mode, cb, cs);
692
- const wb = (1 - as) * ab;
693
- const ws = (1 - ab) * as;
694
- const wm = as * ab;
695
- for (let c = 0; c < 3; c++) dst[i + c] = (wb * cb[c] + ws * cs[c] + wm * m[c]) / ao;
696
- dst[i + 3] = ao;
616
+ },
617
+ grid: { name: "Grid", size: 16, paint: (x, y) => x === 0 || y === 0 ? [90, 90, 90, 255] : [250, 250, 250, 255] },
618
+ noise: {
619
+ name: "Noise",
620
+ size: 64,
621
+ paint: (x, y) => {
622
+ const v = Math.round(hashNoise(x, y) * 255);
623
+ return [v, v, v, 255];
697
624
  }
698
625
  }
699
626
  };
700
- function lerp(dst, before, alpha, coverage) {
701
- for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
702
- const k = coverage ? alpha * coverage[p] : alpha;
703
- if (k >= 1) continue;
704
- for (let c = 0; c < 4; c++) dst[i + c] = before[i + c] + (dst[i + c] - before[i + c]) * k;
705
- }
627
+ function builtinPatternIds() {
628
+ return Object.keys(BUILTINS);
706
629
  }
707
- function mapColour(data, f) {
708
- for (let i = 0; i < data.length; i += 4) {
709
- data[i] = f(data[i]);
710
- data[i + 1] = f(data[i + 1]);
711
- data[i + 2] = f(data[i + 2]);
630
+ var builtinCache = /* @__PURE__ */ new Map();
631
+ function builtinPattern(id) {
632
+ const def = BUILTINS[id];
633
+ if (!def) return null;
634
+ let p = builtinCache.get(id);
635
+ if (!p) {
636
+ const data = new Uint8ClampedArray(def.size * def.size * 4);
637
+ for (let y = 0; y < def.size; y++) {
638
+ for (let x = 0; x < def.size; x++) data.set(def.paint(x, y), (y * def.size + x) * 4);
639
+ }
640
+ p = { id, name: def.name, width: def.size, height: def.size, data };
641
+ builtinCache.set(id, p);
712
642
  }
643
+ return p;
713
644
  }
714
- function workingToSamples(data, depth) {
715
- if (depth === 32) return data;
716
- const out = new Uint16Array(data.length);
717
- for (let i = 0; i < data.length; i++) {
718
- const v = data[i];
719
- out[i] = v > 0 ? v < 1 ? Math.round(v * 65535) : 65535 : 0;
720
- }
721
- return out;
645
+ function hashNoise(x, y) {
646
+ let h = Math.imul(x | 0, 2376512323) ^ Math.imul(y | 0, 3625334849) ^ 2654435769;
647
+ h ^= h >>> 15;
648
+ h = Math.imul(h, 739982445);
649
+ h ^= h >>> 12;
650
+ return (h & 65535) / 65536;
722
651
  }
723
652
 
724
- // src/raster/blur.ts
725
- function gaussianKernel(sigma) {
726
- const r = Math.ceil(sigma * 3);
727
- const k = new Float32Array(2 * r + 1);
728
- let s = 0;
729
- for (let i = -r; i <= r; i++) {
730
- const v = Math.exp(-(i * i) / (2 * sigma * sigma));
731
- k[i + r] = v;
732
- s += v;
653
+ // src/raster/effects/render.ts
654
+ var INSIDE_EPS = 0.5 / 255;
655
+ var INF = 1e20;
656
+ var FAR = 1e9;
657
+ var STROKE_CHAMFER_MAX = 20;
658
+ var BEVEL_H_EPS = 1e-5;
659
+ var fmap = (w, h, fill2 = 0) => {
660
+ const v = new Float32Array(w * h);
661
+ if (fill2) v.fill(fill2);
662
+ return { w, h, v };
663
+ };
664
+ var clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
665
+ var clamp012 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
666
+ function mapGet(m, x, y) {
667
+ return x < 0 || y < 0 || x >= m.w || y >= m.h ? 0 : m.v[y * m.w + x];
668
+ }
669
+ function shifted(m, dx, dy, outside) {
670
+ const reach = (d) => Number.isFinite(d) ? clamp(d, -1e9, 1e9) : 0;
671
+ dx = reach(dx);
672
+ dy = reach(dy);
673
+ const fx = Math.floor(dx);
674
+ const fy = Math.floor(dy);
675
+ const ax = dx - fx;
676
+ const ay = dy - fy;
677
+ const { w, h, v } = m;
678
+ const s = (x, y) => x < 0 || y < 0 || x >= w || y >= h ? outside : v[y * w + x];
679
+ const out = fmap(w, h);
680
+ for (let y = 0; y < h; y++) {
681
+ const sy = y - fy;
682
+ for (let x = 0; x < w; x++) {
683
+ const sx = x - fx;
684
+ const top = s(sx, sy) * (1 - ax) + s(sx - 1, sy) * ax;
685
+ const bot = s(sx, sy - 1) * (1 - ax) + s(sx - 1, sy - 1) * ax;
686
+ out.v[y * w + x] = top * (1 - ay) + bot * ay;
687
+ }
733
688
  }
734
- for (let i = 0; i < k.length; i++) k[i] /= s;
735
- return k;
689
+ return out;
736
690
  }
737
- var DIRECT_GAUSSIAN_MAX_SIGMA = 8;
738
- function boxRadii(sigma) {
739
- const n = 3;
740
- const wIdeal = Math.sqrt(12 * sigma * sigma / n + 1);
741
- let wl = Math.floor(wIdeal);
742
- if (wl % 2 === 0) wl--;
743
- const wu = wl + 2;
744
- const mIdeal = (12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
745
- const m = Math.round(mIdeal);
746
- const sizes = [0, 1, 2].map((i) => i < m ? wl : wu);
747
- return sizes.map((s) => (s - 1) / 2);
691
+ function mapped(m, f) {
692
+ const out = fmap(m.w, m.h);
693
+ for (let i = 0; i < m.v.length; i++) out.v[i] = f(m.v[i]);
694
+ return out;
748
695
  }
749
- function convolveLine(src, off, stride, len, k, edge, dst) {
750
- const r = (k.length - 1) / 2;
751
- for (let i = 0; i < len; i++) {
752
- let a = 0;
753
- const lo = i - r;
754
- for (let j = 0; j < k.length; j++) {
755
- let x = lo + j;
756
- if (x < 0 || x >= len) {
757
- if (edge === "zero") continue;
758
- x = x < 0 ? 0 : len - 1;
696
+ function dt1(f, n, out, near, v, z) {
697
+ let k = 0;
698
+ v[0] = 0;
699
+ z[0] = -Infinity;
700
+ z[1] = Infinity;
701
+ for (let q = 1; q < n; q++) {
702
+ for (; ; ) {
703
+ const p = v[k];
704
+ const s = (f[q] + q * q - (f[p] + p * p)) / (2 * q - 2 * p);
705
+ if (s <= z[k] && k > 0) {
706
+ k--;
707
+ continue;
759
708
  }
760
- a += src[off + x * stride] * k[j];
709
+ if (s <= z[k]) {
710
+ v[0] = q;
711
+ z[0] = -Infinity;
712
+ z[1] = Infinity;
713
+ break;
714
+ }
715
+ k++;
716
+ v[k] = q;
717
+ z[k] = s;
718
+ z[k + 1] = Infinity;
719
+ break;
761
720
  }
762
- dst[i] = a;
763
721
  }
764
- }
765
- function boxesLine(src, off, stride, len, radii, edge, a, b, dst) {
766
- const pad = radii.reduce((s, r) => s + r, 0);
767
- const plen = len + 2 * pad;
768
- for (let i = 0; i < plen; i++) {
769
- const j = i - pad;
770
- a[i] = j < 0 ? edge === "zero" ? 0 : src[off] : j >= len ? edge === "zero" ? 0 : src[off + (len - 1) * stride] : src[off + j * stride];
722
+ k = 0;
723
+ for (let q = 0; q < n; q++) {
724
+ while (z[k + 1] < q) k++;
725
+ const p = v[k];
726
+ const d = q - p;
727
+ out[q] = d * d + f[p];
728
+ near[q] = p;
771
729
  }
772
- let from = a;
773
- let to = b;
774
- for (const r of radii) {
775
- let sum = 0;
776
- for (let i = 0; i <= Math.min(r, plen - 1); i++) sum += from[i];
777
- const k = 2 * r + 1;
778
- for (let i = 0; i < plen; i++) {
779
- to[i] = sum / k;
780
- const add = i + r + 1;
781
- const drop = i - r;
782
- if (add < plen) sum += from[add];
783
- if (drop >= 0) sum -= from[drop];
784
- }
785
- const t = from;
786
- from = to;
787
- to = t;
788
- }
789
- for (let i = 0; i < len; i++) dst[i] = from[i + pad];
790
730
  }
791
- function gaussianBlur(src, w, h, sigma, edge = "zero") {
792
- const out = Float32Array.from(src);
793
- if (!(sigma >= 0.1) || w <= 0 || h <= 0) return out;
794
- const s = Math.min(sigma, 4 * Math.max(w, h));
795
- const line = new Float32Array(Math.max(w, h));
796
- const passes = [];
797
- if (s <= DIRECT_GAUSSIAN_MAX_SIGMA) {
798
- const k = gaussianKernel(s);
799
- passes.push((buf, off, stride, len) => convolveLine(buf, off, stride, len, k, edge, line));
800
- } else {
801
- const radii = boxRadii(s);
802
- const plen = Math.max(w, h) + 2 * radii.reduce((a2, r) => a2 + r, 0);
803
- const a = new Float32Array(plen);
804
- const b = new Float32Array(plen);
805
- passes.push((buf, off, stride, len) => boxesLine(buf, off, stride, len, radii, edge, a, b, line));
806
- }
807
- for (const pass of passes) {
731
+ function edtNearest(inside, w, h) {
732
+ const total = w * h;
733
+ const n = Math.max(w, h);
734
+ const f = new Float64Array(n);
735
+ const o = new Float64Array(n);
736
+ const nr = new Int32Array(n);
737
+ const v = new Int32Array(n);
738
+ const z = new Float64Array(n + 1);
739
+ const gc = new Float64Array(total);
740
+ const nc = new Int32Array(total);
741
+ for (let x = 0; x < w; x++) {
742
+ for (let y = 0; y < h; y++) f[y] = inside[y * w + x] ? 0 : INF;
743
+ dt1(f, h, o, nr, v, z);
808
744
  for (let y = 0; y < h; y++) {
809
- pass(out, y * w, 1, w);
810
- out.set(line.subarray(0, w), y * w);
745
+ gc[x * h + y] = o[y];
746
+ nc[x * h + y] = nr[y];
811
747
  }
812
748
  }
813
- for (const pass of passes) {
749
+ const d = new Float32Array(total);
750
+ const near = new Int32Array(total);
751
+ for (let y = 0; y < h; y++) {
752
+ for (let x = 0; x < w; x++) f[x] = gc[x * h + y];
753
+ dt1(f, w, o, nr, v, z);
814
754
  for (let x = 0; x < w; x++) {
815
- pass(out, x, w, h);
816
- for (let y = 0; y < h; y++) out[y * w + x] = line[y];
755
+ d[y * w + x] = Math.sqrt(o[x]);
756
+ const px = nr[x];
757
+ near[y * w + x] = nc[px * h + y] * w + px;
817
758
  }
818
759
  }
819
- return out;
760
+ return { d, near };
820
761
  }
821
-
822
- // src/raster/layers.ts
823
- var childrenOf = (l) => l.type === "group" ? _nullishCoalesce(l.children, () => ( null)) : null;
824
- function flattenLayers(layers) {
825
- const out = [];
826
- const walk = (list) => {
827
- for (const l of list) {
828
- out.push(l);
829
- const c = childrenOf(l);
830
- if (c) walk(c);
762
+ var S2 = Math.SQRT2;
763
+ var S5 = 2.236068;
764
+ var FWD = [
765
+ [-1, 0, 1],
766
+ [-1, -1, S2],
767
+ [0, -1, 1],
768
+ [1, -1, S2],
769
+ [-1, -2, S5],
770
+ [1, -2, S5],
771
+ [-2, -1, S5],
772
+ [2, -1, S5]
773
+ ];
774
+ function chamferFrom(d, w, h) {
775
+ const ox = FWD.map((f) => f[0]);
776
+ const oy = FWD.map((f) => f[1]);
777
+ const wt = FWD.map((f) => f[2]);
778
+ const k = FWD.length;
779
+ for (let pass = 0; pass < 2; pass++) {
780
+ const sign = pass === 0 ? 1 : -1;
781
+ for (let yy = 0; yy < h; yy++) {
782
+ const y = pass === 0 ? yy : h - 1 - yy;
783
+ for (let xx = 0; xx < w; xx++) {
784
+ const x = pass === 0 ? xx : w - 1 - xx;
785
+ const i = y * w + x;
786
+ let best = d[i];
787
+ for (let j = 0; j < k; j++) {
788
+ const nx = x + ox[j] * sign;
789
+ const ny = y + oy[j] * sign;
790
+ if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue;
791
+ const c = d[ny * w + nx] + wt[j];
792
+ if (c < best) best = c;
793
+ }
794
+ d[i] = best;
795
+ }
831
796
  }
832
- };
833
- walk(layers);
797
+ }
798
+ return d;
799
+ }
800
+ function distOutside(s, chamfer) {
801
+ const { w, h, v } = s;
802
+ const n = v.length;
803
+ const out = new Float32Array(n);
804
+ if (chamfer) {
805
+ const start = new Float32Array(n);
806
+ for (let i = 0; i < n; i++) start[i] = v[i] > INSIDE_EPS ? 1 - Math.min(v[i], 1) : INF;
807
+ const d2 = chamferFrom(start, w, h);
808
+ for (let i = 0; i < n; i++) out[i] = v[i] > INSIDE_EPS ? -0.5 : d2[i] - 0.5;
809
+ return out;
810
+ }
811
+ const inside = new Uint8Array(n);
812
+ for (let i = 0; i < n; i++) inside[i] = v[i] > INSIDE_EPS ? 1 : 0;
813
+ const { d, near } = edtNearest(inside, w, h);
814
+ for (let i = 0; i < n; i++) out[i] = inside[i] ? -0.5 : d[i] - 0.5 + (1 - Math.min(v[near[i]], 1));
834
815
  return out;
835
816
  }
836
- function findLayer(layers, id) {
837
- const walk = (list, parent, path) => {
838
- for (let i = 0; i < list.length; i++) {
839
- const l = list[i];
840
- if (l.id === id) return { layer: l, parent, index: i, path };
841
- const c = childrenOf(l);
842
- if (c) {
843
- const g = l;
844
- const hit = walk(c, g, [...path, g]);
845
- if (hit) return hit;
846
- }
817
+ function localCoverage(s) {
818
+ const out = { w: s.w, h: s.h, v: new Float32Array(s.v) };
819
+ for (let y = 0; y < s.h; y++) {
820
+ for (let x = 0; x < s.w; x++) {
821
+ const a = s.v[y * s.w + x];
822
+ if (a <= INSIDE_EPS) continue;
823
+ let mx = a;
824
+ for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) mx = Math.max(mx, mapGet(s, x + dx, y + dy));
825
+ out.v[y * s.w + x] = Math.min(a / mx, 1);
847
826
  }
848
- return null;
849
- };
850
- return walk(layers, null, []);
827
+ }
828
+ return out;
851
829
  }
852
- function mapLayer(layers, id, fn) {
853
- let changed = false;
854
- const walk = (list) => {
855
- let out = null;
856
- for (let i = 0; i < list.length; i++) {
857
- const l = list[i];
858
- let next = l;
859
- if (l.id === id) {
860
- next = fn(l);
861
- changed = true;
830
+ function distInside(s, chamfer) {
831
+ const { w, h, v } = s;
832
+ const n = v.length;
833
+ const out = new Float32Array(n);
834
+ if (chamfer) {
835
+ const cov = localCoverage(s);
836
+ const start = new Float32Array(n);
837
+ for (let i = 0; i < n; i++) start[i] = v[i] <= INSIDE_EPS ? 0 : cov.v[i] < 1 - INSIDE_EPS ? cov.v[i] : INF;
838
+ const d2 = chamferFrom(start, w, h);
839
+ for (let i = 0; i < n; i++) out[i] = v[i] <= INSIDE_EPS ? -0.5 : d2[i] - 0.5;
840
+ return out;
841
+ }
842
+ const outside = new Uint8Array(n);
843
+ for (let i = 0; i < n; i++) outside[i] = v[i] <= INSIDE_EPS ? 1 : 0;
844
+ const { d } = edtNearest(outside, w, h);
845
+ for (let i = 0; i < n; i++) out[i] = outside[i] ? -0.5 : d[i] - 0.5;
846
+ return out;
847
+ }
848
+ function edgeDistances(s, reach) {
849
+ const { w, h, v } = s;
850
+ const n = v.length;
851
+ const edge = new Uint8Array(n);
852
+ const inside = new Uint8Array(n);
853
+ for (let y = 0; y < h; y++) {
854
+ for (let x = 0; x < w; x++) {
855
+ const i = y * w + x;
856
+ const a = v[i];
857
+ if (a <= INSIDE_EPS) continue;
858
+ inside[i] = 1;
859
+ if (a < 1 - INSIDE_EPS || mapGet(s, x - 1, y) <= INSIDE_EPS || mapGet(s, x + 1, y) <= INSIDE_EPS || mapGet(s, x, y - 1) <= INSIDE_EPS || mapGet(s, x, y + 1) <= INSIDE_EPS) edge[i] = 1;
860
+ }
861
+ }
862
+ const { d, near } = edtNearest(edge, w, h);
863
+ const din = new Float32Array(n);
864
+ const dout = new Float32Array(n);
865
+ for (let y = 0; y < h; y++) {
866
+ for (let x = 0; x < w; x++) {
867
+ const i = y * w + x;
868
+ const q = near[i];
869
+ let sd;
870
+ if (d[i] > reach || d[i] >= INF / 2) {
871
+ sd = inside[i] ? -(d[i] + 0.5) : d[i] - 0.5;
862
872
  } else {
863
- const c = childrenOf(l);
864
- if (c) {
865
- const children = walk(c);
866
- if (children !== c) next = { ...l, children };
873
+ const qx = q % w;
874
+ const qy = (q - qx) / w;
875
+ const g = (dx, dy) => mapGet(s, qx + dx, qy + dy);
876
+ let nx = -(g(1, -1) + 2 * g(1, 0) + g(1, 1) - g(-1, -1) - 2 * g(-1, 0) - g(-1, 1));
877
+ let ny = -(g(-1, 1) + 2 * g(0, 1) + g(1, 1) - g(-1, -1) - 2 * g(0, -1) - g(1, -1));
878
+ const len = Math.hypot(nx, ny);
879
+ if (len > 1e-6) {
880
+ nx /= len;
881
+ ny /= len;
882
+ } else if (d[i] > 0) {
883
+ nx = (x - qx) / d[i];
884
+ ny = (y - qy) / d[i];
885
+ } else {
886
+ nx = 1;
887
+ ny = 0;
867
888
  }
889
+ sd = (x - qx) * nx + (y - qy) * ny - (Math.min(v[q], 1) - 0.5);
868
890
  }
869
- if (next !== l) {
870
- if (!out) out = list.slice(0, i);
871
- if (next) out.push(next);
872
- } else if (out) out.push(l);
891
+ din[i] = inside[i] ? Math.max(-sd, inside[i] && !edge[i] ? 0.5 : -0.5) : -0.5;
892
+ dout[i] = inside[i] && !edge[i] ? -0.5 : Math.max(sd, -0.5);
873
893
  }
874
- return _nullishCoalesce(out, () => ( list));
875
- };
876
- const result = walk(layers);
877
- return changed ? result : layers;
894
+ }
895
+ return { din, dout };
878
896
  }
879
- function insertLayer(layers, layer, parentId, index) {
880
- const put = (list) => {
881
- const at = index === void 0 ? list.length : Math.max(0, Math.min(list.length, index));
882
- const next = list.slice();
883
- next.splice(at, 0, layer);
884
- return next;
885
- };
886
- if (!parentId) return put(layers);
887
- return mapLayer(layers, parentId, (g) => {
888
- const c = childrenOf(g);
889
- return c ? { ...g, children: put(c) } : g;
890
- });
897
+ function dilate(s, r) {
898
+ if (!(r > 0)) return s;
899
+ const d = distOutside(s, true);
900
+ const out = { w: s.w, h: s.h, v: new Float32Array(s.v) };
901
+ for (let i = 0; i < d.length; i++) {
902
+ const o = out.v[i];
903
+ out.v[i] = d[i] < 0 ? Math.min(o + r, 1) : Math.max(o, clamp012(r + 0.5 - d[i]));
904
+ }
905
+ return out;
891
906
  }
892
- function isLayerLocked(layer, what) {
893
- return Boolean(_optionalChain([layer, 'access', _21 => _21.locks, 'optionalAccess', _22 => _22.all]) || _optionalChain([layer, 'access', _23 => _23.locks, 'optionalAccess', _24 => _24[what]]));
907
+ function boxWidth(w) {
908
+ return Number.isNaN(w) ? 1 : clamp(w, 1, MAX_EFFECT_REACH);
894
909
  }
895
-
896
- // src/raster/effects/patterns.ts
897
- var PatternTile = class {
898
-
899
-
900
-
901
- constructor(p) {
902
- this.w = Math.max(1, p.width | 0);
903
- this.h = Math.max(1, p.height | 0);
904
- const n = this.w * this.h;
905
- this.px = new Float32Array(n * 4);
906
- for (let i = 0; i < n; i++) {
907
- const a = (_nullishCoalesce(p.data[i * 4 + 3], () => ( 0))) / 255;
908
- this.px[i * 4] = (_nullishCoalesce(p.data[i * 4], () => ( 0))) / 255 * a;
909
- this.px[i * 4 + 1] = (_nullishCoalesce(p.data[i * 4 + 1], () => ( 0))) / 255 * a;
910
- this.px[i * 4 + 2] = (_nullishCoalesce(p.data[i * 4 + 2], () => ( 0))) / 255 * a;
911
- this.px[i * 4 + 3] = a;
912
- }
910
+ function boxGeom(bw) {
911
+ bw = boxWidth(bw);
912
+ const half = bw / 2;
913
+ const r = Math.max(0, Math.ceil(half - 0.5));
914
+ const f = clamp012(half - (r - 0.5));
915
+ return [r, f, 1 / bw];
916
+ }
917
+ function boxLine(src, x0, dst, bw) {
918
+ const n = src.length;
919
+ const [r, f, norm] = boxGeom(bw);
920
+ const at = (i) => i >= 0 && i < n ? src[i] : 0;
921
+ if (r === 0) {
922
+ for (let k = 0; k < dst.length; k++) dst[k] = at(x0 + k);
923
+ return;
913
924
  }
914
- /** Bilinear wrapping sample at tile coordinates (pixel centres at `i + 0.5`), straight alpha into `out`. */
915
- sample(u, v, out) {
916
- u -= 0.5;
917
- v -= 0.5;
918
- const x0 = Math.floor(u);
919
- const y0 = Math.floor(v);
920
- const fx = u - x0;
921
- const fy = v - y0;
922
- let r = 0;
923
- let g = 0;
924
- let b = 0;
925
- let a = 0;
926
- for (let dy = 0; dy < 2; dy++) {
927
- const wy2 = dy ? fy : 1 - fy;
928
- if (wy2 === 0) continue;
929
- const yi = ((y0 + dy) % this.h + this.h) % this.h;
930
- for (let dx = 0; dx < 2; dx++) {
931
- const wx2 = dx ? fx : 1 - fx;
932
- if (wx2 === 0) continue;
933
- const xi = ((x0 + dx) % this.w + this.w) % this.w;
934
- const k = wx2 * wy2;
935
- const i = (yi * this.w + xi) * 4;
936
- r += this.px[i] * k;
937
- g += this.px[i + 1] * k;
938
- b += this.px[i + 2] * k;
939
- a += this.px[i + 3] * k;
940
- }
941
- }
942
- if (a <= 0) {
943
- out[0] = out[1] = out[2] = out[3] = 0;
944
- return;
945
- }
946
- out[0] = r / a;
947
- out[1] = g / a;
948
- out[2] = b / a;
949
- out[3] = Math.min(1, a);
925
+ let inner = 0;
926
+ for (let i = x0 - (r - 1); i <= x0 + (r - 1); i++) inner += at(i);
927
+ for (let k = 0; k < dst.length; k++) {
928
+ const x = x0 + k;
929
+ dst[k] = (inner + f * (at(x - r) + at(x + r))) * norm;
930
+ inner += at(x + r) - at(x - r + 1);
950
931
  }
951
- };
952
- var PatternPlacement = class {
953
-
954
-
955
-
956
-
957
-
958
- /** `anchor`: the layer's top-left (used when `link`); `phase` in px; `scale` a fraction; `angle` degrees counter-clockwise. */
959
- constructor(anchor, link, phase, scale, angle) {
960
- const bx = link ? anchor.x : 0;
961
- const by = link ? anchor.y : 0;
962
- this.ox = bx + phase.x;
963
- this.oy = by + phase.y;
964
- this.inv = Number.isFinite(scale) && scale > 1e-3 ? 1 / scale : 1;
965
- const a = (Number.isFinite(angle) ? angle : 0) * Math.PI / 180;
966
- this.c = Math.cos(a);
967
- this.s = Math.sin(a);
932
+ }
933
+ var BLUR_EPS = 1e-7;
934
+ var BLUR_FIX = 2 ** 32;
935
+ function tentLine(src, dst, bw, mid) {
936
+ const [r] = boxGeom(bw);
937
+ const m = mid.subarray(0, src.length + 2 * r);
938
+ for (let i = 0; i < src.length; i++) src[i] = Math.round(src[i] * BLUR_FIX);
939
+ boxLine(src, -r, m, bw);
940
+ for (let i = 0; i < m.length; i++) m[i] = Math.round(m[i]);
941
+ boxLine(m, r, dst, bw);
942
+ for (let i = 0; i < dst.length; i++) {
943
+ const v = dst[i] / BLUR_FIX;
944
+ dst[i] = Math.abs(v) < BLUR_EPS ? 0 : v;
968
945
  }
969
- /** Tile coordinates of the document point `(x, y)` into `out[0..1]`. */
970
- map(x, y, out) {
971
- const dx = x - this.ox;
972
- const dy = y - this.oy;
973
- out[0] = (dx * this.c - dy * this.s) * this.inv;
974
- out[1] = (dx * this.s + dy * this.c) * this.inv;
946
+ }
947
+ function tent(m, w) {
948
+ if (!Number.isFinite(w) || m.v.length === 0) return;
949
+ if (boxGeom(w)[0] === 0) return;
950
+ const { w: mw, h: mh } = m;
951
+ const r = boxGeom(w)[0];
952
+ const mid = new Float64Array(Math.max(mw, mh) + 2 * r);
953
+ const row = new Float64Array(mw);
954
+ const rowOut = new Float64Array(mw);
955
+ for (let y = 0; y < mh; y++) {
956
+ for (let x = 0; x < mw; x++) row[x] = m.v[y * mw + x];
957
+ tentLine(row, rowOut, w, mid);
958
+ for (let x = 0; x < mw; x++) m.v[y * mw + x] = rowOut[x];
975
959
  }
976
- };
977
- var BUILTINS = {
978
- checker: { name: "Checker", size: 16, paint: (x, y) => x < 8 !== y < 8 ? [204, 204, 204, 255] : [255, 255, 255, 255] },
979
- stripes: { name: "Diagonal Stripes", size: 16, paint: (x, y) => (x + y) % 16 < 8 ? [40, 40, 40, 255] : [235, 235, 235, 255] },
980
- dots: {
981
- name: "Dots",
982
- size: 12,
983
- paint: (x, y) => {
984
- const d = Math.hypot(x + 0.5 - 6, y + 0.5 - 6);
985
- const a = Math.max(0, Math.min(1, 3.5 - d));
986
- return [Math.round(255 - a * 215), Math.round(255 - a * 215), Math.round(255 - a * 215), 255];
987
- }
988
- },
989
- grid: { name: "Grid", size: 16, paint: (x, y) => x === 0 || y === 0 ? [90, 90, 90, 255] : [250, 250, 250, 255] },
990
- noise: {
991
- name: "Noise",
992
- size: 64,
993
- paint: (x, y) => {
994
- const v = Math.round(hashNoise(x, y) * 255);
995
- return [v, v, v, 255];
996
- }
960
+ const col = new Float64Array(mh);
961
+ const colOut = new Float64Array(mh);
962
+ for (let x = 0; x < mw; x++) {
963
+ for (let y = 0; y < mh; y++) col[y] = m.v[y * mw + x];
964
+ tentLine(col, colOut, w, mid);
965
+ for (let y = 0; y < mh; y++) m.v[y * mw + x] = colOut[y];
997
966
  }
998
- };
999
- function builtinPatternIds() {
1000
- return Object.keys(BUILTINS);
1001
967
  }
1002
- var builtinCache = /* @__PURE__ */ new Map();
1003
- function builtinPattern(id) {
1004
- const def = BUILTINS[id];
1005
- if (!def) return null;
1006
- let p = builtinCache.get(id);
1007
- if (!p) {
1008
- const data = new Uint8ClampedArray(def.size * def.size * 4);
1009
- for (let y = 0; y < def.size; y++) {
1010
- for (let x = 0; x < def.size; x++) data.set(def.paint(x, y), (y * def.size + x) * 4);
968
+ function blur(m, size) {
969
+ if (Number.isFinite(size)) tent(m, size);
970
+ }
971
+ var lutCache = /* @__PURE__ */ new WeakMap();
972
+ function contourLut(c) {
973
+ if (!c) return null;
974
+ const cached = lutCache.get(c);
975
+ if (cached !== void 0) return cached;
976
+ const pts = c.points;
977
+ const linear = pts.length === 2 && pts[0].input === 0 && pts[0].output === 0 && pts[1].input === 1 && pts[1].output === 1;
978
+ let lut = null;
979
+ if (pts.length >= 2 && !linear) {
980
+ if (!pts.some((p) => p.corner)) lut = curveLut(pts);
981
+ else {
982
+ const sorted = [...pts].sort((a, b) => a.input - b.input);
983
+ let start = 0;
984
+ for (let i = 1; i < sorted.length; i++) {
985
+ if (!(sorted[i].corner || i === sorted.length - 1)) continue;
986
+ const seg = sorted.slice(start, i + 1);
987
+ const from = seg[0].input;
988
+ const part = curveLut(seg);
989
+ if (!lut) lut = part;
990
+ else for (let k = 0; k < part.length; k++) if (k / (part.length - 1) >= from) lut[k] = part[k];
991
+ start = i;
992
+ }
993
+ lut ??= curveLut(pts);
1011
994
  }
1012
- p = { id, name: def.name, width: def.size, height: def.size, data };
1013
- builtinCache.set(id, p);
1014
995
  }
1015
- return p;
996
+ lutCache.set(c, lut);
997
+ return lut;
1016
998
  }
1017
- function hashNoise(x, y) {
1018
- let h = Math.imul(x | 0, 2376512323) ^ Math.imul(y | 0, 3625334849) ^ 2654435769;
1019
- h ^= h >>> 15;
1020
- h = Math.imul(h, 739982445);
1021
- h ^= h >>> 12;
1022
- return (h & 65535) / 65536;
999
+ function lutAt(l, v) {
1000
+ const x = clamp012(v) * (l.length - 1);
1001
+ const i = Math.floor(x);
1002
+ const j = Math.min(i + 1, l.length - 1);
1003
+ return l[i] + (l[j] - l[i]) * (x - i);
1023
1004
  }
1024
-
1025
- // src/raster/curve.ts
1026
- var CURVE_LUT_SIZE = 4096;
1027
- var clamp01 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
1028
- function curveLut(points, size = CURVE_LUT_SIZE) {
1029
- 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]);
1030
- const dedup = [];
1031
- for (const p of pts) {
1032
- if (dedup.length && Math.abs(dedup[dedup.length - 1][0] - p[0]) < 1e-6) continue;
1033
- dedup.push(p);
1005
+ function applyLut(m, l) {
1006
+ return l ? mapped(m, (v) => lutAt(l, v)) : m;
1007
+ }
1008
+ function rangedLut(c, range) {
1009
+ const base = contourLut(c);
1010
+ const r = Number.isFinite(range) ? clamp(range, 0.01, 1) : 1;
1011
+ if (r >= 0.999) return base;
1012
+ const n = 4096;
1013
+ const out = new Float32Array(n);
1014
+ for (let k = 0; k < n; k++) {
1015
+ const v = Math.min(k / (n - 1) / r, 1);
1016
+ out[k] = base ? lutAt(base, v) : v;
1034
1017
  }
1035
- const out = new Float32Array(size);
1036
- const n = dedup.length;
1037
- if (n < 2) {
1038
- for (let k = 0; k < size; k++) out[k] = k / (size - 1);
1039
- return out;
1018
+ return out;
1019
+ }
1020
+ function satinLut(c) {
1021
+ const lut = contourLut(c);
1022
+ if (!lut) return null;
1023
+ const end = lut[lut.length - 1];
1024
+ const out = new Float32Array(lut.length);
1025
+ for (let k = 0; k < lut.length; k++) out[k] = Math.abs(lut[lut.length - 1 - k] - end);
1026
+ return out;
1027
+ }
1028
+ function noise(m, amount, x0, y0) {
1029
+ if (!Number.isFinite(amount) || amount <= 0) return;
1030
+ for (let y = 0; y < m.h; y++) {
1031
+ for (let x = 0; x < m.w; x++) {
1032
+ const i = y * m.w + x;
1033
+ if (m.v[i] <= BLUR_EPS) continue;
1034
+ m.v[i] = clamp012(m.v[i] + (hashNoise(x0 + x, y0 + y) - 0.5) * 2 * amount);
1035
+ }
1040
1036
  }
1041
- const x = dedup.map((p) => p[0]);
1042
- const y = dedup.map((p) => p[1]);
1043
- const m2 = new Float64Array(n);
1044
- if (n > 2) {
1045
- const c = new Float64Array(n);
1046
- const d = new Float64Array(n);
1047
- for (let i = 1; i < n - 1; i++) {
1048
- const h0 = x[i] - x[i - 1];
1049
- const h1 = x[i + 1] - x[i];
1050
- const a = h0 / 6;
1051
- const b = (h0 + h1) / 3;
1052
- const cc = h1 / 6;
1053
- const r = (y[i + 1] - y[i]) / h1 - (y[i] - y[i - 1]) / h0;
1054
- const denom = b - a * c[i - 1];
1055
- c[i] = cc / denom;
1056
- d[i] = (r - a * d[i - 1]) / denom;
1057
- }
1058
- for (let i = n - 2; i >= 1; i--) m2[i] = d[i] - c[i] * m2[i + 1];
1059
- }
1060
- let seg = 0;
1061
- for (let k = 0; k < size; k++) {
1062
- const xv = k / (size - 1);
1063
- if (xv <= x[0]) {
1064
- out[k] = clamp01(y[0]);
1065
- continue;
1066
- }
1067
- if (xv >= x[n - 1]) {
1068
- out[k] = clamp01(y[n - 1]);
1069
- continue;
1070
- }
1071
- while (seg < n - 2 && xv > x[seg + 1]) seg++;
1072
- const x0 = x[seg], x1 = x[seg + 1];
1073
- const h = x1 - x0;
1074
- const a = (x1 - xv) / h;
1075
- const b = (xv - x0) / h;
1076
- 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;
1077
- out[k] = clamp01(v);
1078
- }
1079
- return out;
1080
1037
  }
1081
-
1082
- // src/raster/effects/render.ts
1083
- var INSIDE_EPS = 0.5 / 255;
1084
- var INF = 1e20;
1085
- var FAR = 1e9;
1086
- var STROKE_CHAMFER_MAX = 20;
1087
- var BEVEL_H_EPS = 1e-5;
1088
- var fmap = (w, h, fill2 = 0) => {
1089
- const v = new Float32Array(w * h);
1090
- if (fill2) v.fill(fill2);
1091
- return { w, h, v };
1092
- };
1093
- var clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
1094
- var clamp012 = (v) => v <= 0 ? 0 : v >= 1 ? 1 : v;
1095
- function mapGet(m, x, y) {
1096
- return x < 0 || y < 0 || x >= m.w || y >= m.h ? 0 : m.v[y * m.w + x];
1038
+ function lightOffset(angle, distance) {
1039
+ const a = angle * Math.PI / 180;
1040
+ return [Math.round(-Math.cos(a) * distance), Math.round(Math.sin(a) * distance)];
1097
1041
  }
1098
- function shifted(m, dx, dy, outside) {
1099
- const reach = (d) => Number.isFinite(d) ? clamp(d, -1e9, 1e9) : 0;
1100
- dx = reach(dx);
1101
- dy = reach(dy);
1102
- const fx = Math.floor(dx);
1103
- const fy = Math.floor(dy);
1104
- const ax = dx - fx;
1105
- const ay = dy - fy;
1106
- const { w, h, v } = m;
1107
- const s = (x, y) => x < 0 || y < 0 || x >= w || y >= h ? outside : v[y * w + x];
1108
- const out = fmap(w, h);
1109
- for (let y = 0; y < h; y++) {
1110
- const sy = y - fy;
1111
- for (let x = 0; x < w; x++) {
1112
- const sx = x - fx;
1113
- const top = s(sx, sy) * (1 - ax) + s(sx - 1, sy) * ax;
1114
- const bot = s(sx, sy - 1) * (1 - ax) + s(sx - 1, sy - 1) * ax;
1115
- out.v[y * w + x] = top * (1 - ay) + bot * ay;
1042
+ function spreadSplit(size, spread) {
1043
+ return [Math.round(size * spread), size * (1 - spread)];
1044
+ }
1045
+ function shadowMap(shape, s, spread, light, inner, ox, oy) {
1046
+ const angle = s.useGlobalLight ? light.angle : s.angle;
1047
+ const [dx, dy] = lightOffset(angle, s.distance);
1048
+ const src = inner ? mapped(shape, (a) => 1 - a) : shape;
1049
+ let m = shifted(src, dx, dy, inner ? 1 : 0);
1050
+ const [r, bw] = spreadSplit(s.size, spread);
1051
+ m = dilate(m, r);
1052
+ blur(m, bw);
1053
+ m = applyLut(m, contourLut(s.contour));
1054
+ noise(m, s.noise, ox, oy);
1055
+ if (inner) for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1056
+ return m;
1057
+ }
1058
+ function glowMap(shape, g, ox, oy) {
1059
+ const inner = g.kind === "inner-glow";
1060
+ const spread = inner ? g.choke : g.spread;
1061
+ const src = inner ? mapped(shape, (a) => 1 - a) : shape;
1062
+ let m;
1063
+ if (g.technique === "precise") {
1064
+ const d = inner ? distInside(shape, false) : distOutside(src, false);
1065
+ const solid = g.size * spread;
1066
+ const soft = Math.max(g.size + 1 - solid, 1e-3);
1067
+ m = fmap(shape.w, shape.h);
1068
+ for (let i = 0; i < d.length; i++) {
1069
+ const di = d[i] + 0.5;
1070
+ m.v[i] = di <= solid ? 1 : 0.5 * clamp012(1 - (di - solid) / soft);
1116
1071
  }
1072
+ } else {
1073
+ const [r, bw] = spreadSplit(g.size, spread);
1074
+ m = dilate(src, r);
1075
+ if (m === src || m === shape) m = { w: m.w, h: m.h, v: new Float32Array(m.v) };
1076
+ blur(m, bw);
1117
1077
  }
1118
- return out;
1078
+ m = applyLut(m, rangedLut(g.contour, g.range));
1079
+ if (inner && g.source === "center") m = mapped(m, (v) => 1 - v);
1080
+ noise(m, g.noise, ox, oy);
1081
+ if (inner) for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1082
+ return m;
1119
1083
  }
1120
- function mapped(m, f) {
1121
- const out = fmap(m.w, m.h);
1122
- for (let i = 0; i < m.v.length; i++) out.v[i] = f(m.v[i]);
1123
- return out;
1084
+ function satinMap(shape, s) {
1085
+ const [dx, dy] = lightOffset(s.angle, Math.max(1, s.distance));
1086
+ const a = shifted(shape, dx, dy, 0);
1087
+ const b = shifted(shape, -dx, -dy, 0);
1088
+ tent(a, s.size);
1089
+ tent(b, s.size);
1090
+ let m = fmap(shape.w, shape.h);
1091
+ for (let i = 0; i < m.v.length; i++) m.v[i] = Math.abs(a.v[i] - b.v[i]);
1092
+ if (s.invert) m = mapped(m, (v) => 1 - v);
1093
+ m = applyLut(m, satinLut(s.contour));
1094
+ for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1095
+ return m;
1124
1096
  }
1125
- function dt1(f, n, out, near, v, z) {
1126
- let k = 0;
1127
- v[0] = 0;
1128
- z[0] = -Infinity;
1129
- z[1] = Infinity;
1130
- for (let q = 1; q < n; q++) {
1131
- for (; ; ) {
1132
- const p = v[k];
1133
- const s = (f[q] + q * q - (f[p] + p * p)) / (2 * q - 2 * p);
1134
- if (s <= z[k] && k > 0) {
1135
- k--;
1136
- continue;
1137
- }
1138
- if (s <= z[k]) {
1139
- v[0] = q;
1140
- z[0] = -Infinity;
1141
- z[1] = Infinity;
1142
- break;
1143
- }
1144
- k++;
1145
- v[k] = q;
1146
- z[k] = s;
1147
- z[k + 1] = Infinity;
1148
- break;
1149
- }
1097
+ function bevelGeom(b) {
1098
+ const size = Math.max(b.size, 1);
1099
+ const emboss = b.style === "emboss" || b.style === "pillow-emboss";
1100
+ const paint2 = b.style === "outer-bevel" ? "outer" : emboss ? "both" : "inner";
1101
+ const width = emboss ? Math.ceil(size / 2) : size;
1102
+ const smooth = b.technique === "smooth";
1103
+ const sign = b.direction === "up" ? 1 : -1;
1104
+ return {
1105
+ paint: paint2,
1106
+ width,
1107
+ depth: b.depth * (smooth ? width : size / 2) * sign,
1108
+ pillow: b.style === "pillow-emboss",
1109
+ chiselSoft: b.technique === "chisel-soft" ? Math.max(size / 4, 1) : 0
1110
+ };
1111
+ }
1112
+ function bevelChiselH(paint2, size, din, dout, soft) {
1113
+ const ramp = size + 1;
1114
+ if (paint2 === "outer" && !soft) {
1115
+ const top = (size + 2) / ramp;
1116
+ return dout > 0 ? clamp((size + 1.5 - dout) / ramp, 0, top) : top;
1150
1117
  }
1151
- k = 0;
1152
- for (let q = 0; q < n; q++) {
1153
- while (z[k + 1] < q) k++;
1154
- const p = v[k];
1155
- const d = q - p;
1156
- out[q] = d * d + f[p];
1157
- near[q] = p;
1118
+ if (paint2 === "outer") return dout > 0 ? 1 - clamp012((dout + 0.5) / ramp) : (size + 2) / ramp;
1119
+ if (paint2 === "both") {
1120
+ const half = size / 2 + 0.5;
1121
+ return din > 0 ? 0.5 + 0.5 * clamp012(din / half) : 0.5 - 0.5 * clamp012(dout / half);
1158
1122
  }
1123
+ if (soft) return din > 0 ? clamp((din + 1.5) / ramp, 0, (size + 2) / ramp) : 0;
1124
+ return din > 0 ? clamp012((din + 0.5) / ramp) : 0;
1159
1125
  }
1160
- function edtNearest(inside, w, h) {
1161
- const total = w * h;
1162
- const n = Math.max(w, h);
1163
- const f = new Float64Array(n);
1164
- const o = new Float64Array(n);
1165
- const nr = new Int32Array(n);
1166
- const v = new Int32Array(n);
1167
- const z = new Float64Array(n + 1);
1168
- const gc = new Float64Array(total);
1169
- const nc = new Int32Array(total);
1170
- for (let x = 0; x < w; x++) {
1171
- for (let y = 0; y < h; y++) f[y] = inside[y * w + x] ? 0 : INF;
1172
- dt1(f, h, o, nr, v, z);
1173
- for (let y = 0; y < h; y++) {
1174
- gc[x * h + y] = o[y];
1175
- nc[x * h + y] = nr[y];
1176
- }
1126
+ function bevelHeight(shape, b, g, rect, anchor, ctx) {
1127
+ const size = Math.max(b.size, 1);
1128
+ let h;
1129
+ if (b.technique === "smooth") {
1130
+ h = { w: shape.w, h: shape.h, v: new Float32Array(shape.v) };
1131
+ tent(h, g.width);
1132
+ } else {
1133
+ const { din, dout } = edgeDistances(shape, size + 2);
1134
+ h = fmap(shape.w, shape.h);
1135
+ const soft = g.chiselSoft > 0;
1136
+ for (let i = 0; i < h.v.length; i++) h.v[i] = bevelChiselH(g.paint, size, din[i], dout[i], soft);
1137
+ if (soft && g.paint === "both") tent(h, g.chiselSoft);
1177
1138
  }
1178
- const d = new Float32Array(total);
1179
- const near = new Int32Array(total);
1180
- for (let y = 0; y < h; y++) {
1181
- for (let x = 0; x < w; x++) f[x] = gc[x * h + y];
1182
- dt1(f, w, o, nr, v, z);
1183
- for (let x = 0; x < w; x++) {
1184
- d[y * w + x] = Math.sqrt(o[x]);
1185
- const px = nr[x];
1186
- near[y * w + x] = nc[px * h + y] * w + px;
1139
+ if (b.contourElement) h = applyLut(h, _nullishCoalesce(contourLut(b.contourElement.contour), () => ( identityLut())));
1140
+ const t = b.texture;
1141
+ const tile = t ? ctx.pattern(t.patternId) : null;
1142
+ if (t && tile) {
1143
+ const unit = Math.abs(b.depth) > 1e-6 ? Math.max(Math.abs(g.depth / b.depth), 1e-3) : Math.max(g.width, 1);
1144
+ const place = new PatternPlacement(anchor, _nullishCoalesce(t.link, () => ( true)), _nullishCoalesce(t.phase, () => ( { x: 0, y: 0 })), t.scale, 0);
1145
+ const k = t.depth / unit;
1146
+ const uv = [0, 0];
1147
+ const p = [0, 0, 0, 0];
1148
+ for (let y = 0; y < h.h; y++) {
1149
+ for (let x = 0; x < h.w; x++) {
1150
+ place.map(rect.x + x + 0.5, rect.y + y + 0.5, uv);
1151
+ tile.sample(uv[0], uv[1], p);
1152
+ const l = (0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2]) * p[3];
1153
+ h.v[y * h.w + x] += k * (t.invert ? 1 - l : l);
1154
+ }
1187
1155
  }
1188
1156
  }
1189
- return { d, near };
1157
+ if (b.soften >= 1) tent(h, b.soften);
1158
+ return h;
1190
1159
  }
1191
- var S2 = Math.SQRT2;
1192
- var S5 = 2.236068;
1193
- var FWD = [
1194
- [-1, 0, 1],
1195
- [-1, -1, S2],
1196
- [0, -1, 1],
1197
- [1, -1, S2],
1198
- [-1, -2, S5],
1199
- [1, -2, S5],
1200
- [-2, -1, S5],
1201
- [2, -1, S5]
1202
- ];
1203
- function chamferFrom(d, w, h) {
1204
- const ox = FWD.map((f) => f[0]);
1205
- const oy = FWD.map((f) => f[1]);
1206
- const wt = FWD.map((f) => f[2]);
1207
- const k = FWD.length;
1208
- for (let pass = 0; pass < 2; pass++) {
1209
- const sign = pass === 0 ? 1 : -1;
1210
- for (let yy = 0; yy < h; yy++) {
1211
- const y = pass === 0 ? yy : h - 1 - yy;
1212
- for (let xx = 0; xx < w; xx++) {
1213
- const x = pass === 0 ? xx : w - 1 - xx;
1214
- const i = y * w + x;
1215
- let best = d[i];
1216
- for (let j = 0; j < k; j++) {
1217
- const nx = x + ox[j] * sign;
1218
- const ny = y + oy[j] * sign;
1219
- if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue;
1220
- const c = d[ny * w + nx] + wt[j];
1221
- if (c < best) best = c;
1222
- }
1223
- d[i] = best;
1160
+ var identity = null;
1161
+ function identityLut() {
1162
+ if (!identity) {
1163
+ identity = new Float32Array(4096);
1164
+ for (let k = 0; k < 4096; k++) identity[k] = k / 4095;
1165
+ }
1166
+ return identity;
1167
+ }
1168
+ function bevelMaps(shape, b, rect, anchor, ctx) {
1169
+ const g = bevelGeom(b);
1170
+ const hmap = bevelHeight(shape, b, g, rect, anchor, ctx);
1171
+ const angle = b.useGlobalLight ? ctx.light.angle : b.angle;
1172
+ const altitude = b.useGlobalLight ? ctx.light.altitude : b.altitude;
1173
+ const sa = Math.sin(angle * Math.PI / 180);
1174
+ const ca = Math.cos(angle * Math.PI / 180);
1175
+ const se = Math.sin(altitude * Math.PI / 180);
1176
+ const ce = Math.cos(altitude * Math.PI / 180);
1177
+ const lx = ca * ce;
1178
+ const ly = -sa * ce;
1179
+ const lz = se;
1180
+ const reachPast = g.paint === "both" || g.paint === "outer" && b.technique !== "smooth";
1181
+ const onBevel = (x, y) => mapGet(hmap, x, y) > BEVEL_H_EPS || reachPast && (mapGet(hmap, x + 1, y) > BEVEL_H_EPS || mapGet(hmap, x - 1, y) > BEVEL_H_EPS || mapGet(hmap, x, y + 1) > BEVEL_H_EPS || mapGet(hmap, x, y - 1) > BEVEL_H_EPS);
1182
+ const gloss = contourLut(b.glossContour);
1183
+ const shadeInto = (depth, outside) => {
1184
+ const hi2 = fmap(shape.w, shape.h);
1185
+ const sh2 = fmap(shape.w, shape.h);
1186
+ for (let y = 0; y < shape.h; y++) {
1187
+ for (let x = 0; x < shape.w; x++) {
1188
+ const i = y * shape.w + x;
1189
+ const gx = (mapGet(hmap, x + 1, y) - mapGet(hmap, x - 1, y)) * 0.5 * depth;
1190
+ const gy = (mapGet(hmap, x, y + 1) - mapGet(hmap, x, y - 1)) * 0.5 * depth;
1191
+ const len = Math.sqrt(gx * gx + gy * gy + 1);
1192
+ const shade = (-gx * lx - gy * ly + lz) / len;
1193
+ const region = outside ? shape.v[i] < 1 - INSIDE_EPS && onBevel(x, y) ? 1 : 0 : shape.v[i];
1194
+ const k = shade - se;
1195
+ if (k > 0) hi2.v[i] = clamp012(k / Math.max(1 - se, 1e-3)) * region;
1196
+ else sh2.v[i] = clamp012(-k / Math.max(se, 1e-3)) * region;
1224
1197
  }
1225
1198
  }
1199
+ return [applyLut(hi2, gloss), applyLut(sh2, gloss)];
1200
+ };
1201
+ if (g.paint !== "both") {
1202
+ const [hi2, sh2] = shadeInto(g.depth, g.paint === "outer");
1203
+ return { maps: [hi2, sh2], paint: g.paint };
1226
1204
  }
1227
- return d;
1228
- }
1229
- function distOutside(s, chamfer) {
1230
- const { w, h, v } = s;
1231
- const n = v.length;
1232
- const out = new Float32Array(n);
1233
- if (chamfer) {
1234
- const start = new Float32Array(n);
1235
- for (let i = 0; i < n; i++) start[i] = v[i] > INSIDE_EPS ? 1 - Math.min(v[i], 1) : INF;
1236
- const d2 = chamferFrom(start, w, h);
1237
- for (let i = 0; i < n; i++) out[i] = v[i] > INSIDE_EPS ? -0.5 : d2[i] - 0.5;
1205
+ const [hi, sh] = shadeInto(g.depth, false);
1206
+ const [ho, so] = shadeInto(g.pillow ? -g.depth : g.depth, true);
1207
+ const mix = (a, o) => {
1208
+ const out = fmap(a.w, a.h);
1209
+ for (let i = 0; i < out.v.length; i++) {
1210
+ const s = shape.v[i];
1211
+ out.v[i] = (s > INSIDE_EPS ? a.v[i] : 0) + o.v[i] * (1 - Math.min(s, 1));
1212
+ }
1238
1213
  return out;
1239
- }
1240
- const inside = new Uint8Array(n);
1241
- for (let i = 0; i < n; i++) inside[i] = v[i] > INSIDE_EPS ? 1 : 0;
1242
- const { d, near } = edtNearest(inside, w, h);
1243
- for (let i = 0; i < n; i++) out[i] = inside[i] ? -0.5 : d[i] - 0.5 + (1 - Math.min(v[near[i]], 1));
1244
- return out;
1214
+ };
1215
+ return { maps: [mix(hi, ho), mix(sh, so)], paint: "both" };
1245
1216
  }
1246
- function localCoverage(s) {
1247
- const out = { w: s.w, h: s.h, v: new Float32Array(s.v) };
1248
- for (let y = 0; y < s.h; y++) {
1249
- for (let x = 0; x < s.w; x++) {
1250
- const a = s.v[y * s.w + x];
1251
- if (a <= INSIDE_EPS) continue;
1252
- let mx = a;
1253
- for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) mx = Math.max(mx, mapGet(s, x + dx, y + dy));
1254
- out.v[y * s.w + x] = Math.min(a / mx, 1);
1255
- }
1256
- }
1257
- return out;
1217
+ function strokeWidths(s) {
1218
+ return s.position === "outside" ? [0, s.size] : s.position === "inside" ? [s.size, 0] : [s.size / 2, s.size / 2];
1258
1219
  }
1259
- function distInside(s, chamfer) {
1260
- const { w, h, v } = s;
1261
- const n = v.length;
1262
- const out = new Float32Array(n);
1263
- if (chamfer) {
1264
- const cov = localCoverage(s);
1265
- const start = new Float32Array(n);
1266
- for (let i = 0; i < n; i++) start[i] = v[i] <= INSIDE_EPS ? 0 : cov.v[i] < 1 - INSIDE_EPS ? cov.v[i] : INF;
1267
- const d2 = chamferFrom(start, w, h);
1268
- for (let i = 0; i < n; i++) out[i] = v[i] <= INSIDE_EPS ? -0.5 : d2[i] - 0.5;
1269
- return out;
1270
- }
1271
- const outside = new Uint8Array(n);
1272
- for (let i = 0; i < n; i++) outside[i] = v[i] <= INSIDE_EPS ? 1 : 0;
1273
- const { d } = edtNearest(outside, w, h);
1274
- for (let i = 0; i < n; i++) out[i] = outside[i] ? -0.5 : d[i] - 0.5;
1275
- return out;
1220
+ function activeEffectItems(effects) {
1221
+ if (!hasActiveEffects(effects)) return [];
1222
+ const s = effectsScale(effects);
1223
+ return effects.items.filter((e) => e.enabled).map((e) => scaleLayerEffect(e, s));
1276
1224
  }
1277
- function edgeDistances(s, reach) {
1278
- const { w, h, v } = s;
1279
- const n = v.length;
1280
- const edge = new Uint8Array(n);
1281
- const inside = new Uint8Array(n);
1282
- for (let y = 0; y < h; y++) {
1283
- for (let x = 0; x < w; x++) {
1284
- const i = y * w + x;
1285
- const a = v[i];
1286
- if (a <= INSIDE_EPS) continue;
1287
- inside[i] = 1;
1288
- if (a < 1 - INSIDE_EPS || mapGet(s, x - 1, y) <= INSIDE_EPS || mapGet(s, x + 1, y) <= INSIDE_EPS || mapGet(s, x, y - 1) <= INSIDE_EPS || mapGet(s, x, y + 1) <= INSIDE_EPS) edge[i] = 1;
1225
+ function effectsAreLocal(items) {
1226
+ const linked = (p) => p.link !== false;
1227
+ return items.every((e) => {
1228
+ switch (e.kind) {
1229
+ case "gradient-overlay":
1230
+ return !e.gradient.align;
1231
+ case "pattern-overlay":
1232
+ return !linked(e);
1233
+ case "stroke":
1234
+ return e.fill.type === "color" || e.fill.type === "pattern" && !linked(e.fill);
1235
+ case "drop-shadow":
1236
+ case "inner-shadow":
1237
+ case "outer-glow":
1238
+ case "inner-glow":
1239
+ return e.noise <= 0;
1240
+ case "bevel-emboss":
1241
+ return !e.texture || !linked(e.texture);
1242
+ default:
1243
+ return true;
1289
1244
  }
1290
- }
1291
- const { d, near } = edtNearest(edge, w, h);
1292
- const din = new Float32Array(n);
1293
- const dout = new Float32Array(n);
1294
- for (let y = 0; y < h; y++) {
1295
- for (let x = 0; x < w; x++) {
1296
- const i = y * w + x;
1297
- const q = near[i];
1298
- let sd;
1299
- if (d[i] > reach || d[i] >= INF / 2) {
1300
- sd = inside[i] ? -(d[i] + 0.5) : d[i] - 0.5;
1301
- } else {
1302
- const qx = q % w;
1303
- const qy = (q - qx) / w;
1304
- const g = (dx, dy) => mapGet(s, qx + dx, qy + dy);
1305
- let nx = -(g(1, -1) + 2 * g(1, 0) + g(1, 1) - g(-1, -1) - 2 * g(-1, 0) - g(-1, 1));
1306
- let ny = -(g(-1, 1) + 2 * g(0, 1) + g(1, 1) - g(-1, -1) - 2 * g(0, -1) - g(1, -1));
1307
- const len = Math.hypot(nx, ny);
1308
- if (len > 1e-6) {
1309
- nx /= len;
1310
- ny /= len;
1311
- } else if (d[i] > 0) {
1312
- nx = (x - qx) / d[i];
1313
- ny = (y - qy) / d[i];
1314
- } else {
1315
- nx = 1;
1316
- ny = 0;
1317
- }
1318
- sd = (x - qx) * nx + (y - qy) * ny - (Math.min(v[q], 1) - 0.5);
1245
+ });
1246
+ }
1247
+ function shapeBounds(shape, rect) {
1248
+ const { width: w, height: h } = rect;
1249
+ const rowHit = (y) => {
1250
+ for (let x = 0, i = y * w; x < w; x++, i++) if (shape[i] > INSIDE_EPS) return true;
1251
+ return false;
1252
+ };
1253
+ let y0 = 0;
1254
+ while (y0 < h && !rowHit(y0)) y0++;
1255
+ if (y0 === h) return null;
1256
+ let y1 = h - 1;
1257
+ while (!rowHit(y1)) y1--;
1258
+ let x0 = w;
1259
+ let x1 = -1;
1260
+ for (let y = y0; y <= y1; y++) {
1261
+ const o = y * w;
1262
+ for (let x = 0; x < x0; x++) {
1263
+ if (shape[o + x] > INSIDE_EPS) {
1264
+ x0 = x;
1265
+ break;
1266
+ }
1267
+ }
1268
+ for (let x = w - 1; x > x1; x--) {
1269
+ if (shape[o + x] > INSIDE_EPS) {
1270
+ x1 = x;
1271
+ break;
1319
1272
  }
1320
- din[i] = inside[i] ? Math.max(-sd, inside[i] && !edge[i] ? 0.5 : -0.5) : -0.5;
1321
- dout[i] = inside[i] && !edge[i] ? -0.5 : Math.max(sd, -0.5);
1322
1273
  }
1323
1274
  }
1324
- return { din, dout };
1325
- }
1326
- function dilate(s, r) {
1327
- if (!(r > 0)) return s;
1328
- const d = distOutside(s, true);
1329
- const out = { w: s.w, h: s.h, v: new Float32Array(s.v) };
1330
- for (let i = 0; i < d.length; i++) {
1331
- const o = out.v[i];
1332
- out.v[i] = d[i] < 0 ? Math.min(o + r, 1) : Math.max(o, clamp012(r + 0.5 - d[i]));
1333
- }
1334
- return out;
1335
- }
1336
- function boxWidth(w) {
1337
- return Number.isNaN(w) ? 1 : clamp(w, 1, MAX_EFFECT_REACH);
1338
- }
1339
- function boxGeom(bw) {
1340
- bw = boxWidth(bw);
1341
- const half = bw / 2;
1342
- const r = Math.max(0, Math.ceil(half - 0.5));
1343
- const f = clamp012(half - (r - 0.5));
1344
- return [r, f, 1 / bw];
1345
- }
1346
- function boxLine(src, x0, dst, bw) {
1347
- const n = src.length;
1348
- const [r, f, norm] = boxGeom(bw);
1349
- const at = (i) => i >= 0 && i < n ? src[i] : 0;
1350
- if (r === 0) {
1351
- for (let k = 0; k < dst.length; k++) dst[k] = at(x0 + k);
1352
- return;
1353
- }
1354
- let inner = 0;
1355
- for (let i = x0 - (r - 1); i <= x0 + (r - 1); i++) inner += at(i);
1356
- for (let k = 0; k < dst.length; k++) {
1357
- const x = x0 + k;
1358
- dst[k] = (inner + f * (at(x - r) + at(x + r))) * norm;
1359
- inner += at(x + r) - at(x - r + 1);
1360
- }
1361
- }
1362
- var BLUR_EPS = 1e-7;
1363
- var BLUR_FIX = 2 ** 32;
1364
- function tentLine(src, dst, bw, mid) {
1365
- const [r] = boxGeom(bw);
1366
- const m = mid.subarray(0, src.length + 2 * r);
1367
- for (let i = 0; i < src.length; i++) src[i] = Math.round(src[i] * BLUR_FIX);
1368
- boxLine(src, -r, m, bw);
1369
- for (let i = 0; i < m.length; i++) m[i] = Math.round(m[i]);
1370
- boxLine(m, r, dst, bw);
1371
- for (let i = 0; i < dst.length; i++) {
1372
- const v = dst[i] / BLUR_FIX;
1373
- dst[i] = Math.abs(v) < BLUR_EPS ? 0 : v;
1374
- }
1275
+ return { x: rect.x + x0, y: rect.y + y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
1375
1276
  }
1376
- function tent(m, w) {
1377
- if (!Number.isFinite(w) || m.v.length === 0) return;
1378
- if (boxGeom(w)[0] === 0) return;
1379
- const { w: mw, h: mh } = m;
1380
- const r = boxGeom(w)[0];
1381
- const mid = new Float64Array(Math.max(mw, mh) + 2 * r);
1382
- const row = new Float64Array(mw);
1383
- const rowOut = new Float64Array(mw);
1384
- for (let y = 0; y < mh; y++) {
1385
- for (let x = 0; x < mw; x++) row[x] = m.v[y * mw + x];
1386
- tentLine(row, rowOut, w, mid);
1387
- for (let x = 0; x < mw; x++) m.v[y * mw + x] = rowOut[x];
1388
- }
1389
- const col = new Float64Array(mh);
1390
- const colOut = new Float64Array(mh);
1391
- for (let x = 0; x < mw; x++) {
1392
- for (let y = 0; y < mh; y++) col[y] = m.v[y * mw + x];
1393
- tentLine(col, colOut, w, mid);
1394
- for (let y = 0; y < mh; y++) m.v[y * mw + x] = colOut[y];
1395
- }
1396
- }
1397
- function blur(m, size) {
1398
- if (Number.isFinite(size)) tent(m, size);
1399
- }
1400
- var lutCache = /* @__PURE__ */ new WeakMap();
1401
- function contourLut(c) {
1402
- if (!c) return null;
1403
- const cached = lutCache.get(c);
1404
- if (cached !== void 0) return cached;
1405
- const pts = c.points;
1406
- const linear = pts.length === 2 && pts[0].input === 0 && pts[0].output === 0 && pts[1].input === 1 && pts[1].output === 1;
1407
- let lut = null;
1408
- if (pts.length >= 2 && !linear) {
1409
- if (!pts.some((p) => p.corner)) lut = curveLut(pts);
1410
- else {
1411
- const sorted = [...pts].sort((a, b) => a.input - b.input);
1412
- let start = 0;
1413
- for (let i = 1; i < sorted.length; i++) {
1414
- if (!(sorted[i].corner || i === sorted.length - 1)) continue;
1415
- const seg = sorted.slice(start, i + 1);
1416
- const from = seg[0].input;
1417
- const part = curveLut(seg);
1418
- if (!lut) lut = part;
1419
- else for (let k = 0; k < part.length; k++) if (k / (part.length - 1) >= from) lut[k] = part[k];
1420
- start = i;
1277
+ function buildEffectMaps(items, shape, rect, ctx) {
1278
+ const w = rect.width;
1279
+ const h = rect.height;
1280
+ const s = { w, h, v: shape };
1281
+ const bounds = shapeBounds(shape, rect);
1282
+ const anchor = bounds ? { x: bounds.x, y: bounds.y } : { x: rect.x, y: rect.y };
1283
+ const per = [];
1284
+ const bevelPaint = [];
1285
+ const frames = /* @__PURE__ */ new Map();
1286
+ let bytes = shape.byteLength;
1287
+ items.forEach((e, i) => {
1288
+ let maps = [];
1289
+ let paint2 = null;
1290
+ switch (e.kind) {
1291
+ case "drop-shadow":
1292
+ maps = [shadowMap(s, e, e.spread, ctx.light, false, rect.x, rect.y)];
1293
+ break;
1294
+ case "inner-shadow":
1295
+ maps = [shadowMap(s, e, e.choke, ctx.light, true, rect.x, rect.y)];
1296
+ break;
1297
+ case "outer-glow":
1298
+ case "inner-glow":
1299
+ maps = [glowMap(s, e, rect.x, rect.y)];
1300
+ break;
1301
+ case "satin":
1302
+ maps = [satinMap(s, e)];
1303
+ break;
1304
+ case "bevel-emboss": {
1305
+ const r = bevelMaps(s, e, rect, anchor, ctx);
1306
+ maps = r.maps;
1307
+ paint2 = r.paint;
1308
+ break;
1421
1309
  }
1422
- lut ??= curveLut(pts);
1310
+ case "stroke":
1311
+ if (e.fill.type === "gradient" && bounds) {
1312
+ const grow = Math.max(0, Math.ceil(Math.min(strokeWidths(e)[1], MAX_EFFECT_REACH)) - 1);
1313
+ frames.set(i, { x: bounds.x - grow, y: bounds.y - grow, width: bounds.width + 2 * grow, height: bounds.height + 2 * grow });
1314
+ }
1315
+ break;
1423
1316
  }
1424
- }
1425
- lutCache.set(c, lut);
1426
- return lut;
1427
- }
1428
- function lutAt(l, v) {
1429
- const x = clamp012(v) * (l.length - 1);
1430
- const i = Math.floor(x);
1431
- const j = Math.min(i + 1, l.length - 1);
1432
- return l[i] + (l[j] - l[i]) * (x - i);
1317
+ per.push(maps.map((m) => m.v));
1318
+ bevelPaint.push(paint2);
1319
+ for (const m of maps) bytes += m.v.byteLength;
1320
+ });
1321
+ const strokes = items.filter((e) => e.kind === "stroke");
1322
+ const outW = strokes.map((st) => strokeWidths(st)[1]).filter((x) => x > 0);
1323
+ const din = strokes.length ? distInside(s, true) : null;
1324
+ const dout = outW.some((x) => x < STROKE_CHAMFER_MAX) ? distOutside(s, true) : null;
1325
+ const doutExact = outW.some((x) => x >= STROKE_CHAMFER_MAX) ? distOutside(s, false) : null;
1326
+ for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
1327
+ return { rect, items, bounds, shape, per, bevelPaint, din, dout, doutExact, frames, bytes };
1433
1328
  }
1434
- function applyLut(m, l) {
1435
- return l ? mapped(m, (v) => lutAt(l, v)) : m;
1329
+ var rectArea = (r) => r.width * r.height;
1330
+ function clipRect(a, b) {
1331
+ const x0 = Math.max(a.x, b.x);
1332
+ const y0 = Math.max(a.y, b.y);
1333
+ const x1 = Math.min(a.x + a.width, b.x + b.width);
1334
+ const y1 = Math.min(a.y + a.height, b.y + b.height);
1335
+ return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
1436
1336
  }
1437
- function rangedLut(c, range) {
1438
- const base = contourLut(c);
1439
- const r = Number.isFinite(range) ? clamp(range, 0.01, 1) : 1;
1440
- if (r >= 0.999) return base;
1441
- const n = 4096;
1442
- const out = new Float32Array(n);
1443
- for (let k = 0; k < n; k++) {
1444
- const v = Math.min(k / (n - 1) / r, 1);
1445
- out[k] = base ? lutAt(base, v) : v;
1446
- }
1447
- return out;
1337
+ var growRect = (r, m) => ({ x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m });
1338
+ function unionRect(a, b) {
1339
+ const x0 = Math.min(a.x, b.x);
1340
+ const y0 = Math.min(a.y, b.y);
1341
+ return { x: x0, y: y0, width: Math.max(a.x + a.width, b.x + b.width) - x0, height: Math.max(a.y + a.height, b.y + b.height) - y0 };
1448
1342
  }
1449
- function satinLut(c) {
1450
- const lut = contourLut(c);
1451
- if (!lut) return null;
1452
- const end = lut[lut.length - 1];
1453
- const out = new Float32Array(lut.length);
1454
- for (let k = 0; k < lut.length; k++) out[k] = Math.abs(lut[lut.length - 1 - k] - end);
1455
- return out;
1343
+ function rectMinus(r, cut) {
1344
+ const i = clipRect(r, cut);
1345
+ if (!i) return [r];
1346
+ const parts = [
1347
+ { x: r.x, y: r.y, width: r.width, height: i.y - r.y },
1348
+ { x: r.x, y: i.y + i.height, width: r.width, height: r.y + r.height - (i.y + i.height) },
1349
+ { x: r.x, y: i.y, width: i.x - r.x, height: i.height },
1350
+ { x: i.x + i.width, y: i.y, width: r.x + r.width - (i.x + i.width), height: i.height }
1351
+ ];
1352
+ return parts.filter((p) => p.width > 0 && p.height > 0);
1456
1353
  }
1457
- function noise(m, amount, x0, y0) {
1458
- if (!Number.isFinite(amount) || amount <= 0) return;
1459
- for (let y = 0; y < m.h; y++) {
1460
- for (let x = 0; x < m.w; x++) {
1461
- const i = y * m.w + x;
1462
- if (m.v[i] <= BLUR_EPS) continue;
1463
- m.v[i] = clamp012(m.v[i] + (hashNoise(x0 + x, y0 + y) - 0.5) * 2 * amount);
1464
- }
1354
+ function pasteMap(dst, to, src, from, a) {
1355
+ for (let y = a.y; y < a.y + a.height; y++) {
1356
+ const s = (y - from.y) * from.width + (a.x - from.x);
1357
+ dst.set(src.subarray(s, s + a.width), (y - to.y) * to.width + (a.x - to.x));
1465
1358
  }
1466
1359
  }
1467
- function lightOffset(angle, distance) {
1468
- const a = angle * Math.PI / 180;
1469
- return [Math.round(-Math.cos(a) * distance), Math.round(Math.sin(a) * distance)];
1470
- }
1471
- function spreadSplit(size, spread) {
1472
- return [Math.round(size * spread), size * (1 - spread)];
1473
- }
1474
- function shadowMap(shape, s, spread, light, inner, ox, oy) {
1475
- const angle = s.useGlobalLight ? light.angle : s.angle;
1476
- const [dx, dy] = lightOffset(angle, s.distance);
1477
- const src = inner ? mapped(shape, (a) => 1 - a) : shape;
1478
- let m = shifted(src, dx, dy, inner ? 1 : 0);
1479
- const [r, bw] = spreadSplit(s.size, spread);
1480
- m = dilate(m, r);
1481
- blur(m, bw);
1482
- m = applyLut(m, contourLut(s.contour));
1483
- noise(m, s.noise, ox, oy);
1484
- if (inner) for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1485
- return m;
1486
- }
1487
- function glowMap(shape, g, ox, oy) {
1488
- const inner = g.kind === "inner-glow";
1489
- const spread = inner ? g.choke : g.spread;
1490
- const src = inner ? mapped(shape, (a) => 1 - a) : shape;
1491
- let m;
1492
- if (g.technique === "precise") {
1493
- const d = inner ? distInside(shape, false) : distOutside(src, false);
1494
- const solid = g.size * spread;
1495
- const soft = Math.max(g.size + 1 - solid, 1e-3);
1496
- m = fmap(shape.w, shape.h);
1497
- for (let i = 0; i < d.length; i++) {
1498
- const di = d[i] + 0.5;
1499
- m.v[i] = di <= solid ? 1 : 0.5 * clamp012(1 - (di - solid) / soft);
1360
+ function patchEffectMaps(prev, items, rect, changed, margin, shapeOver, ctx) {
1361
+ if (!effectsAreLocal(items) || rectArea(rect) <= 0) return null;
1362
+ let areas = [];
1363
+ for (const c of changed) {
1364
+ const a = clipRect(growRect(c, margin), rect);
1365
+ if (a) areas.push(a);
1366
+ }
1367
+ areas.push(...rectMinus(rect, prev.rect));
1368
+ for (let merged = true; merged; ) {
1369
+ merged = false;
1370
+ for (let i = 0; i < areas.length && !merged; i++) {
1371
+ for (let j = i + 1; j < areas.length; j++) {
1372
+ if (clipRect(growRect(areas[i], 2 * margin), areas[j])) {
1373
+ areas[i] = unionRect(areas[i], areas[j]);
1374
+ areas.splice(j, 1);
1375
+ merged = true;
1376
+ break;
1377
+ }
1378
+ }
1500
1379
  }
1501
- } else {
1502
- const [r, bw] = spreadSplit(g.size, spread);
1503
- m = dilate(src, r);
1504
- if (m === src || m === shape) m = { w: m.w, h: m.h, v: new Float32Array(m.v) };
1505
- blur(m, bw);
1506
1380
  }
1507
- m = applyLut(m, rangedLut(g.contour, g.range));
1508
- if (inner && g.source === "center") m = mapped(m, (v) => 1 - v);
1509
- noise(m, g.noise, ox, oy);
1510
- if (inner) for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1511
- return m;
1512
- }
1513
- function satinMap(shape, s) {
1514
- const [dx, dy] = lightOffset(s.angle, Math.max(1, s.distance));
1515
- const a = shifted(shape, dx, dy, 0);
1516
- const b = shifted(shape, -dx, -dy, 0);
1517
- tent(a, s.size);
1518
- tent(b, s.size);
1519
- let m = fmap(shape.w, shape.h);
1520
- for (let i = 0; i < m.v.length; i++) m.v[i] = Math.abs(a.v[i] - b.v[i]);
1521
- if (s.invert) m = mapped(m, (v) => 1 - v);
1522
- m = applyLut(m, satinLut(s.contour));
1523
- for (let i = 0; i < m.v.length; i++) m.v[i] *= shape.v[i];
1524
- return m;
1381
+ const windows = areas.map((a) => clipRect(growRect(a, margin), rect));
1382
+ if (windows.reduce((n, w) => n + rectArea(w), 0) > rectArea(rect) / 2) return null;
1383
+ const same = rect.x === prev.rect.x && rect.y === prev.rect.y && rect.width === prev.rect.width && rect.height === prev.rect.height;
1384
+ const take = (v) => same ? v : crop(v, prev.rect, rect, 0);
1385
+ const shape = take(prev.shape);
1386
+ const per = prev.per.map((maps) => maps.map(take));
1387
+ const din = prev.din && take(prev.din);
1388
+ const dout = prev.dout && take(prev.dout);
1389
+ const doutExact = prev.doutExact && take(prev.doutExact);
1390
+ areas.forEach((a, k) => {
1391
+ const w = windows[k];
1392
+ const part = buildEffectMaps(items, shapeOver(w), w, ctx);
1393
+ pasteMap(shape, rect, part.shape, w, a);
1394
+ per.forEach((maps, i) => maps.forEach((m, j) => pasteMap(m, rect, part.per[i][j], w, a)));
1395
+ if (din) pasteMap(din, rect, part.din, w, a);
1396
+ if (dout) pasteMap(dout, rect, part.dout, w, a);
1397
+ if (doutExact) pasteMap(doutExact, rect, part.doutExact, w, a);
1398
+ });
1399
+ let bytes = shape.byteLength;
1400
+ for (const maps of per) for (const m of maps) bytes += m.byteLength;
1401
+ for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
1402
+ return { rect, items, bounds: shapeBounds(shape, rect), shape, per, bevelPaint: prev.bevelPaint, din, dout, doutExact, frames: /* @__PURE__ */ new Map(), bytes };
1525
1403
  }
1526
- function bevelGeom(b) {
1527
- const size = Math.max(b.size, 1);
1528
- const emboss = b.style === "emboss" || b.style === "pillow-emboss";
1529
- const paint2 = b.style === "outer-bevel" ? "outer" : emboss ? "both" : "inner";
1530
- const width = emboss ? Math.ceil(size / 2) : size;
1531
- const smooth = b.technique === "smooth";
1532
- const sign = b.direction === "up" ? 1 : -1;
1533
- return {
1534
- paint: paint2,
1535
- width,
1536
- depth: b.depth * (smooth ? width : size / 2) * sign,
1537
- pillow: b.style === "pillow-emboss",
1538
- chiselSoft: b.technique === "chisel-soft" ? Math.max(size / 4, 1) : 0
1539
- };
1540
- }
1541
- function bevelChiselH(paint2, size, din, dout, soft) {
1542
- const ramp = size + 1;
1543
- if (paint2 === "outer" && !soft) {
1544
- const top = (size + 2) / ramp;
1545
- return dout > 0 ? clamp((size + 1.5 - dout) / ramp, 0, top) : top;
1404
+ var rgbScratchB = [0, 0, 0];
1405
+ var rgbScratchS = [0, 0, 0];
1406
+ var rgbScratchM = [0, 0, 0];
1407
+ function compositeAt(dst, i, mode, separable, sr, sg, sb, sa) {
1408
+ if (!(sa > 0)) return;
1409
+ const ab = dst[i + 3];
1410
+ const ao = sa + ab * (1 - sa);
1411
+ if (ao <= 0) {
1412
+ dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
1413
+ return;
1546
1414
  }
1547
- if (paint2 === "outer") return dout > 0 ? 1 - clamp012((dout + 0.5) / ramp) : (size + 2) / ramp;
1548
- if (paint2 === "both") {
1549
- const half = size / 2 + 0.5;
1550
- return din > 0 ? 0.5 + 0.5 * clamp012(din / half) : 0.5 - 0.5 * clamp012(dout / half);
1415
+ const b0 = dst[i];
1416
+ const b1 = dst[i + 1];
1417
+ const b2 = dst[i + 2];
1418
+ if (mode === "pigment") {
1419
+ rgbScratchB[0] = b0;
1420
+ rgbScratchB[1] = b1;
1421
+ rgbScratchB[2] = b2;
1422
+ rgbScratchS[0] = sr;
1423
+ rgbScratchS[1] = sg;
1424
+ rgbScratchS[2] = sb;
1425
+ _chunk7ISPWEJAcjs.mixPigmentRgb.call(void 0, rgbScratchB, rgbScratchS, sa / ao, rgbScratchM);
1426
+ dst[i] = rgbScratchM[0];
1427
+ dst[i + 1] = rgbScratchM[1];
1428
+ dst[i + 2] = rgbScratchM[2];
1429
+ dst[i + 3] = ao;
1430
+ return;
1551
1431
  }
1552
- if (soft) return din > 0 ? clamp((din + 1.5) / ramp, 0, (size + 2) / ramp) : 0;
1553
- return din > 0 ? clamp012((din + 0.5) / ramp) : 0;
1554
- }
1555
- function bevelHeight(shape, b, g, rect, anchor, ctx) {
1556
- const size = Math.max(b.size, 1);
1557
- let h;
1558
- if (b.technique === "smooth") {
1559
- h = { w: shape.w, h: shape.h, v: new Float32Array(shape.v) };
1560
- tent(h, g.width);
1432
+ let m0;
1433
+ let m1;
1434
+ let m2;
1435
+ if (mode === "normal") {
1436
+ m0 = sr;
1437
+ m1 = sg;
1438
+ m2 = sb;
1439
+ } else if (separable) {
1440
+ m0 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b0, sr);
1441
+ m1 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b1, sg);
1442
+ m2 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b2, sb);
1561
1443
  } else {
1562
- const { din, dout } = edgeDistances(shape, size + 2);
1563
- h = fmap(shape.w, shape.h);
1564
- const soft = g.chiselSoft > 0;
1565
- for (let i = 0; i < h.v.length; i++) h.v[i] = bevelChiselH(g.paint, size, din[i], dout[i], soft);
1566
- if (soft && g.paint === "both") tent(h, g.chiselSoft);
1567
- }
1568
- if (b.contourElement) h = applyLut(h, _nullishCoalesce(contourLut(b.contourElement.contour), () => ( identityLut())));
1569
- const t = b.texture;
1570
- const tile = t ? ctx.pattern(t.patternId) : null;
1571
- if (t && tile) {
1572
- const unit = Math.abs(b.depth) > 1e-6 ? Math.max(Math.abs(g.depth / b.depth), 1e-3) : Math.max(g.width, 1);
1573
- const place = new PatternPlacement(anchor, _nullishCoalesce(t.link, () => ( true)), _nullishCoalesce(t.phase, () => ( { x: 0, y: 0 })), t.scale, 0);
1574
- const k = t.depth / unit;
1575
- const uv = [0, 0];
1576
- const p = [0, 0, 0, 0];
1577
- for (let y = 0; y < h.h; y++) {
1578
- for (let x = 0; x < h.w; x++) {
1579
- place.map(rect.x + x + 0.5, rect.y + y + 0.5, uv);
1580
- tile.sample(uv[0], uv[1], p);
1581
- const l = (0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2]) * p[3];
1582
- h.v[y * h.w + x] += k * (t.invert ? 1 - l : l);
1583
- }
1584
- }
1444
+ rgbScratchB[0] = b0;
1445
+ rgbScratchB[1] = b1;
1446
+ rgbScratchB[2] = b2;
1447
+ rgbScratchS[0] = sr;
1448
+ rgbScratchS[1] = sg;
1449
+ rgbScratchS[2] = sb;
1450
+ const m = _chunk7ISPWEJAcjs.blendRgb.call(void 0, mode, rgbScratchB, rgbScratchS);
1451
+ m0 = m[0];
1452
+ m1 = m[1];
1453
+ m2 = m[2];
1585
1454
  }
1586
- if (b.soften >= 1) tent(h, b.soften);
1587
- return h;
1455
+ const wb = (1 - sa) * ab;
1456
+ const ws = (1 - ab) * sa;
1457
+ const wm = sa * ab;
1458
+ dst[i] = (wb * b0 + ws * sr + wm * m0) / ao;
1459
+ dst[i + 1] = (wb * b1 + ws * sg + wm * m1) / ao;
1460
+ dst[i + 2] = (wb * b2 + ws * sb + wm * m2) / ao;
1461
+ dst[i + 3] = ao;
1588
1462
  }
1589
- var identity = null;
1590
- function identityLut() {
1591
- if (!identity) {
1592
- identity = new Float32Array(4096);
1593
- for (let k = 0; k < 4096; k++) identity[k] = k / 4095;
1463
+ function paint(dst, m, color2, mode, opacity) {
1464
+ const sep = mode !== "normal" && _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, mode);
1465
+ const c = [0, 0, 0, 1];
1466
+ const n = m.length;
1467
+ for (let i = 0; i < n; i++) {
1468
+ const a = m[i] * opacity;
1469
+ if (!(a > 0)) continue;
1470
+ color2(i, c);
1471
+ compositeAt(dst, i * 4, mode, sep, c[0], c[1], c[2], c[3] * Math.min(a, 1));
1594
1472
  }
1595
- return identity;
1596
1473
  }
1597
- function bevelMaps(shape, b, rect, anchor, ctx) {
1598
- const g = bevelGeom(b);
1599
- const hmap = bevelHeight(shape, b, g, rect, anchor, ctx);
1600
- const angle = b.useGlobalLight ? ctx.light.angle : b.angle;
1601
- const altitude = b.useGlobalLight ? ctx.light.altitude : b.altitude;
1602
- const sa = Math.sin(angle * Math.PI / 180);
1603
- const ca = Math.cos(angle * Math.PI / 180);
1604
- const se = Math.sin(altitude * Math.PI / 180);
1605
- const ce = Math.cos(altitude * Math.PI / 180);
1606
- const lx = ca * ce;
1607
- const ly = -sa * ce;
1608
- const lz = se;
1609
- const reachPast = g.paint === "both" || g.paint === "outer" && b.technique !== "smooth";
1610
- const onBevel = (x, y) => mapGet(hmap, x, y) > BEVEL_H_EPS || reachPast && (mapGet(hmap, x + 1, y) > BEVEL_H_EPS || mapGet(hmap, x - 1, y) > BEVEL_H_EPS || mapGet(hmap, x, y + 1) > BEVEL_H_EPS || mapGet(hmap, x, y - 1) > BEVEL_H_EPS);
1611
- const gloss = contourLut(b.glossContour);
1612
- const shadeInto = (depth, outside) => {
1613
- const hi2 = fmap(shape.w, shape.h);
1614
- const sh2 = fmap(shape.w, shape.h);
1615
- for (let y = 0; y < shape.h; y++) {
1616
- for (let x = 0; x < shape.w; x++) {
1617
- const i = y * shape.w + x;
1618
- const gx = (mapGet(hmap, x + 1, y) - mapGet(hmap, x - 1, y)) * 0.5 * depth;
1619
- const gy = (mapGet(hmap, x, y + 1) - mapGet(hmap, x, y - 1)) * 0.5 * depth;
1620
- const len = Math.sqrt(gx * gx + gy * gy + 1);
1621
- const shade = (-gx * lx - gy * ly + lz) / len;
1622
- const region = outside ? shape.v[i] < 1 - INSIDE_EPS && onBevel(x, y) ? 1 : 0 : shape.v[i];
1623
- const k = shade - se;
1624
- if (k > 0) hi2.v[i] = clamp012(k / Math.max(1 - se, 1e-3)) * region;
1625
- else sh2.v[i] = clamp012(-k / Math.max(se, 1e-3)) * region;
1474
+ function rgbOf(hex) {
1475
+ return _nullishCoalesce(parseEffectColor(hex), () => ( [0, 0, 0]));
1476
+ }
1477
+ function paintColor(dst, m, hex, mode, opacity) {
1478
+ const [r, g, b] = rgbOf(hex);
1479
+ paint(
1480
+ dst,
1481
+ m,
1482
+ (_i, c) => {
1483
+ c[0] = r;
1484
+ c[1] = g;
1485
+ c[2] = b;
1486
+ c[3] = 1;
1487
+ },
1488
+ mode,
1489
+ opacity
1490
+ );
1491
+ }
1492
+ var PreparedGradient = class {
1493
+
1494
+
1495
+ constructor(g) {
1496
+ this.color = [...g.stops].sort((a, b) => a.position - b.position).map((s) => [s.position, ...rgbOf(s.color)]);
1497
+ this.alpha = [..._nullishCoalesce(g.opacityStops, () => ( []))].sort((a, b) => a.position - b.position).map((s) => [s.position, s.opacity]);
1498
+ }
1499
+ sample(t, out) {
1500
+ const c = this.color;
1501
+ if (!c.length) {
1502
+ out[0] = out[1] = out[2] = t;
1503
+ } else if (c.length === 1 || t <= c[0][0]) {
1504
+ out[0] = c[0][1];
1505
+ out[1] = c[0][2];
1506
+ out[2] = c[0][3];
1507
+ } else {
1508
+ let done = false;
1509
+ for (let k = 0; k < c.length - 1; k++) {
1510
+ const a2 = c[k];
1511
+ const b = c[k + 1];
1512
+ if (t <= b[0]) {
1513
+ const f = b[0] > a2[0] ? (t - a2[0]) / (b[0] - a2[0]) : 0;
1514
+ out[0] = a2[1] + (b[1] - a2[1]) * f;
1515
+ out[1] = a2[2] + (b[2] - a2[2]) * f;
1516
+ out[2] = a2[3] + (b[3] - a2[3]) * f;
1517
+ done = true;
1518
+ break;
1519
+ }
1520
+ }
1521
+ if (!done) {
1522
+ const l = c[c.length - 1];
1523
+ out[0] = l[1];
1524
+ out[1] = l[2];
1525
+ out[2] = l[3];
1626
1526
  }
1627
1527
  }
1628
- return [applyLut(hi2, gloss), applyLut(sh2, gloss)];
1629
- };
1630
- if (g.paint !== "both") {
1631
- const [hi2, sh2] = shadeInto(g.depth, g.paint === "outer");
1632
- return { maps: [hi2, sh2], paint: g.paint };
1633
- }
1634
- const [hi, sh] = shadeInto(g.depth, false);
1635
- const [ho, so] = shadeInto(g.pillow ? -g.depth : g.depth, true);
1636
- const mix = (a, o) => {
1637
- const out = fmap(a.w, a.h);
1638
- for (let i = 0; i < out.v.length; i++) {
1639
- const s = shape.v[i];
1640
- out.v[i] = (s > INSIDE_EPS ? a.v[i] : 0) + o.v[i] * (1 - Math.min(s, 1));
1528
+ const a = this.alpha;
1529
+ if (!a.length) out[3] = 1;
1530
+ else if (a.length === 1 || t <= a[0][0]) out[3] = a[0][1];
1531
+ else {
1532
+ out[3] = a[a.length - 1][1];
1533
+ for (let k = 0; k < a.length - 1; k++) {
1534
+ if (t <= a[k + 1][0]) {
1535
+ const f = a[k + 1][0] > a[k][0] ? (t - a[k][0]) / (a[k + 1][0] - a[k][0]) : 0;
1536
+ out[3] = a[k][1] + (a[k + 1][1] - a[k][1]) * f;
1537
+ break;
1538
+ }
1539
+ }
1641
1540
  }
1642
- return out;
1643
- };
1644
- return { maps: [mix(hi, ho), mix(sh, so)], paint: "both" };
1645
- }
1646
- function strokeWidths(s) {
1647
- return s.position === "outside" ? [0, s.size] : s.position === "inside" ? [s.size, 0] : [s.size / 2, s.size / 2];
1648
- }
1649
- function activeEffectItems(effects) {
1650
- if (!hasActiveEffects(effects)) return [];
1651
- const s = effectsScale(effects);
1652
- return effects.items.filter((e) => e.enabled).map((e) => scaleLayerEffect(e, s));
1541
+ }
1542
+ };
1543
+ function gradientUnits(angle, w, h) {
1544
+ const a = angle * Math.PI / 180;
1545
+ const s = Math.sin(a);
1546
+ const c = Math.cos(a);
1547
+ const len = Math.max(Math.sqrt((c * w) ** 2 + (s * h) ** 2), 1);
1548
+ const chord = Math.max(Math.min(w / Math.max(Math.abs(c), 1e-6), h / Math.max(Math.abs(s), 1e-6)), 1);
1549
+ return [chord, len];
1653
1550
  }
1654
- function effectsAreLocal(items) {
1655
- const linked = (p) => p.link !== false;
1656
- return items.every((e) => {
1657
- switch (e.kind) {
1658
- case "gradient-overlay":
1659
- return !e.gradient.align;
1660
- case "pattern-overlay":
1661
- return !linked(e);
1662
- case "stroke":
1663
- return e.fill.type === "color" || e.fill.type === "pattern" && !linked(e.fill);
1664
- case "drop-shadow":
1665
- case "inner-shadow":
1666
- case "outer-glow":
1667
- case "inner-glow":
1668
- return e.noise <= 0;
1669
- case "bevel-emboss":
1670
- return !e.texture || !linked(e.texture);
1671
- default:
1672
- return true;
1673
- }
1674
- });
1675
- }
1676
- function shapeBounds(shape, rect) {
1677
- const { width: w, height: h } = rect;
1678
- const rowHit = (y) => {
1679
- for (let x = 0, i = y * w; x < w; x++, i++) if (shape[i] > INSIDE_EPS) return true;
1680
- return false;
1681
- };
1682
- let y0 = 0;
1683
- while (y0 < h && !rowHit(y0)) y0++;
1684
- if (y0 === h) return null;
1685
- let y1 = h - 1;
1686
- while (!rowHit(y1)) y1--;
1687
- let x0 = w;
1688
- let x1 = -1;
1689
- for (let y = y0; y <= y1; y++) {
1690
- const o = y * w;
1691
- for (let x = 0; x < x0; x++) {
1692
- if (shape[o + x] > INSIDE_EPS) {
1693
- x0 = x;
1694
- break;
1695
- }
1696
- }
1697
- for (let x = w - 1; x > x1; x--) {
1698
- if (shape[o + x] > INSIDE_EPS) {
1699
- x1 = x;
1700
- break;
1701
- }
1551
+ function gradientT(style, angle, scale, reverse, offset, frame, x, y) {
1552
+ const w = Math.max(frame.width, 1);
1553
+ const h = Math.max(frame.height, 1);
1554
+ const cx = frame.x + w / 2 + offset.x * w;
1555
+ const cy = frame.y + h / 2 + offset.y * h;
1556
+ const a = angle * Math.PI / 180;
1557
+ const s = Math.sin(a);
1558
+ const c = Math.cos(a);
1559
+ const dx = x - cx;
1560
+ const dy = y - cy;
1561
+ const along = dx * c - dy * s;
1562
+ const across = dx * s + dy * c;
1563
+ let [chord, len] = gradientUnits(angle, w, h);
1564
+ chord *= Math.max(scale, 1e-3);
1565
+ len *= Math.max(scale, 1e-3);
1566
+ const corner = 0.5 * (c - s);
1567
+ let t;
1568
+ switch (style) {
1569
+ case "linear":
1570
+ t = (along - corner) / chord + 0.5;
1571
+ break;
1572
+ case "reflected":
1573
+ t = Math.abs((along - corner) / (chord / 2));
1574
+ break;
1575
+ case "radial":
1576
+ t = Math.sqrt(dx * dx + dy * dy) / (len / 2);
1577
+ break;
1578
+ case "diamond":
1579
+ t = (Math.abs(along) + Math.abs(across)) / (len / 2);
1580
+ break;
1581
+ case "angle": {
1582
+ const turn = (a - Math.atan2(-dy, dx)) / (2 * Math.PI);
1583
+ t = turn - Math.floor(turn);
1584
+ break;
1702
1585
  }
1703
1586
  }
1704
- return { x: rect.x + x0, y: rect.y + y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
1705
- }
1706
- function buildEffectMaps(items, shape, rect, ctx) {
1707
- const w = rect.width;
1708
- const h = rect.height;
1709
- const s = { w, h, v: shape };
1710
- const bounds = shapeBounds(shape, rect);
1711
- const anchor = bounds ? { x: bounds.x, y: bounds.y } : { x: rect.x, y: rect.y };
1712
- const per = [];
1713
- const bevelPaint = [];
1714
- const frames = /* @__PURE__ */ new Map();
1715
- let bytes = shape.byteLength;
1716
- items.forEach((e, i) => {
1717
- let maps = [];
1718
- let paint2 = null;
1719
- switch (e.kind) {
1720
- case "drop-shadow":
1721
- maps = [shadowMap(s, e, e.spread, ctx.light, false, rect.x, rect.y)];
1722
- break;
1723
- case "inner-shadow":
1724
- maps = [shadowMap(s, e, e.choke, ctx.light, true, rect.x, rect.y)];
1725
- break;
1726
- case "outer-glow":
1727
- case "inner-glow":
1728
- maps = [glowMap(s, e, rect.x, rect.y)];
1729
- break;
1730
- case "satin":
1731
- maps = [satinMap(s, e)];
1732
- break;
1733
- case "bevel-emboss": {
1734
- const r = bevelMaps(s, e, rect, anchor, ctx);
1735
- maps = r.maps;
1736
- paint2 = r.paint;
1737
- break;
1738
- }
1739
- case "stroke":
1740
- if (e.fill.type === "gradient" && bounds) {
1741
- const grow = Math.max(0, Math.ceil(Math.min(strokeWidths(e)[1], MAX_EFFECT_REACH)) - 1);
1742
- frames.set(i, { x: bounds.x - grow, y: bounds.y - grow, width: bounds.width + 2 * grow, height: bounds.height + 2 * grow });
1743
- }
1744
- break;
1745
- }
1746
- per.push(maps.map((m) => m.v));
1747
- bevelPaint.push(paint2);
1748
- for (const m of maps) bytes += m.v.byteLength;
1749
- });
1750
- const strokes = items.filter((e) => e.kind === "stroke");
1751
- const outW = strokes.map((st) => strokeWidths(st)[1]).filter((x) => x > 0);
1752
- const din = strokes.length ? distInside(s, true) : null;
1753
- const dout = outW.some((x) => x < STROKE_CHAMFER_MAX) ? distOutside(s, true) : null;
1754
- const doutExact = outW.some((x) => x >= STROKE_CHAMFER_MAX) ? distOutside(s, false) : null;
1755
- for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
1756
- return { rect, items, bounds, shape, per, bevelPaint, din, dout, doutExact, frames, bytes };
1587
+ t = clamp012(t);
1588
+ return reverse ? 1 - t : t;
1757
1589
  }
1758
- var rectArea = (r) => r.width * r.height;
1759
- function clipRect(a, b) {
1760
- const x0 = Math.max(a.x, b.x);
1761
- const y0 = Math.max(a.y, b.y);
1762
- const x1 = Math.min(a.x + a.width, b.x + b.width);
1763
- const y1 = Math.min(a.y + a.height, b.y + b.height);
1764
- return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
1590
+ function gradientLayout(style, angle, scale, offset, frame) {
1591
+ const unchanged = [angle, scale, offset];
1592
+ if (style !== "linear" && style !== "reflected" || ![angle, scale, offset.x, offset.y].every(Number.isFinite)) return unchanged;
1593
+ const w = Math.max(frame.width, 1);
1594
+ const h = Math.max(frame.height, 1);
1595
+ const cx = frame.x + w / 2 + offset.x * w;
1596
+ const cy = frame.y + h / 2 + offset.y * h;
1597
+ const chordOf = (r) => Math.max(Math.min(w / Math.max(Math.abs(Math.cos(r)), 1e-6), h / Math.max(Math.abs(Math.sin(r)), 1e-6)), 1);
1598
+ const a = angle * Math.PI / 180;
1599
+ const half = chordOf(a) * Math.max(scale, 1e-3) / 2;
1600
+ const dx = Math.cos(a) * half;
1601
+ const dy = -Math.sin(a) * half;
1602
+ const snap2 = (v2) => Math.floor(v2 + 1e-4);
1603
+ const end = [snap2(cx + dx), snap2(cy + dy)];
1604
+ let start;
1605
+ let mid;
1606
+ if (style === "reflected") {
1607
+ start = [cx, cy];
1608
+ mid = [cx, cy];
1609
+ } else {
1610
+ start = [snap2(cx - dx), snap2(cy - dy)];
1611
+ mid = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
1612
+ }
1613
+ const v = [end[0] - start[0], end[1] - start[1]];
1614
+ const len = Math.hypot(v[0], v[1]);
1615
+ if (len < 0.5) return unchanged;
1616
+ const a2 = Math.atan2(-v[1], v[0]);
1617
+ const span = style === "reflected" ? 2 * len : len;
1618
+ return [a2 * 180 / Math.PI, span / chordOf(a2), { x: offset.x + (mid[0] - cx) / w, y: offset.y + (mid[1] - cy) / h }];
1765
1619
  }
1766
- var growRect = (r, m) => ({ x: r.x - m, y: r.y - m, width: r.width + 2 * m, height: r.height + 2 * m });
1767
- function unionRect(a, b) {
1768
- const x0 = Math.min(a.x, b.x);
1769
- const y0 = Math.min(a.y, b.y);
1770
- return { x: x0, y: y0, width: Math.max(a.x + a.width, b.x + b.width) - x0, height: Math.max(a.y + a.height, b.y + b.height) - y0 };
1620
+ function paintGradient(dst, m, g, frame, env, mode, opacity) {
1621
+ const prepared = new PreparedGradient(g);
1622
+ const [angle, scale, offset] = gradientLayout(g.style, g.angle, g.scale, g.offset, frame);
1623
+ const { x: rx, y: ry, width: w } = env.rect;
1624
+ paint(dst, m, (i, c) => prepared.sample(gradientT(g.style, angle, scale, g.reverse, offset, frame, rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5), c), mode, opacity);
1771
1625
  }
1772
- function rectMinus(r, cut) {
1773
- const i = clipRect(r, cut);
1774
- if (!i) return [r];
1775
- const parts = [
1776
- { x: r.x, y: r.y, width: r.width, height: i.y - r.y },
1777
- { x: r.x, y: i.y + i.height, width: r.width, height: r.y + r.height - (i.y + i.height) },
1778
- { x: r.x, y: i.y, width: i.x - r.x, height: i.height },
1779
- { x: i.x + i.width, y: i.y, width: r.x + r.width - (i.x + i.width), height: i.height }
1780
- ];
1781
- return parts.filter((p) => p.width > 0 && p.height > 0);
1626
+ function paintPattern(dst, m, p, env, mode, opacity) {
1627
+ const tile = env.ctx.pattern(p.patternId);
1628
+ if (!tile) return;
1629
+ const place = new PatternPlacement(env.anchor, _nullishCoalesce(p.link, () => ( true)), _nullishCoalesce(p.phase, () => ( { x: 0, y: 0 })), p.scale, _nullishCoalesce(p.angle, () => ( 0)));
1630
+ const { x: rx, y: ry, width: w } = env.rect;
1631
+ const uv = [0, 0];
1632
+ paint(
1633
+ dst,
1634
+ m,
1635
+ (i, c) => {
1636
+ place.map(rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5, uv);
1637
+ tile.sample(uv[0], uv[1], c);
1638
+ },
1639
+ mode,
1640
+ opacity
1641
+ );
1782
1642
  }
1783
- function pasteMap(dst, to, src, from, a) {
1784
- for (let y = a.y; y < a.y + a.height; y++) {
1785
- const s = (y - from.y) * from.width + (a.x - from.x);
1786
- dst.set(src.subarray(s, s + a.width), (y - to.y) * to.width + (a.x - to.x));
1787
- }
1643
+ function paintFill(dst, m, f, frame, env, mode, opacity) {
1644
+ if (f.type === "color") paintColor(dst, m, f.color, mode, opacity);
1645
+ else if (f.type === "gradient") paintGradient(dst, m, f.gradient, f.gradient.align ? frame : env.canvas, env, mode, opacity);
1646
+ else paintPattern(dst, m, f, env, mode, opacity);
1788
1647
  }
1789
- function patchEffectMaps(prev, items, rect, changed, margin, shapeOver, ctx) {
1790
- if (!effectsAreLocal(items) || rectArea(rect) <= 0) return null;
1791
- let areas = [];
1792
- for (const c of changed) {
1793
- const a = clipRect(growRect(c, margin), rect);
1794
- if (a) areas.push(a);
1648
+ function effectFillColors(fill2, rect, frame, canvas, anchor, ctx) {
1649
+ const n = rect.width * rect.height;
1650
+ const out = new Float32Array(n * 4);
1651
+ const c = [0, 0, 0, 1];
1652
+ const { x: rx, y: ry, width: w } = rect;
1653
+ if (fill2.type === "color") {
1654
+ const [r, g, b] = rgbOf(fill2.color);
1655
+ for (let i = 0; i < n * 4; i += 4) {
1656
+ out[i] = r;
1657
+ out[i + 1] = g;
1658
+ out[i + 2] = b;
1659
+ out[i + 3] = 1;
1660
+ }
1661
+ return out;
1795
1662
  }
1796
- areas.push(...rectMinus(rect, prev.rect));
1797
- for (let merged = true; merged; ) {
1798
- merged = false;
1799
- for (let i = 0; i < areas.length && !merged; i++) {
1800
- for (let j = i + 1; j < areas.length; j++) {
1801
- if (clipRect(growRect(areas[i], 2 * margin), areas[j])) {
1802
- areas[i] = unionRect(areas[i], areas[j]);
1803
- areas.splice(j, 1);
1804
- merged = true;
1805
- break;
1806
- }
1807
- }
1663
+ if (fill2.type === "gradient") {
1664
+ const gr = fill2.gradient;
1665
+ const f = gr.align ? frame : canvas;
1666
+ const prepared = new PreparedGradient(gr);
1667
+ const [angle, scale, offset] = gradientLayout(gr.style, gr.angle, gr.scale, gr.offset, f);
1668
+ for (let i = 0; i < n; i++) {
1669
+ prepared.sample(gradientT(gr.style, angle, scale, gr.reverse, offset, f, rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5), c);
1670
+ out.set(c, i * 4);
1808
1671
  }
1672
+ return out;
1809
1673
  }
1810
- const windows = areas.map((a) => clipRect(growRect(a, margin), rect));
1811
- if (windows.reduce((n, w) => n + rectArea(w), 0) > rectArea(rect) / 2) return null;
1812
- const same = rect.x === prev.rect.x && rect.y === prev.rect.y && rect.width === prev.rect.width && rect.height === prev.rect.height;
1813
- const take = (v) => same ? v : crop(v, prev.rect, rect, 0);
1814
- const shape = take(prev.shape);
1815
- const per = prev.per.map((maps) => maps.map(take));
1816
- const din = prev.din && take(prev.din);
1817
- const dout = prev.dout && take(prev.dout);
1818
- const doutExact = prev.doutExact && take(prev.doutExact);
1819
- areas.forEach((a, k) => {
1820
- const w = windows[k];
1821
- const part = buildEffectMaps(items, shapeOver(w), w, ctx);
1822
- pasteMap(shape, rect, part.shape, w, a);
1823
- per.forEach((maps, i) => maps.forEach((m, j) => pasteMap(m, rect, part.per[i][j], w, a)));
1824
- if (din) pasteMap(din, rect, part.din, w, a);
1825
- if (dout) pasteMap(dout, rect, part.dout, w, a);
1826
- if (doutExact) pasteMap(doutExact, rect, part.doutExact, w, a);
1827
- });
1828
- let bytes = shape.byteLength;
1829
- for (const maps of per) for (const m of maps) bytes += m.byteLength;
1830
- for (const d of [din, dout, doutExact]) if (d) bytes += d.byteLength;
1831
- return { rect, items, bounds: shapeBounds(shape, rect), shape, per, bevelPaint: prev.bevelPaint, din, dout, doutExact, frames: /* @__PURE__ */ new Map(), bytes };
1674
+ const tile = ctx.pattern(fill2.patternId);
1675
+ if (!tile) return out;
1676
+ const place = new PatternPlacement(anchor, _nullishCoalesce(fill2.link, () => ( true)), _nullishCoalesce(fill2.phase, () => ( { x: 0, y: 0 })), fill2.scale, _nullishCoalesce(fill2.angle, () => ( 0)));
1677
+ const uv = [0, 0];
1678
+ for (let i = 0; i < n; i++) {
1679
+ place.map(rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5, uv);
1680
+ tile.sample(uv[0], uv[1], c);
1681
+ out.set(c, i * 4);
1682
+ }
1683
+ return out;
1832
1684
  }
1833
- var rgbScratchB = [0, 0, 0];
1834
- var rgbScratchS = [0, 0, 0];
1835
- var rgbScratchM = [0, 0, 0];
1836
- function compositeAt(dst, i, mode, separable, sr, sg, sb, sa) {
1837
- if (!(sa > 0)) return;
1838
- const ab = dst[i + 3];
1839
- const ao = sa + ab * (1 - sa);
1840
- if (ao <= 0) {
1841
- dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
1842
- return;
1685
+ function paintGlow(dst, m, g, env) {
1686
+ if (g.fill.type === "color") return paintColor(dst, m, g.fill.color, g.blend, g.opacity);
1687
+ const prepared = new PreparedGradient(g.fill.gradient);
1688
+ const r = Number.isFinite(g.range) ? clamp(g.range, 0.01, 1) : 1;
1689
+ const gain = 1 / (r * r);
1690
+ const strength = new Float32Array(m.length);
1691
+ for (let i = 0; i < m.length; i++) strength[i] = Math.min(m[i] * gain, 1);
1692
+ paint(dst, strength, (i, c) => prepared.sample(1 - clamp012(m[i]), c), g.blend, g.opacity);
1693
+ }
1694
+ function crop(v, from, to, fill2) {
1695
+ const out = new Float32Array(to.width * to.height);
1696
+ if (fill2) out.fill(fill2);
1697
+ const ix0 = Math.max(from.x, to.x);
1698
+ const iy0 = Math.max(from.y, to.y);
1699
+ const ix1 = Math.min(from.x + from.width, to.x + to.width);
1700
+ const iy1 = Math.min(from.y + from.height, to.y + to.height);
1701
+ if (ix1 <= ix0 || iy1 <= iy0) return out;
1702
+ const n = ix1 - ix0;
1703
+ for (let y = iy0; y < iy1; y++) {
1704
+ const s = (y - from.y) * from.width + (ix0 - from.x);
1705
+ out.set(v.subarray(s, s + n), (y - to.y) * to.width + (ix0 - to.x));
1843
1706
  }
1844
- const b0 = dst[i];
1845
- const b1 = dst[i + 1];
1846
- const b2 = dst[i + 2];
1847
- if (mode === "pigment") {
1848
- rgbScratchB[0] = b0;
1849
- rgbScratchB[1] = b1;
1850
- rgbScratchB[2] = b2;
1851
- rgbScratchS[0] = sr;
1852
- rgbScratchS[1] = sg;
1853
- rgbScratchS[2] = sb;
1854
- _chunk7ISPWEJAcjs.mixPigmentRgb.call(void 0, rgbScratchB, rgbScratchS, sa / ao, rgbScratchM);
1855
- dst[i] = rgbScratchM[0];
1856
- dst[i + 1] = rgbScratchM[1];
1857
- dst[i + 2] = rgbScratchM[2];
1858
- dst[i + 3] = ao;
1859
- return;
1707
+ return out;
1708
+ }
1709
+ function compositeLayerEffects(input) {
1710
+ const { backdrop, content, rect, maps, ctx } = input;
1711
+ const items = maps.items;
1712
+ const n = rect.width * rect.height;
1713
+ const cs = content instanceof Float32Array ? 1 : 1 / 255;
1714
+ const bs = backdrop instanceof Float32Array ? 1 : 1 / 255;
1715
+ const floatOut = backdrop instanceof Float32Array;
1716
+ const shape = new Float32Array(n);
1717
+ for (let i = 0; i < n; i++) shape[i] = content[i * 4 + 3] * cs;
1718
+ const before = new Float32Array(n * 4);
1719
+ for (let i = 0; i < n * 4; i++) before[i] = backdrop[i] * bs;
1720
+ const work = new Float32Array(before);
1721
+ const fx = (i, k) => crop(maps.per[i][k], maps.rect, rect, 0);
1722
+ const bounds = _nullishCoalesce(maps.bounds, () => ( rect));
1723
+ const env = { rect, bounds, canvas: input.canvas, anchor: { x: bounds.x, y: bounds.y }, ctx };
1724
+ const fill2 = clamp012(input.fillOpacity);
1725
+ const inside = (a) => a > INSIDE_EPS;
1726
+ const rev = [];
1727
+ for (let i = items.length - 1; i >= 0; i--) rev.push(i);
1728
+ const knockOut = (m, fillOpacity) => {
1729
+ const seeThrough = 1 - clamp012(fillOpacity);
1730
+ for (let i = 0; i < n; i++) m[i] *= 1 - shape[i] * seeThrough;
1731
+ };
1732
+ const normalLike = input.blend === "normal";
1733
+ for (const i of rev) {
1734
+ const e = items[i];
1735
+ if (e.kind !== "drop-shadow") continue;
1736
+ const m = fx(i, 0);
1737
+ if (e.knocksOut) knockOut(m, normalLike ? fill2 : 0);
1738
+ paintColor(work, m, e.color, e.blend, e.opacity);
1860
1739
  }
1861
- let m0;
1862
- let m1;
1863
- let m2;
1864
- if (mode === "normal") {
1865
- m0 = sr;
1866
- m1 = sg;
1867
- m2 = sb;
1868
- } else if (separable) {
1869
- m0 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b0, sr);
1870
- m1 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b1, sg);
1871
- m2 = _chunk7ISPWEJAcjs.blendChannel.call(void 0, mode, b2, sb);
1872
- } else {
1873
- rgbScratchB[0] = b0;
1874
- rgbScratchB[1] = b1;
1875
- rgbScratchB[2] = b2;
1876
- rgbScratchS[0] = sr;
1877
- rgbScratchS[1] = sg;
1878
- rgbScratchS[2] = sb;
1879
- const m = _chunk7ISPWEJAcjs.blendRgb.call(void 0, mode, rgbScratchB, rgbScratchS);
1880
- m0 = m[0];
1881
- m1 = m[1];
1882
- m2 = m[2];
1740
+ for (const i of rev) {
1741
+ const e = items[i];
1742
+ if (e.kind !== "outer-glow") continue;
1743
+ const m = fx(i, 0);
1744
+ knockOut(m, fill2);
1745
+ paintGlow(work, m, e, env);
1883
1746
  }
1884
- const wb = (1 - sa) * ab;
1885
- const ws = (1 - ab) * sa;
1886
- const wm = sa * ab;
1887
- dst[i] = (wb * b0 + ws * sr + wm * m0) / ao;
1888
- dst[i + 1] = (wb * b1 + ws * sg + wm * m1) / ao;
1889
- dst[i + 2] = (wb * b2 + ws * sb + wm * m2) / ao;
1890
- dst[i + 3] = ao;
1891
- }
1892
- function paint(dst, m, color2, mode, opacity) {
1893
- const sep = mode !== "normal" && _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, mode);
1894
- const c = [0, 0, 0, 1];
1895
- const n = m.length;
1747
+ const lay = new Float32Array(n * 4);
1896
1748
  for (let i = 0; i < n; i++) {
1897
- const a = m[i] * opacity;
1898
- if (!(a > 0)) continue;
1899
- color2(i, c);
1900
- compositeAt(dst, i * 4, mode, sep, c[0], c[1], c[2], c[3] * Math.min(a, 1));
1749
+ lay[i * 4] = content[i * 4] * cs;
1750
+ lay[i * 4 + 1] = content[i * 4 + 1] * cs;
1751
+ lay[i * 4 + 2] = content[i * 4 + 2] * cs;
1752
+ lay[i * 4 + 3] = inside(shape[i]) ? fill2 : 0;
1753
+ }
1754
+ const premerge = !normalLike;
1755
+ if (premerge) {
1756
+ const sep2 = _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, input.blend);
1757
+ for (let i = 0; i < n; i++) {
1758
+ const p = i * 4;
1759
+ const sr = lay[p];
1760
+ const sg = lay[p + 1];
1761
+ const sb = lay[p + 2];
1762
+ const sa = lay[p + 3];
1763
+ lay[p] = work[p];
1764
+ lay[p + 1] = work[p + 1];
1765
+ lay[p + 2] = work[p + 2];
1766
+ lay[p + 3] = work[p + 3];
1767
+ compositeAt(lay, p, input.blend, sep2, sr, sg, sb, sa);
1768
+ }
1769
+ }
1770
+ const rel = (m) => {
1771
+ for (let i = 0; i < n; i++) m[i] = inside(shape[i]) ? Math.min(m[i] / shape[i], 1) : 0;
1772
+ return m;
1773
+ };
1774
+ const full = new Float32Array(n);
1775
+ for (let i = 0; i < n; i++) full[i] = inside(shape[i]) ? 1 : 0;
1776
+ for (const i of rev) {
1777
+ const e = items[i];
1778
+ if (e.kind === "pattern-overlay") paintPattern(lay, full, e, env, e.blend, e.opacity);
1779
+ }
1780
+ for (const i of rev) {
1781
+ const e = items[i];
1782
+ if (e.kind === "gradient-overlay") paintGradient(lay, full, e.gradient, e.gradient.align ? bounds : input.canvas, env, e.blend, e.opacity);
1783
+ }
1784
+ for (const i of rev) {
1785
+ const e = items[i];
1786
+ if (e.kind === "color-overlay") paintColor(lay, full, e.color, e.blend, e.opacity);
1787
+ }
1788
+ for (const i of rev) {
1789
+ const e = items[i];
1790
+ if (e.kind === "satin") paintColor(lay, rel(fx(i, 0)), e.color, e.blend, e.opacity);
1791
+ }
1792
+ for (const i of rev) {
1793
+ const e = items[i];
1794
+ if (e.kind === "inner-glow") paintGlow(lay, rel(fx(i, 0)), e, env);
1795
+ }
1796
+ for (const i of rev) {
1797
+ const e = items[i];
1798
+ if (e.kind === "inner-shadow") paintColor(lay, rel(fx(i, 0)), e.color, e.blend, e.opacity);
1799
+ }
1800
+ const strokeIdx = items.map((e, i) => e.kind === "stroke" ? i : -1).filter((i) => i >= 0);
1801
+ const din = strokeIdx.length && maps.din ? crop(maps.din, maps.rect, rect, 0) : null;
1802
+ const frameOf = (i) => _nullishCoalesce(maps.frames.get(i), () => ( bounds));
1803
+ for (let k = strokeIdx.length - 1; k >= 0; k--) {
1804
+ const st = items[strokeIdx[k]];
1805
+ const [inW] = strokeWidths(st);
1806
+ if (!(inW > 0) || !din) continue;
1807
+ const m = new Float32Array(n);
1808
+ for (let i = 0; i < n; i++) m[i] = inside(shape[i]) ? clamp012(inW + 0.5 - din[i]) : 0;
1809
+ paintFill(lay, m, st.fill, frameOf(strokeIdx[k]), env, st.blend, st.opacity);
1810
+ }
1811
+ for (const i of rev) {
1812
+ const e = items[i];
1813
+ if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "inner") continue;
1814
+ paintColor(lay, rel(fx(i, 0)), e.highlightColor, e.highlightBlend, e.highlightOpacity);
1815
+ paintColor(lay, rel(fx(i, 1)), e.shadowColor, e.shadowBlend, e.shadowOpacity);
1816
+ }
1817
+ for (let i = 0; i < n; i++) lay[i * 4 + 3] *= Math.min(shape[i], 1);
1818
+ const outside = strokeIdx.filter((i) => strokeWidths(items[i])[1] > 0);
1819
+ if (outside.length) {
1820
+ const dout = maps.dout ? crop(maps.dout, maps.rect, rect, FAR) : null;
1821
+ const doutExact = maps.doutExact ? crop(maps.doutExact, maps.rect, rect, FAR) : null;
1822
+ const base = new Float32Array(work);
1823
+ const acc = new Float32Array(n * 4);
1824
+ const cover = new Float32Array(n);
1825
+ for (const si of outside) {
1826
+ const st = items[si];
1827
+ const outW = strokeWidths(st)[1];
1828
+ const d = _nullishCoalesce((outW >= STROKE_CHAMFER_MAX ? doutExact : dout), () => ( new Float32Array(n).fill(FAR)));
1829
+ const share = new Float32Array(n);
1830
+ const ones = new Float32Array(n);
1831
+ for (let i = 0; i < n; i++) {
1832
+ const band = clamp012(outW + 0.5 - d[i]);
1833
+ let k;
1834
+ if (inside(shape[i])) {
1835
+ const c = clamp012(lay[i * 4 + 3]);
1836
+ k = c >= 1 ? 1 : clamp012((1 - clamp012(shape[i])) / (1 - c));
1837
+ } else k = band;
1838
+ share[i] = k * st.opacity * (1 - cover[i]);
1839
+ cover[i] += share[i];
1840
+ ones[i] = share[i] > 0 ? 1 : 0;
1841
+ }
1842
+ const blended = new Float32Array(base);
1843
+ paintFill(blended, ones, st.fill, frameOf(si), env, st.blend, 1);
1844
+ for (let i = 0; i < n; i++) {
1845
+ const s = share[i];
1846
+ if (!(s > 0)) continue;
1847
+ const p = i * 4;
1848
+ const ba = blended[p + 3];
1849
+ acc[p] += s * blended[p] * ba;
1850
+ acc[p + 1] += s * blended[p + 1] * ba;
1851
+ acc[p + 2] += s * blended[p + 2] * ba;
1852
+ acc[p + 3] += s * ba;
1853
+ }
1854
+ }
1855
+ for (let i = 0; i < n; i++) {
1856
+ const c = cover[i];
1857
+ if (c <= 0) continue;
1858
+ const p = i * 4;
1859
+ const k = 1 - Math.min(c, 1);
1860
+ const a = work[p + 3] * k + acc[p + 3];
1861
+ if (a > 0) {
1862
+ work[p] = (work[p] * work[p + 3] * k + acc[p]) / a;
1863
+ work[p + 1] = (work[p + 1] * work[p + 3] * k + acc[p + 1]) / a;
1864
+ work[p + 2] = (work[p + 2] * work[p + 3] * k + acc[p + 2]) / a;
1865
+ work[p + 3] = Math.min(a, 1);
1866
+ }
1867
+ }
1868
+ }
1869
+ for (const i of rev) {
1870
+ const e = items[i];
1871
+ if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "outer") continue;
1872
+ paintColor(work, fx(i, 0), e.highlightColor, e.highlightBlend, e.highlightOpacity);
1873
+ paintColor(work, fx(i, 1), e.shadowColor, e.shadowBlend, e.shadowOpacity);
1874
+ }
1875
+ const mode = premerge ? "normal" : input.blend;
1876
+ const sep = _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, mode);
1877
+ for (let i = 0; i < n; i++) {
1878
+ const p = i * 4;
1879
+ if (lay[p + 3] > 0) compositeAt(work, p, mode, sep, lay[p], lay[p + 1], lay[p + 2], lay[p + 3]);
1880
+ }
1881
+ for (const i of rev) {
1882
+ const e = items[i];
1883
+ if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "both") continue;
1884
+ paintColor(work, fx(i, 0), e.highlightColor, e.highlightBlend, e.highlightOpacity);
1885
+ paintColor(work, fx(i, 1), e.shadowColor, e.shadowBlend, e.shadowOpacity);
1886
+ }
1887
+ const op = clamp012(input.opacity);
1888
+ for (let i = 0; i < n; i++) {
1889
+ const p = i * 4;
1890
+ const aa = before[p + 3];
1891
+ const ba = work[p + 3];
1892
+ const alpha = aa + (ba - aa) * op;
1893
+ if (alpha <= 0) {
1894
+ backdrop[p] = backdrop[p + 1] = backdrop[p + 2] = backdrop[p + 3] = 0;
1895
+ continue;
1896
+ }
1897
+ if (floatOut) {
1898
+ for (let c = 0; c < 3; c++) backdrop[p + c] = (before[p + c] * aa + (work[p + c] * ba - before[p + c] * aa) * op) / alpha;
1899
+ backdrop[p + 3] = alpha;
1900
+ continue;
1901
+ }
1902
+ for (let c = 0; c < 3; c++) backdrop[p + c] = Math.round((before[p + c] * aa + (work[p + c] * ba - before[p + c] * aa) * op) / alpha * 255);
1903
+ backdrop[p + 3] = Math.round(alpha * 255);
1901
1904
  }
1902
1905
  }
1903
- function rgbOf(hex) {
1904
- return _nullishCoalesce(parseEffectColor(hex), () => ( [0, 0, 0]));
1905
- }
1906
- function paintColor(dst, m, hex, mode, opacity) {
1907
- const [r, g, b] = rgbOf(hex);
1908
- paint(
1909
- dst,
1910
- m,
1911
- (_i, c) => {
1912
- c[0] = r;
1913
- c[1] = g;
1914
- c[2] = b;
1915
- c[3] = 1;
1916
- },
1917
- mode,
1918
- opacity
1919
- );
1906
+ function renderLayerEffects(effects, layer, backdrop, canvas, ctx) {
1907
+ const items = activeEffectItems(effects);
1908
+ const n = layer.rect.width * layer.rect.height;
1909
+ const shape = new Float32Array(n);
1910
+ for (let i = 0; i < n; i++) shape[i] = layer.content[i * 4 + 3] / 255;
1911
+ const maps = buildEffectMaps(items, shape, layer.rect, ctx);
1912
+ compositeLayerEffects({
1913
+ backdrop,
1914
+ content: layer.content,
1915
+ rect: layer.rect,
1916
+ maps,
1917
+ blend: layer.blend,
1918
+ opacity: layer.opacity,
1919
+ fillOpacity: _nullishCoalesce(layer.fillOpacity, () => ( 1)),
1920
+ canvas,
1921
+ ctx
1922
+ });
1920
1923
  }
1921
- var PreparedGradient = class {
1924
+
1925
+ // src/raster/deep-compositor.ts
1926
+ var isGroup = (l) => l.type === "group";
1927
+ var DeepCompositor = class {
1928
+ constructor(base, profile, deep, depth) {
1929
+ this.base = base;
1930
+ this.profile = profile;
1931
+ this.deep = deep;
1932
+ this.depth = depth;
1933
+ this.linear = depth === 32;
1934
+ }
1922
1935
 
1923
1936
 
1924
- constructor(g) {
1925
- this.color = [...g.stops].sort((a, b) => a.position - b.position).map((s) => [s.position, ...rgbOf(s.color)]);
1926
- this.alpha = [..._nullishCoalesce(g.opacityStops, () => ( []))].sort((a, b) => a.position - b.position).map((s) => [s.position, s.opacity]);
1937
+
1938
+
1939
+
1940
+
1941
+ /** The composite of `layers` over `rect` as float RGBA in the working space (`rect.width × rect.height × 4`). */
1942
+ composite(layers, rect, sources) {
1943
+ this.sources = sources;
1944
+ const acc = new Float32Array(Math.max(0, rect.width * rect.height * 4));
1945
+ if (rect.width > 0 && rect.height > 0) this.runSteps(this.buildSteps(layers), acc, true, rect);
1946
+ return acc;
1927
1947
  }
1928
- sample(t, out) {
1929
- const c = this.color;
1930
- if (!c.length) {
1931
- out[0] = out[1] = out[2] = t;
1932
- } else if (c.length === 1 || t <= c[0][0]) {
1933
- out[0] = c[0][1];
1934
- out[1] = c[0][2];
1935
- out[2] = c[0][3];
1936
- } else {
1937
- let done = false;
1938
- for (let k = 0; k < c.length - 1; k++) {
1939
- const a2 = c[k];
1940
- const b = c[k + 1];
1941
- if (t <= b[0]) {
1942
- const f = b[0] > a2[0] ? (t - a2[0]) / (b[0] - a2[0]) : 0;
1943
- out[0] = a2[1] + (b[1] - a2[1]) * f;
1944
- out[1] = a2[2] + (b[2] - a2[2]) * f;
1945
- out[2] = a2[3] + (b[3] - a2[3]) * f;
1946
- done = true;
1947
- break;
1948
- }
1949
- }
1950
- if (!done) {
1951
- const l = c[c.length - 1];
1952
- out[0] = l[1];
1953
- out[1] = l[2];
1954
- out[2] = l[3];
1948
+ // --- Steps (as RasterCompositor.buildSteps) ------------------------------------
1949
+ isPixel(l) {
1950
+ return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _2 => _2.profile, 'access', _3 => _3.isPixelLike, 'optionalCall', _4 => _4(l)]), () => ( false)));
1951
+ }
1952
+ isFilter(l) {
1953
+ return _nullishCoalesce(_optionalChain([this, 'access', _5 => _5.profile, 'access', _6 => _6.isFilterLayer, 'optionalCall', _7 => _7(l)]), () => ( false));
1954
+ }
1955
+ buildSteps(layers) {
1956
+ const steps = [];
1957
+ for (const layer of layers) {
1958
+ const last = steps[steps.length - 1];
1959
+ if (layer.clipped && last && (last.kind === "content" || last.kind === "group")) {
1960
+ last.clipped.push(layer);
1961
+ continue;
1955
1962
  }
1963
+ if (this.isFilter(layer)) {
1964
+ if (last && last.kind === "adjust") last.layers.push(layer);
1965
+ else steps.push({ kind: "adjust", layers: [layer] });
1966
+ } else if (isGroup(layer)) steps.push({ kind: "group", layer, clipped: [], steps: this.buildSteps(_nullishCoalesce(layer.children, () => ( []))) });
1967
+ else steps.push({ kind: "content", layer, clipped: [] });
1956
1968
  }
1957
- const a = this.alpha;
1958
- if (!a.length) out[3] = 1;
1959
- else if (a.length === 1 || t <= a[0][0]) out[3] = a[0][1];
1960
- else {
1961
- out[3] = a[a.length - 1][1];
1962
- for (let k = 0; k < a.length - 1; k++) {
1963
- if (t <= a[k + 1][0]) {
1964
- const f = a[k + 1][0] > a[k][0] ? (t - a[k][0]) / (a[k + 1][0] - a[k][0]) : 0;
1965
- out[3] = a[k][1] + (a[k + 1][1] - a[k][1]) * f;
1966
- break;
1967
- }
1969
+ return steps;
1970
+ }
1971
+ runSteps(steps, acc, empty, r) {
1972
+ for (const s of steps) empty = this.runStep(s, acc, empty, r);
1973
+ return empty;
1974
+ }
1975
+ runStep(step, acc, empty, r) {
1976
+ if (step.kind === "adjust") {
1977
+ if (empty) return true;
1978
+ this.applyFilterRun(step.layers, acc, r);
1979
+ return false;
1980
+ }
1981
+ const layer = step.layer;
1982
+ if (!layer.visible) return empty;
1983
+ const clipped = step.clipped.filter((l) => l.visible);
1984
+ if (step.kind === "content" && this.deepEffects(layer)) return this.runEffects(layer, clipped, acc, r) ? false : empty;
1985
+ const coverage = this.renderedAlone(layer) ? null : this.base.maskCoverage(layer, r, this.sources);
1986
+ if (coverage && coverage.every((v) => v <= 0)) return empty;
1987
+ if (step.kind === "group" && !this.renderedAlone(layer)) {
1988
+ if (layer.blend === "pass-through" && !clipped.length) {
1989
+ if (layer.opacity >= 1 && !coverage) return this.runSteps(step.steps, acc, empty, r);
1990
+ const before = acc.slice();
1991
+ const stillEmpty = this.runSteps(step.steps, acc, empty, r);
1992
+ lerp(acc, before, layer.opacity, coverage);
1993
+ return empty && stillEmpty;
1968
1994
  }
1995
+ const buf2 = new Float32Array(acc.length);
1996
+ if (this.runSteps(step.steps, buf2, true, r)) return empty;
1997
+ this.applyClipped(clipped, buf2, r);
1998
+ const mode2 = layer.blend === "pass-through" ? "normal" : layer.blend;
1999
+ this.blend(acc, buf2, mode2, layer.opacity, coverage);
2000
+ return false;
2001
+ }
2002
+ const content = this.content(layer, r);
2003
+ if (!content) return empty;
2004
+ const alone = this.renderedAlone(layer);
2005
+ const fill2 = !alone && this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1;
2006
+ const mode = this.blendOf(layer);
2007
+ if (!clipped.length) {
2008
+ this.blend(acc, content, mode, layer.opacity * fill2, coverage);
2009
+ return false;
1969
2010
  }
2011
+ const buf = new Float32Array(acc.length);
2012
+ this.blend(buf, content, "normal", fill2, coverage);
2013
+ this.applyClipped(clipped, buf, r);
2014
+ this.blend(acc, buf, mode, layer.opacity, null);
2015
+ return false;
1970
2016
  }
1971
- };
1972
- function gradientUnits(angle, w, h) {
1973
- const a = angle * Math.PI / 180;
1974
- const s = Math.sin(a);
1975
- const c = Math.cos(a);
1976
- const len = Math.max(Math.sqrt((c * w) ** 2 + (s * h) ** 2), 1);
1977
- const chord = Math.max(Math.min(w / Math.max(Math.abs(c), 1e-6), h / Math.max(Math.abs(s), 1e-6)), 1);
1978
- return [chord, len];
1979
- }
1980
- function gradientT(style, angle, scale, reverse, offset, frame, x, y) {
1981
- const w = Math.max(frame.width, 1);
1982
- const h = Math.max(frame.height, 1);
1983
- const cx = frame.x + w / 2 + offset.x * w;
1984
- const cy = frame.y + h / 2 + offset.y * h;
1985
- const a = angle * Math.PI / 180;
1986
- const s = Math.sin(a);
1987
- const c = Math.cos(a);
1988
- const dx = x - cx;
1989
- const dy = y - cy;
1990
- const along = dx * c - dy * s;
1991
- const across = dx * s + dy * c;
1992
- let [chord, len] = gradientUnits(angle, w, h);
1993
- chord *= Math.max(scale, 1e-3);
1994
- len *= Math.max(scale, 1e-3);
1995
- const corner = 0.5 * (c - s);
1996
- let t;
1997
- switch (style) {
1998
- case "linear":
1999
- t = (along - corner) / chord + 0.5;
2000
- break;
2001
- case "reflected":
2002
- t = Math.abs((along - corner) / (chord / 2));
2003
- break;
2004
- case "radial":
2005
- t = Math.sqrt(dx * dx + dy * dy) / (len / 2);
2006
- break;
2007
- case "diamond":
2008
- t = (Math.abs(along) + Math.abs(across)) / (len / 2);
2009
- break;
2010
- case "angle": {
2011
- const turn = (a - Math.atan2(-dy, dx)) / (2 * Math.PI);
2012
- t = turn - Math.floor(turn);
2013
- break;
2017
+ /**
2018
+ * A pixel layer with effects onto `acc` over `r`: its deep content (filters, mask, clipped
2019
+ * layers) and the effects composited in float. Effect maps come from the 8-bit shape. At 32
2020
+ * bits the effects composite in sRGB-encoded values (their colours and blends are defined
2021
+ * there) and the result is decoded back. Returns whether anything was drawn.
2022
+ */
2023
+ runEffects(layer, clipped, acc, r) {
2024
+ const fx = this.base.effectsInput(layer, r, this.sources);
2025
+ if (!fx) return false;
2026
+ const a = fx.rect;
2027
+ const content = _nullishCoalesce(this.content(layer, a), () => ( new Float32Array(a.width * a.height * 4)));
2028
+ const coverage = this.base.maskCoverage(layer, a, this.sources);
2029
+ if (coverage) for (let i = 0; i < coverage.length; i++) content[i * 4 + 3] *= coverage[i];
2030
+ if (clipped.length) this.applyClipped(clipped, content, a);
2031
+ const sub = new Float32Array(a.width * a.height * 4);
2032
+ for (let y = 0; y < a.height; y++) {
2033
+ const s = ((a.y - r.y + y) * r.width + (a.x - r.x)) * 4;
2034
+ sub.set(acc.subarray(s, s + a.width * 4), y * a.width * 4);
2014
2035
  }
2036
+ if (this.linear) {
2037
+ encodeInPlace(sub);
2038
+ encodeInPlace(content);
2039
+ }
2040
+ compositeLayerEffects({ ...fx, backdrop: sub, content });
2041
+ if (this.linear) decodeInPlace(sub);
2042
+ 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);
2043
+ return true;
2015
2044
  }
2016
- t = clamp012(t);
2017
- return reverse ? 1 - t : t;
2018
- }
2019
- function gradientLayout(style, angle, scale, offset, frame) {
2020
- const unchanged = [angle, scale, offset];
2021
- if (style !== "linear" && style !== "reflected" || ![angle, scale, offset.x, offset.y].every(Number.isFinite)) return unchanged;
2022
- const w = Math.max(frame.width, 1);
2023
- const h = Math.max(frame.height, 1);
2024
- const cx = frame.x + w / 2 + offset.x * w;
2025
- const cy = frame.y + h / 2 + offset.y * h;
2026
- const chordOf = (r) => Math.max(Math.min(w / Math.max(Math.abs(Math.cos(r)), 1e-6), h / Math.max(Math.abs(Math.sin(r)), 1e-6)), 1);
2027
- const a = angle * Math.PI / 180;
2028
- const half = chordOf(a) * Math.max(scale, 1e-3) / 2;
2029
- const dx = Math.cos(a) * half;
2030
- const dy = -Math.sin(a) * half;
2031
- const snap2 = (v2) => Math.floor(v2 + 1e-4);
2032
- const end = [snap2(cx + dx), snap2(cy + dy)];
2033
- let start;
2034
- let mid;
2035
- if (style === "reflected") {
2036
- start = [cx, cy];
2037
- mid = [cx, cy];
2038
- } else {
2039
- start = [snap2(cx - dx), snap2(cy - dy)];
2040
- mid = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
2045
+ applyClipped(clipped, buf, r) {
2046
+ let run = [];
2047
+ const flush = () => {
2048
+ if (run.length) this.applyFilterRun(run, buf, r);
2049
+ run = [];
2050
+ };
2051
+ for (const c of clipped) {
2052
+ if (this.isFilter(c)) {
2053
+ run.push(c);
2054
+ continue;
2055
+ }
2056
+ flush();
2057
+ const alone = this.renderedAlone(c);
2058
+ const coverage = alone ? null : this.base.maskCoverage(c, r, this.sources);
2059
+ let src;
2060
+ if (isGroup(c) && !alone) {
2061
+ src = new Float32Array(buf.length);
2062
+ if (this.runSteps(this.buildSteps(_nullishCoalesce(c.children, () => ( []))), src, true, r)) continue;
2063
+ } else src = this.content(c, r);
2064
+ if (!src) continue;
2065
+ const fill2 = !alone && this.isPixel(c) ? _nullishCoalesce(c.fillOpacity, () => ( 1)) : 1;
2066
+ const keep = new Float32Array(buf.length >> 2);
2067
+ for (let i = 3, p = 0; i < buf.length; i += 4, p++) keep[p] = buf[i];
2068
+ this.blend(buf, src, c.blend === "pass-through" ? "normal" : this.blendOf(c), c.opacity * fill2, coverage);
2069
+ for (let i = 3, p = 0; i < buf.length; i += 4, p++) buf[i] = keep[p];
2070
+ }
2071
+ flush();
2041
2072
  }
2042
- const v = [end[0] - start[0], end[1] - start[1]];
2043
- const len = Math.hypot(v[0], v[1]);
2044
- if (len < 0.5) return unchanged;
2045
- const a2 = Math.atan2(-v[1], v[0]);
2046
- const span = style === "reflected" ? 2 * len : len;
2047
- return [a2 * 180 / Math.PI, span / chordOf(a2), { x: offset.x + (mid[0] - cx) / w, y: offset.y + (mid[1] - cy) / h }];
2048
- }
2049
- function paintGradient(dst, m, g, frame, env, mode, opacity) {
2050
- const prepared = new PreparedGradient(g);
2051
- const [angle, scale, offset] = gradientLayout(g.style, g.angle, g.scale, g.offset, frame);
2052
- const { x: rx, y: ry, width: w } = env.rect;
2053
- paint(dst, m, (i, c) => prepared.sample(gradientT(g.style, angle, scale, g.reverse, offset, frame, rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5), c), mode, opacity);
2054
- }
2055
- function paintPattern(dst, m, p, env, mode, opacity) {
2056
- const tile = env.ctx.pattern(p.patternId);
2057
- if (!tile) return;
2058
- const place = new PatternPlacement(env.anchor, _nullishCoalesce(p.link, () => ( true)), _nullishCoalesce(p.phase, () => ( { x: 0, y: 0 })), p.scale, _nullishCoalesce(p.angle, () => ( 0)));
2059
- const { x: rx, y: ry, width: w } = env.rect;
2060
- const uv = [0, 0];
2061
- paint(
2062
- dst,
2063
- m,
2064
- (i, c) => {
2065
- place.map(rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5, uv);
2066
- tile.sample(uv[0], uv[1], c);
2067
- },
2068
- mode,
2069
- opacity
2070
- );
2071
- }
2072
- function paintFill(dst, m, f, frame, env, mode, opacity) {
2073
- if (f.type === "color") paintColor(dst, m, f.color, mode, opacity);
2074
- else if (f.type === "gradient") paintGradient(dst, m, f.gradient, f.gradient.align ? frame : env.canvas, env, mode, opacity);
2075
- else paintPattern(dst, m, f, env, mode, opacity);
2076
- }
2077
- function effectFillColors(fill2, rect, frame, canvas, anchor, ctx) {
2078
- const n = rect.width * rect.height;
2079
- const out = new Float32Array(n * 4);
2080
- const c = [0, 0, 0, 1];
2081
- const { x: rx, y: ry, width: w } = rect;
2082
- if (fill2.type === "color") {
2083
- const [r, g, b] = rgbOf(fill2.color);
2084
- for (let i = 0; i < n * 4; i += 4) {
2085
- out[i] = r;
2086
- out[i + 1] = g;
2087
- out[i + 2] = b;
2088
- out[i + 3] = 1;
2073
+ applyFilterRun(layers, acc, r) {
2074
+ const visible = [];
2075
+ let masks;
2076
+ for (const node of layers) {
2077
+ if (!node.visible) continue;
2078
+ const cov = this.base.maskCoverage(node, r, this.sources);
2079
+ if (cov) {
2080
+ if (cov.every((v) => v <= 0)) continue;
2081
+ (masks ??= /* @__PURE__ */ new Map()).set(node.id, cov);
2082
+ }
2083
+ visible.push(node);
2084
+ }
2085
+ if (!visible.length) return;
2086
+ if (this.deep.applyFilterRunDeep) {
2087
+ if (this.linear) mapColour(acc, _chunk7ISPWEJAcjs.srgbEncode);
2088
+ this.deep.applyFilterRunDeep(visible, acc, r, masks, this.sources);
2089
+ if (this.linear) mapColour(acc, _chunk7ISPWEJAcjs.srgbDecode);
2090
+ return;
2091
+ }
2092
+ const bytes = this.to8(acc);
2093
+ _optionalChain([this, 'access', _8 => _8.profile, 'access', _9 => _9.applyFilterRun, 'optionalCall', _10 => _10(visible, bytes, r, masks, this.sources)]);
2094
+ acc.set(this.from8(bytes));
2095
+ }
2096
+ // --- Layer content ---------------------------------------------------------------
2097
+ /** Layers drawn by the 8-bit compositor alone (effects, pixel filters, content the editor draws). */
2098
+ /** A pixel(-like) layer with effects: composited in float through `compositeLayerEffects`. */
2099
+ deepEffects(layer) {
2100
+ return hasActiveEffects(layer.effects) && !this.isFilter(layer) && this.isPixel(layer) && !isGroup(layer);
2101
+ }
2102
+ renderedAlone(layer) {
2103
+ if (hasActiveEffects(layer.effects) && !this.isFilter(layer) && !this.deepEffects(layer)) return true;
2104
+ 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)]);
2105
+ return !isGroup(layer);
2106
+ }
2107
+ blendOf(layer) {
2108
+ return _nullishCoalesce(_optionalChain([this, 'access', _17 => _17.profile, 'access', _18 => _18.contentBlend, 'optionalCall', _19 => _19(layer)]), () => ( layer.blend));
2109
+ }
2110
+ /** A layer's float RGBA over `r` (straight alpha, working space), or `null` when it has none there. */
2111
+ content(layer, r) {
2112
+ if (this.renderedAlone(layer)) {
2113
+ const solo = { ...layer, blend: isGroup(layer) && layer.blend === "pass-through" ? "pass-through" : "normal", opacity: 1, clipped: false };
2114
+ const bytes = this.base.composite([solo], r, this.sources);
2115
+ return this.from8(bytes);
2116
+ }
2117
+ const surface = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
2118
+ if (!surface) return null;
2119
+ const ox = _nullishCoalesce(_optionalChain([layer, 'access', _20 => _20.offset, 'optionalAccess', _21 => _21.x]), () => ( 0));
2120
+ const oy = _nullishCoalesce(_optionalChain([layer, 'access', _22 => _22.offset, 'optionalAccess', _23 => _23.y]), () => ( 0));
2121
+ const filters = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([this, 'access', _24 => _24.deep, 'access', _25 => _25.pixelFiltersDeep, 'optionalCall', _26 => _26(layer)]), () => ( null)) : null;
2122
+ if (!filters) return this.samples(surface, { x: r.x - ox, y: r.y - oy, width: r.width, height: r.height });
2123
+ const m = filters.reach;
2124
+ const W = this.sources.width;
2125
+ const H = this.sources.height;
2126
+ const x0 = m ? Math.max(0, r.x - m) : r.x;
2127
+ const y0 = m ? Math.max(0, r.y - m) : r.y;
2128
+ const x1 = m ? Math.min(W, r.x + r.width + m) : r.x + r.width;
2129
+ const y1 = m ? Math.min(H, r.y + r.height + m) : r.y + r.height;
2130
+ if (x1 <= x0 || y1 <= y0) return new Float32Array(r.width * r.height * 4);
2131
+ const big = { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
2132
+ const data = this.samples(surface, { ...big, x: big.x - ox, y: big.y - oy });
2133
+ filters.apply(data, big.width, big.height, this.linear);
2134
+ if (big.x === r.x && big.y === r.y && big.width === r.width && big.height === r.height) return data;
2135
+ const out = new Float32Array(r.width * r.height * 4);
2136
+ for (let y = 0; y < r.height; y++) {
2137
+ const sy = r.y + y - big.y;
2138
+ if (sy < 0 || sy >= big.height) continue;
2139
+ for (let x = 0; x < r.width; x++) {
2140
+ const sx = r.x + x - big.x;
2141
+ if (sx < 0 || sx >= big.width) continue;
2142
+ const s = (sy * big.width + sx) * 4;
2143
+ const d = (y * r.width + x) * 4;
2144
+ out[d] = data[s];
2145
+ out[d + 1] = data[s + 1];
2146
+ out[d + 2] = data[s + 2];
2147
+ out[d + 3] = data[s + 3];
2148
+ }
2089
2149
  }
2090
2150
  return out;
2091
2151
  }
2092
- if (fill2.type === "gradient") {
2093
- const gr = fill2.gradient;
2094
- const f = gr.align ? frame : canvas;
2095
- const prepared = new PreparedGradient(gr);
2096
- const [angle, scale, offset] = gradientLayout(gr.style, gr.angle, gr.scale, gr.offset, f);
2097
- for (let i = 0; i < n; i++) {
2098
- prepared.sample(gradientT(gr.style, angle, scale, gr.reverse, offset, f, rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5), c);
2099
- out.set(c, i * 4);
2152
+ /** A surface's samples over `rect` (layer space) in the working space. */
2153
+ samples(surface, rect) {
2154
+ const samples = _chunk7ISPWEJAcjs.readDeepRegion.call(void 0, surface, rect, this.depth);
2155
+ if (samples instanceof Float32Array) return samples;
2156
+ const out = new Float32Array(samples.length);
2157
+ for (let i = 0; i < samples.length; i++) out[i] = samples[i] / 65535;
2158
+ return out;
2159
+ }
2160
+ /** 8-bit RGBA to the working space. */
2161
+ from8(bytes) {
2162
+ if (this.linear) return _chunk7ISPWEJAcjs.to32From8.call(void 0, bytes, 4);
2163
+ const out = new Float32Array(bytes.length);
2164
+ for (let i = 0; i < bytes.length; i++) out[i] = bytes[i] / 255;
2165
+ return out;
2166
+ }
2167
+ /** The working space to 8-bit RGBA. */
2168
+ to8(acc) {
2169
+ const out = new Uint8ClampedArray(acc.length);
2170
+ for (let i = 0; i < acc.length; i += 4) {
2171
+ for (let c = 0; c < 3; c++) out[i + c] = Math.round((this.linear ? _chunk7ISPWEJAcjs.srgbEncode.call(void 0, acc[i + c]) : acc[i + c]) * 255);
2172
+ out[i + 3] = Math.round(acc[i + 3] * 255);
2100
2173
  }
2101
2174
  return out;
2102
2175
  }
2103
- const tile = ctx.pattern(fill2.patternId);
2104
- if (!tile) return out;
2105
- const place = new PatternPlacement(anchor, _nullishCoalesce(fill2.link, () => ( true)), _nullishCoalesce(fill2.phase, () => ( { x: 0, y: 0 })), fill2.scale, _nullishCoalesce(fill2.angle, () => ( 0)));
2106
- const uv = [0, 0];
2107
- for (let i = 0; i < n; i++) {
2108
- place.map(rx + i % w + 0.5, ry + Math.floor(i / w) + 0.5, uv);
2109
- tile.sample(uv[0], uv[1], c);
2110
- out.set(c, i * 4);
2176
+ // --- Blending --------------------------------------------------------------------
2177
+ /** `src` over `dst` with `mode` at `alpha` × coverage (straight alpha, float), as `blendTile`. */
2178
+ blend(dst, src, mode, alpha, coverage) {
2179
+ if (!(alpha > 0)) return;
2180
+ const normal = mode === "normal";
2181
+ const pigment = mode === "pigment";
2182
+ const cb = [0, 0, 0];
2183
+ const cs = [0, 0, 0];
2184
+ const mix = [0, 0, 0];
2185
+ for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
2186
+ const sa = src[i + 3];
2187
+ if (!(sa > 0)) continue;
2188
+ const k = coverage ? alpha * coverage[p] : alpha;
2189
+ if (!(k > 0)) continue;
2190
+ const as = Math.min(1, sa * k);
2191
+ const ab = dst[i + 3];
2192
+ const ao = as + ab * (1 - as);
2193
+ if (ao <= 0) {
2194
+ dst[i] = dst[i + 1] = dst[i + 2] = dst[i + 3] = 0;
2195
+ continue;
2196
+ }
2197
+ if (normal && as >= 1) {
2198
+ dst[i] = src[i];
2199
+ dst[i + 1] = src[i + 1];
2200
+ dst[i + 2] = src[i + 2];
2201
+ dst[i + 3] = 1;
2202
+ continue;
2203
+ }
2204
+ for (let c = 0; c < 3; c++) {
2205
+ cb[c] = dst[i + c];
2206
+ cs[c] = src[i + c];
2207
+ }
2208
+ if (pigment) {
2209
+ if (this.linear) for (let c = 0; c < 3; c++) cb[c] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, cb[c]), cs[c] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, cs[c]);
2210
+ _chunk7ISPWEJAcjs.mixPigmentRgb.call(void 0, cb, cs, as / ao, mix);
2211
+ for (let c = 0; c < 3; c++) dst[i + c] = this.linear ? _chunk7ISPWEJAcjs.srgbDecode.call(void 0, mix[c]) : mix[c];
2212
+ dst[i + 3] = ao;
2213
+ continue;
2214
+ }
2215
+ const m = normal ? cs : _chunk7ISPWEJAcjs.blendRgb.call(void 0, mode, cb, cs);
2216
+ const wb = (1 - as) * ab;
2217
+ const ws = (1 - ab) * as;
2218
+ const wm = as * ab;
2219
+ for (let c = 0; c < 3; c++) dst[i + c] = (wb * cb[c] + ws * cs[c] + wm * m[c]) / ao;
2220
+ dst[i + 3] = ao;
2221
+ }
2222
+ }
2223
+ };
2224
+ function lerp(dst, before, alpha, coverage) {
2225
+ for (let i = 0, p = 0; i < dst.length; i += 4, p++) {
2226
+ const k = coverage ? alpha * coverage[p] : alpha;
2227
+ if (k >= 1) continue;
2228
+ for (let c = 0; c < 4; c++) dst[i + c] = before[i + c] + (dst[i + c] - before[i + c]) * k;
2111
2229
  }
2112
- return out;
2113
2230
  }
2114
- function paintGlow(dst, m, g, env) {
2115
- if (g.fill.type === "color") return paintColor(dst, m, g.fill.color, g.blend, g.opacity);
2116
- const prepared = new PreparedGradient(g.fill.gradient);
2117
- const r = Number.isFinite(g.range) ? clamp(g.range, 0.01, 1) : 1;
2118
- const gain = 1 / (r * r);
2119
- const strength = new Float32Array(m.length);
2120
- for (let i = 0; i < m.length; i++) strength[i] = Math.min(m[i] * gain, 1);
2121
- paint(dst, strength, (i, c) => prepared.sample(1 - clamp012(m[i]), c), g.blend, g.opacity);
2231
+ function mapColour(data, f) {
2232
+ for (let i = 0; i < data.length; i += 4) {
2233
+ data[i] = f(data[i]);
2234
+ data[i + 1] = f(data[i + 1]);
2235
+ data[i + 2] = f(data[i + 2]);
2236
+ }
2122
2237
  }
2123
- function crop(v, from, to, fill2) {
2124
- const out = new Float32Array(to.width * to.height);
2125
- if (fill2) out.fill(fill2);
2126
- const ix0 = Math.max(from.x, to.x);
2127
- const iy0 = Math.max(from.y, to.y);
2128
- const ix1 = Math.min(from.x + from.width, to.x + to.width);
2129
- const iy1 = Math.min(from.y + from.height, to.y + to.height);
2130
- if (ix1 <= ix0 || iy1 <= iy0) return out;
2131
- const n = ix1 - ix0;
2132
- for (let y = iy0; y < iy1; y++) {
2133
- const s = (y - from.y) * from.width + (ix0 - from.x);
2134
- out.set(v.subarray(s, s + n), (y - to.y) * to.width + (ix0 - to.x));
2238
+ function workingToSamples(data, depth) {
2239
+ if (depth === 32) return data;
2240
+ const out = new Uint16Array(data.length);
2241
+ for (let i = 0; i < data.length; i++) {
2242
+ const v = data[i];
2243
+ out[i] = v > 0 ? v < 1 ? Math.round(v * 65535) : 65535 : 0;
2135
2244
  }
2136
2245
  return out;
2137
2246
  }
2138
- function compositeLayerEffects(input) {
2139
- const { backdrop, content, rect, maps, ctx } = input;
2140
- const items = maps.items;
2141
- const n = rect.width * rect.height;
2142
- const shape = new Float32Array(n);
2143
- for (let i = 0; i < n; i++) shape[i] = content[i * 4 + 3] / 255;
2144
- const before = new Float32Array(n * 4);
2145
- for (let i = 0; i < n * 4; i++) before[i] = backdrop[i] / 255;
2146
- const work = new Float32Array(before);
2147
- const fx = (i, k) => crop(maps.per[i][k], maps.rect, rect, 0);
2148
- const bounds = _nullishCoalesce(maps.bounds, () => ( rect));
2149
- const env = { rect, bounds, canvas: input.canvas, anchor: { x: bounds.x, y: bounds.y }, ctx };
2150
- const fill2 = clamp012(input.fillOpacity);
2151
- const inside = (a) => a > INSIDE_EPS;
2152
- const rev = [];
2153
- for (let i = items.length - 1; i >= 0; i--) rev.push(i);
2154
- const knockOut = (m, fillOpacity) => {
2155
- const seeThrough = 1 - clamp012(fillOpacity);
2156
- for (let i = 0; i < n; i++) m[i] *= 1 - shape[i] * seeThrough;
2157
- };
2158
- const normalLike = input.blend === "normal";
2159
- for (const i of rev) {
2160
- const e = items[i];
2161
- if (e.kind !== "drop-shadow") continue;
2162
- const m = fx(i, 0);
2163
- if (e.knocksOut) knockOut(m, normalLike ? fill2 : 0);
2164
- paintColor(work, m, e.color, e.blend, e.opacity);
2165
- }
2166
- for (const i of rev) {
2167
- const e = items[i];
2168
- if (e.kind !== "outer-glow") continue;
2169
- const m = fx(i, 0);
2170
- knockOut(m, fill2);
2171
- paintGlow(work, m, e, env);
2172
- }
2173
- const lay = new Float32Array(n * 4);
2174
- for (let i = 0; i < n; i++) {
2175
- lay[i * 4] = content[i * 4] / 255;
2176
- lay[i * 4 + 1] = content[i * 4 + 1] / 255;
2177
- lay[i * 4 + 2] = content[i * 4 + 2] / 255;
2178
- lay[i * 4 + 3] = inside(shape[i]) ? fill2 : 0;
2247
+ function encodeInPlace(d) {
2248
+ for (let i = 0; i < d.length; i += 4) {
2249
+ d[i] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, d[i]);
2250
+ d[i + 1] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, d[i + 1]);
2251
+ d[i + 2] = _chunk7ISPWEJAcjs.srgbEncode.call(void 0, d[i + 2]);
2179
2252
  }
2180
- const premerge = !normalLike;
2181
- if (premerge) {
2182
- const sep2 = _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, input.blend);
2183
- for (let i = 0; i < n; i++) {
2184
- const p = i * 4;
2185
- const sr = lay[p];
2186
- const sg = lay[p + 1];
2187
- const sb = lay[p + 2];
2188
- const sa = lay[p + 3];
2189
- lay[p] = work[p];
2190
- lay[p + 1] = work[p + 1];
2191
- lay[p + 2] = work[p + 2];
2192
- lay[p + 3] = work[p + 3];
2193
- compositeAt(lay, p, input.blend, sep2, sr, sg, sb, sa);
2194
- }
2195
- }
2196
- const rel = (m) => {
2197
- for (let i = 0; i < n; i++) m[i] = inside(shape[i]) ? Math.min(m[i] / shape[i], 1) : 0;
2198
- return m;
2199
- };
2200
- const full = new Float32Array(n);
2201
- for (let i = 0; i < n; i++) full[i] = inside(shape[i]) ? 1 : 0;
2202
- for (const i of rev) {
2203
- const e = items[i];
2204
- if (e.kind === "pattern-overlay") paintPattern(lay, full, e, env, e.blend, e.opacity);
2253
+ }
2254
+ function decodeInPlace(d) {
2255
+ for (let i = 0; i < d.length; i += 4) {
2256
+ d[i] = _chunk7ISPWEJAcjs.srgbDecode.call(void 0, d[i]);
2257
+ d[i + 1] = _chunk7ISPWEJAcjs.srgbDecode.call(void 0, d[i + 1]);
2258
+ d[i + 2] = _chunk7ISPWEJAcjs.srgbDecode.call(void 0, d[i + 2]);
2205
2259
  }
2206
- for (const i of rev) {
2207
- const e = items[i];
2208
- if (e.kind === "gradient-overlay") paintGradient(lay, full, e.gradient, e.gradient.align ? bounds : input.canvas, env, e.blend, e.opacity);
2260
+ }
2261
+
2262
+ // src/raster/blur.ts
2263
+ function gaussianKernel(sigma) {
2264
+ const r = Math.ceil(sigma * 3);
2265
+ const k = new Float32Array(2 * r + 1);
2266
+ let s = 0;
2267
+ for (let i = -r; i <= r; i++) {
2268
+ const v = Math.exp(-(i * i) / (2 * sigma * sigma));
2269
+ k[i + r] = v;
2270
+ s += v;
2209
2271
  }
2210
- for (const i of rev) {
2211
- const e = items[i];
2212
- if (e.kind === "color-overlay") paintColor(lay, full, e.color, e.blend, e.opacity);
2272
+ for (let i = 0; i < k.length; i++) k[i] /= s;
2273
+ return k;
2274
+ }
2275
+ var DIRECT_GAUSSIAN_MAX_SIGMA = 8;
2276
+ function boxRadii(sigma) {
2277
+ const n = 3;
2278
+ const wIdeal = Math.sqrt(12 * sigma * sigma / n + 1);
2279
+ let wl = Math.floor(wIdeal);
2280
+ if (wl % 2 === 0) wl--;
2281
+ const wu = wl + 2;
2282
+ const mIdeal = (12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
2283
+ const m = Math.round(mIdeal);
2284
+ const sizes = [0, 1, 2].map((i) => i < m ? wl : wu);
2285
+ return sizes.map((s) => (s - 1) / 2);
2286
+ }
2287
+ function convolveLine(src, off, stride, len, k, edge, dst) {
2288
+ const r = (k.length - 1) / 2;
2289
+ for (let i = 0; i < len; i++) {
2290
+ let a = 0;
2291
+ const lo = i - r;
2292
+ for (let j = 0; j < k.length; j++) {
2293
+ let x = lo + j;
2294
+ if (x < 0 || x >= len) {
2295
+ if (edge === "zero") continue;
2296
+ x = x < 0 ? 0 : len - 1;
2297
+ }
2298
+ a += src[off + x * stride] * k[j];
2299
+ }
2300
+ dst[i] = a;
2213
2301
  }
2214
- for (const i of rev) {
2215
- const e = items[i];
2216
- if (e.kind === "satin") paintColor(lay, rel(fx(i, 0)), e.color, e.blend, e.opacity);
2302
+ }
2303
+ function boxesLine(src, off, stride, len, radii, edge, a, b, dst) {
2304
+ const pad = radii.reduce((s, r) => s + r, 0);
2305
+ const plen = len + 2 * pad;
2306
+ for (let i = 0; i < plen; i++) {
2307
+ const j = i - pad;
2308
+ a[i] = j < 0 ? edge === "zero" ? 0 : src[off] : j >= len ? edge === "zero" ? 0 : src[off + (len - 1) * stride] : src[off + j * stride];
2217
2309
  }
2218
- for (const i of rev) {
2219
- const e = items[i];
2220
- if (e.kind === "inner-glow") paintGlow(lay, rel(fx(i, 0)), e, env);
2310
+ let from = a;
2311
+ let to = b;
2312
+ for (const r of radii) {
2313
+ let sum = 0;
2314
+ for (let i = 0; i <= Math.min(r, plen - 1); i++) sum += from[i];
2315
+ const k = 2 * r + 1;
2316
+ for (let i = 0; i < plen; i++) {
2317
+ to[i] = sum / k;
2318
+ const add = i + r + 1;
2319
+ const drop = i - r;
2320
+ if (add < plen) sum += from[add];
2321
+ if (drop >= 0) sum -= from[drop];
2322
+ }
2323
+ const t = from;
2324
+ from = to;
2325
+ to = t;
2221
2326
  }
2222
- for (const i of rev) {
2223
- const e = items[i];
2224
- if (e.kind === "inner-shadow") paintColor(lay, rel(fx(i, 0)), e.color, e.blend, e.opacity);
2327
+ for (let i = 0; i < len; i++) dst[i] = from[i + pad];
2328
+ }
2329
+ function gaussianBlur(src, w, h, sigma, edge = "zero") {
2330
+ const out = Float32Array.from(src);
2331
+ if (!(sigma >= 0.1) || w <= 0 || h <= 0) return out;
2332
+ const s = Math.min(sigma, 4 * Math.max(w, h));
2333
+ const line = new Float32Array(Math.max(w, h));
2334
+ const passes = [];
2335
+ if (s <= DIRECT_GAUSSIAN_MAX_SIGMA) {
2336
+ const k = gaussianKernel(s);
2337
+ passes.push((buf, off, stride, len) => convolveLine(buf, off, stride, len, k, edge, line));
2338
+ } else {
2339
+ const radii = boxRadii(s);
2340
+ const plen = Math.max(w, h) + 2 * radii.reduce((a2, r) => a2 + r, 0);
2341
+ const a = new Float32Array(plen);
2342
+ const b = new Float32Array(plen);
2343
+ passes.push((buf, off, stride, len) => boxesLine(buf, off, stride, len, radii, edge, a, b, line));
2225
2344
  }
2226
- const strokeIdx = items.map((e, i) => e.kind === "stroke" ? i : -1).filter((i) => i >= 0);
2227
- const din = strokeIdx.length && maps.din ? crop(maps.din, maps.rect, rect, 0) : null;
2228
- const frameOf = (i) => _nullishCoalesce(maps.frames.get(i), () => ( bounds));
2229
- for (let k = strokeIdx.length - 1; k >= 0; k--) {
2230
- const st = items[strokeIdx[k]];
2231
- const [inW] = strokeWidths(st);
2232
- if (!(inW > 0) || !din) continue;
2233
- const m = new Float32Array(n);
2234
- for (let i = 0; i < n; i++) m[i] = inside(shape[i]) ? clamp012(inW + 0.5 - din[i]) : 0;
2235
- paintFill(lay, m, st.fill, frameOf(strokeIdx[k]), env, st.blend, st.opacity);
2345
+ for (const pass of passes) {
2346
+ for (let y = 0; y < h; y++) {
2347
+ pass(out, y * w, 1, w);
2348
+ out.set(line.subarray(0, w), y * w);
2349
+ }
2236
2350
  }
2237
- for (const i of rev) {
2238
- const e = items[i];
2239
- if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "inner") continue;
2240
- paintColor(lay, rel(fx(i, 0)), e.highlightColor, e.highlightBlend, e.highlightOpacity);
2241
- paintColor(lay, rel(fx(i, 1)), e.shadowColor, e.shadowBlend, e.shadowOpacity);
2351
+ for (const pass of passes) {
2352
+ for (let x = 0; x < w; x++) {
2353
+ pass(out, x, w, h);
2354
+ for (let y = 0; y < h; y++) out[y * w + x] = line[y];
2355
+ }
2242
2356
  }
2243
- for (let i = 0; i < n; i++) lay[i * 4 + 3] *= Math.min(shape[i], 1);
2244
- const outside = strokeIdx.filter((i) => strokeWidths(items[i])[1] > 0);
2245
- if (outside.length) {
2246
- const dout = maps.dout ? crop(maps.dout, maps.rect, rect, FAR) : null;
2247
- const doutExact = maps.doutExact ? crop(maps.doutExact, maps.rect, rect, FAR) : null;
2248
- const base = new Float32Array(work);
2249
- const acc = new Float32Array(n * 4);
2250
- const cover = new Float32Array(n);
2251
- for (const si of outside) {
2252
- const st = items[si];
2253
- const outW = strokeWidths(st)[1];
2254
- const d = _nullishCoalesce((outW >= STROKE_CHAMFER_MAX ? doutExact : dout), () => ( new Float32Array(n).fill(FAR)));
2255
- const share = new Float32Array(n);
2256
- const ones = new Float32Array(n);
2257
- for (let i = 0; i < n; i++) {
2258
- const band = clamp012(outW + 0.5 - d[i]);
2259
- let k;
2260
- if (inside(shape[i])) {
2261
- const c = clamp012(lay[i * 4 + 3]);
2262
- k = c >= 1 ? 1 : clamp012((1 - clamp012(shape[i])) / (1 - c));
2263
- } else k = band;
2264
- share[i] = k * st.opacity * (1 - cover[i]);
2265
- cover[i] += share[i];
2266
- ones[i] = share[i] > 0 ? 1 : 0;
2267
- }
2268
- const blended = new Float32Array(base);
2269
- paintFill(blended, ones, st.fill, frameOf(si), env, st.blend, 1);
2270
- for (let i = 0; i < n; i++) {
2271
- const s = share[i];
2272
- if (!(s > 0)) continue;
2273
- const p = i * 4;
2274
- const ba = blended[p + 3];
2275
- acc[p] += s * blended[p] * ba;
2276
- acc[p + 1] += s * blended[p + 1] * ba;
2277
- acc[p + 2] += s * blended[p + 2] * ba;
2278
- acc[p + 3] += s * ba;
2279
- }
2357
+ return out;
2358
+ }
2359
+
2360
+ // src/raster/layers.ts
2361
+ var childrenOf = (l) => l.type === "group" ? _nullishCoalesce(l.children, () => ( null)) : null;
2362
+ function flattenLayers(layers) {
2363
+ const out = [];
2364
+ const walk = (list) => {
2365
+ for (const l of list) {
2366
+ out.push(l);
2367
+ const c = childrenOf(l);
2368
+ if (c) walk(c);
2280
2369
  }
2281
- for (let i = 0; i < n; i++) {
2282
- const c = cover[i];
2283
- if (c <= 0) continue;
2284
- const p = i * 4;
2285
- const k = 1 - Math.min(c, 1);
2286
- const a = work[p + 3] * k + acc[p + 3];
2287
- if (a > 0) {
2288
- work[p] = (work[p] * work[p + 3] * k + acc[p]) / a;
2289
- work[p + 1] = (work[p + 1] * work[p + 3] * k + acc[p + 1]) / a;
2290
- work[p + 2] = (work[p + 2] * work[p + 3] * k + acc[p + 2]) / a;
2291
- work[p + 3] = Math.min(a, 1);
2370
+ };
2371
+ walk(layers);
2372
+ return out;
2373
+ }
2374
+ function findLayer(layers, id) {
2375
+ const walk = (list, parent, path) => {
2376
+ for (let i = 0; i < list.length; i++) {
2377
+ const l = list[i];
2378
+ if (l.id === id) return { layer: l, parent, index: i, path };
2379
+ const c = childrenOf(l);
2380
+ if (c) {
2381
+ const g = l;
2382
+ const hit = walk(c, g, [...path, g]);
2383
+ if (hit) return hit;
2292
2384
  }
2293
2385
  }
2294
- }
2295
- for (const i of rev) {
2296
- const e = items[i];
2297
- if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "outer") continue;
2298
- paintColor(work, fx(i, 0), e.highlightColor, e.highlightBlend, e.highlightOpacity);
2299
- paintColor(work, fx(i, 1), e.shadowColor, e.shadowBlend, e.shadowOpacity);
2300
- }
2301
- const mode = premerge ? "normal" : input.blend;
2302
- const sep = _chunk7ISPWEJAcjs.isSeparableBlendMode.call(void 0, mode);
2303
- for (let i = 0; i < n; i++) {
2304
- const p = i * 4;
2305
- if (lay[p + 3] > 0) compositeAt(work, p, mode, sep, lay[p], lay[p + 1], lay[p + 2], lay[p + 3]);
2306
- }
2307
- for (const i of rev) {
2308
- const e = items[i];
2309
- if (e.kind !== "bevel-emboss" || maps.bevelPaint[i] !== "both") continue;
2310
- paintColor(work, fx(i, 0), e.highlightColor, e.highlightBlend, e.highlightOpacity);
2311
- paintColor(work, fx(i, 1), e.shadowColor, e.shadowBlend, e.shadowOpacity);
2312
- }
2313
- const op = clamp012(input.opacity);
2314
- for (let i = 0; i < n; i++) {
2315
- const p = i * 4;
2316
- const aa = before[p + 3];
2317
- const ba = work[p + 3];
2318
- const alpha = aa + (ba - aa) * op;
2319
- if (alpha <= 0) {
2320
- backdrop[p] = backdrop[p + 1] = backdrop[p + 2] = backdrop[p + 3] = 0;
2321
- continue;
2386
+ return null;
2387
+ };
2388
+ return walk(layers, null, []);
2389
+ }
2390
+ function mapLayer(layers, id, fn) {
2391
+ let changed = false;
2392
+ const walk = (list) => {
2393
+ let out = null;
2394
+ for (let i = 0; i < list.length; i++) {
2395
+ const l = list[i];
2396
+ let next = l;
2397
+ if (l.id === id) {
2398
+ next = fn(l);
2399
+ changed = true;
2400
+ } else {
2401
+ const c = childrenOf(l);
2402
+ if (c) {
2403
+ const children = walk(c);
2404
+ if (children !== c) next = { ...l, children };
2405
+ }
2406
+ }
2407
+ if (next !== l) {
2408
+ if (!out) out = list.slice(0, i);
2409
+ if (next) out.push(next);
2410
+ } else if (out) out.push(l);
2322
2411
  }
2323
- for (let c = 0; c < 3; c++) backdrop[p + c] = Math.round((before[p + c] * aa + (work[p + c] * ba - before[p + c] * aa) * op) / alpha * 255);
2324
- backdrop[p + 3] = Math.round(alpha * 255);
2325
- }
2412
+ return _nullishCoalesce(out, () => ( list));
2413
+ };
2414
+ const result = walk(layers);
2415
+ return changed ? result : layers;
2326
2416
  }
2327
- function renderLayerEffects(effects, layer, backdrop, canvas, ctx) {
2328
- const items = activeEffectItems(effects);
2329
- const n = layer.rect.width * layer.rect.height;
2330
- const shape = new Float32Array(n);
2331
- for (let i = 0; i < n; i++) shape[i] = layer.content[i * 4 + 3] / 255;
2332
- const maps = buildEffectMaps(items, shape, layer.rect, ctx);
2333
- compositeLayerEffects({
2334
- backdrop,
2335
- content: layer.content,
2336
- rect: layer.rect,
2337
- maps,
2338
- blend: layer.blend,
2339
- opacity: layer.opacity,
2340
- fillOpacity: _nullishCoalesce(layer.fillOpacity, () => ( 1)),
2341
- canvas,
2342
- ctx
2417
+ function insertLayer(layers, layer, parentId, index) {
2418
+ const put = (list) => {
2419
+ const at = index === void 0 ? list.length : Math.max(0, Math.min(list.length, index));
2420
+ const next = list.slice();
2421
+ next.splice(at, 0, layer);
2422
+ return next;
2423
+ };
2424
+ if (!parentId) return put(layers);
2425
+ return mapLayer(layers, parentId, (g) => {
2426
+ const c = childrenOf(g);
2427
+ return c ? { ...g, children: put(c) } : g;
2343
2428
  });
2344
2429
  }
2430
+ function isLayerLocked(layer, what) {
2431
+ return Boolean(_optionalChain([layer, 'access', _27 => _27.locks, 'optionalAccess', _28 => _28.all]) || _optionalChain([layer, 'access', _29 => _29.locks, 'optionalAccess', _30 => _30[what]]));
2432
+ }
2345
2433
 
2346
2434
  // src/raster/compositor.ts
2347
2435
  var TILE_PIXELS = _chunk7ISPWEJAcjs.TILE * _chunk7ISPWEJAcjs.TILE;
@@ -2563,7 +2651,7 @@ var RasterCompositor = (_class = class {
2563
2651
  const dirty = grow > 0 ? options.dirty.map((d) => inflateRect(d, grow)) : options.dirty;
2564
2652
  for (const { tx, ty } of _chunk7ISPWEJAcjs.tilesInRect.call(void 0, rect)) {
2565
2653
  stats.tiles++;
2566
- const before = _optionalChain([this, 'access', _25 => _25.tiles, 'access', _26 => _26.get, 'call', _27 => _27(_chunk7ISPWEJAcjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _28 => _28.result]);
2654
+ const before = _optionalChain([this, 'access', _31 => _31.tiles, 'access', _32 => _32.get, 'call', _33 => _33(_chunk7ISPWEJAcjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _34 => _34.result]);
2567
2655
  const data = this.compositeTile(layers, steps, tx, ty, stats, dirty ? dirtyInTile(dirty, tx, ty) : null);
2568
2656
  onTile(tx, ty, data, data !== before);
2569
2657
  }
@@ -2591,13 +2679,33 @@ var RasterCompositor = (_class = class {
2591
2679
  this.setSources(sources);
2592
2680
  return this.maskTile(layer, r);
2593
2681
  }
2682
+ /**
2683
+ * For the float compositor: everything `compositeLayerEffects` needs for `layer` over `r` but
2684
+ * the pixels (the area its effects reach inside `r`, the effect maps built from its 8-bit
2685
+ * shape, blend, opacities, canvas and context), or `null` when nothing reaches `r`.
2686
+ */
2687
+ effectsInput(layer, r, sources) {
2688
+ this.setSources(sources);
2689
+ const maps = this.effectMapsOf(layer);
2690
+ const rect = this.effectArea(layer, maps, r);
2691
+ if (!rect) return null;
2692
+ return {
2693
+ rect,
2694
+ maps,
2695
+ blend: isGroup2(layer) ? layer.blend === "pass-through" ? "normal" : layer.blend : this.contentBlend(layer),
2696
+ opacity: layer.opacity,
2697
+ fillOpacity: this.isPixel(layer) ? _nullishCoalesce(layer.fillOpacity, () => ( 1)) : 1,
2698
+ canvas: { x: 0, y: 0, width: this.sources.width, height: this.sources.height },
2699
+ ctx: this.effectContext()
2700
+ };
2701
+ }
2594
2702
  // --- Steps -------------------------------------------------------------------
2595
2703
  /** Pixel layers, and the layer kinds the profile composites like them. */
2596
2704
  isPixel(l) {
2597
- return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _29 => _29.profile, 'access', _30 => _30.isPixelLike, 'optionalCall', _31 => _31(l)]), () => ( false)));
2705
+ return l.type === "pixel" || (_nullishCoalesce(_optionalChain([this, 'access', _35 => _35.profile, 'access', _36 => _36.isPixelLike, 'optionalCall', _37 => _37(l)]), () => ( false)));
2598
2706
  }
2599
2707
  isFilter(l) {
2600
- return _nullishCoalesce(_optionalChain([this, 'access', _32 => _32.profile, 'access', _33 => _33.isFilterLayer, 'optionalCall', _34 => _34(l)]), () => ( false));
2708
+ return _nullishCoalesce(_optionalChain([this, 'access', _38 => _38.profile, 'access', _39 => _39.isFilterLayer, 'optionalCall', _40 => _40(l)]), () => ( false));
2601
2709
  }
2602
2710
  /**
2603
2711
  * Groups a layer list into compositing steps: clipped layers join the nearest unclipped
@@ -2636,9 +2744,9 @@ var RasterCompositor = (_class = class {
2636
2744
  if (key !== void 0) return key;
2637
2745
  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;
2638
2746
  const base = [layer.type, layer.id, layer.visible, layer.opacity, layer.blend, Boolean(layer.clipped), mask];
2639
- if (this.isPixel(layer)) base.push(_nullishCoalesce(_optionalChain([layer, 'access', _35 => _35.offset, 'optionalAccess', _36 => _36.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _37 => _37.offset, 'optionalAccess', _38 => _38.y]), () => ( 0)), _nullishCoalesce(layer.fillOpacity, () => ( 1)));
2747
+ 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)));
2640
2748
  if (this.hasEffects(layer)) base.push(effectsFingerprint(layer.effects));
2641
- const extra = _optionalChain([this, 'access', _39 => _39.profile, 'access', _40 => _40.layerKey, 'optionalCall', _41 => _41(layer)]);
2749
+ const extra = _optionalChain([this, 'access', _45 => _45.profile, 'access', _46 => _46.layerKey, 'optionalCall', _47 => _47(layer)]);
2642
2750
  if (extra !== void 0) base.push(extra);
2643
2751
  key = JSON.stringify(base);
2644
2752
  this.propsKeyCache.set(layer, key);
@@ -2805,7 +2913,7 @@ var RasterCompositor = (_class = class {
2805
2913
  const refs = [surface.defaultValue];
2806
2914
  const r = { x: tx * _chunk7ISPWEJAcjs.TILE - dx, y: ty * _chunk7ISPWEJAcjs.TILE - dy, width: _chunk7ISPWEJAcjs.TILE, height: _chunk7ISPWEJAcjs.TILE };
2807
2915
  for (const t of _chunk7ISPWEJAcjs.tilesInRect.call(void 0, r)) refs.push(_nullishCoalesce(surface.getTile(t.tx, t.ty), () => ( null)));
2808
- refs.push(...this.maskRefs(layer, tx, ty, _nullishCoalesce(_optionalChain([layer, 'access', _42 => _42.offset, 'optionalAccess', _43 => _43.x]), () => ( 0)), _nullishCoalesce(_optionalChain([layer, 'access', _44 => _44.offset, 'optionalAccess', _45 => _45.y]), () => ( 0))));
2916
+ 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))));
2809
2917
  return { key, refs };
2810
2918
  }
2811
2919
  // --- Layer effects ------------------------------------------------------------
@@ -2835,7 +2943,7 @@ var RasterCompositor = (_class = class {
2835
2943
  this.fxContext = {
2836
2944
  light: _nullishCoalesce(sources.globalLight, () => ( DEFAULT_GLOBAL_LIGHT)),
2837
2945
  pattern: (id) => {
2838
- const p = _nullishCoalesce(_optionalChain([sources, 'access', _46 => _46.pattern, 'optionalCall', _47 => _47(id)]), () => ( builtinPattern(id)));
2946
+ const p = _nullishCoalesce(_optionalChain([sources, 'access', _52 => _52.pattern, 'optionalCall', _53 => _53(id)]), () => ( builtinPattern(id)));
2839
2947
  if (!p || !(p.width > 0 && p.height > 0) || p.data.length < p.width * p.height * 4) return null;
2840
2948
  let t = tiles.get(p);
2841
2949
  if (!t) {
@@ -2963,7 +3071,7 @@ var RasterCompositor = (_class = class {
2963
3071
  * without filters or a feathered or parametric mask (those spread a change beyond it).
2964
3072
  */
2965
3073
  dirtyCoversShape(layer) {
2966
- if (!this.isPixel(layer) || _optionalChain([this, 'access', _48 => _48.profile, 'access', _49 => _49.pixelFilters, 'optionalCall', _50 => _50(layer)])) return false;
3074
+ if (!this.isPixel(layer) || _optionalChain([this, 'access', _54 => _54.profile, 'access', _55 => _55.pixelFilters, 'optionalCall', _56 => _56(layer)])) return false;
2967
3075
  const mask = layer.mask;
2968
3076
  return !mask || mask.enabled === false || !mask.source && !((_nullishCoalesce(mask.feather, () => ( 0))) > 0);
2969
3077
  }
@@ -3051,10 +3159,10 @@ var RasterCompositor = (_class = class {
3051
3159
  */
3052
3160
  layerPixels(layer) {
3053
3161
  const raw = this.sources.surfaceOf ? this.sources.surfaceOf(layer) : layer.surface;
3054
- const ox = _nullishCoalesce(_optionalChain([layer, 'access', _51 => _51.offset, 'optionalAccess', _52 => _52.x]), () => ( 0));
3055
- const oy = _nullishCoalesce(_optionalChain([layer, 'access', _53 => _53.offset, 'optionalAccess', _54 => _54.y]), () => ( 0));
3056
- const filters = _nullishCoalesce(_optionalChain([this, 'access', _55 => _55.profile, 'access', _56 => _56.pixelFilters, 'optionalCall', _57 => _57(layer)]), () => ( null));
3057
- if (!_optionalChain([filters, 'optionalAccess', _58 => _58.spatial])) return { surface: raw, dx: ox, dy: oy, perPixel: filters };
3162
+ const ox = _nullishCoalesce(_optionalChain([layer, 'access', _57 => _57.offset, 'optionalAccess', _58 => _58.x]), () => ( 0));
3163
+ const oy = _nullishCoalesce(_optionalChain([layer, 'access', _59 => _59.offset, 'optionalAccess', _60 => _60.y]), () => ( 0));
3164
+ const filters = _nullishCoalesce(_optionalChain([this, 'access', _61 => _61.profile, 'access', _62 => _62.pixelFilters, 'optionalCall', _63 => _63(layer)]), () => ( null));
3165
+ if (!_optionalChain([filters, 'optionalAccess', _64 => _64.spatial])) return { surface: raw, dx: ox, dy: oy, perPixel: filters };
3058
3166
  const fkey = `${ox},${oy}:${filters.key}`;
3059
3167
  let byKey = this.filteredCache.get(raw);
3060
3168
  if (!byKey) {
@@ -3071,7 +3179,7 @@ var RasterCompositor = (_class = class {
3071
3179
  }
3072
3180
  /** RGBA of a content layer over `r` (document space, inside one tile), or `null` when it has nothing there. */
3073
3181
  contentTile(layer, r) {
3074
- if (!this.isPixel(layer)) return _nullishCoalesce(_optionalChain([this, 'access', _59 => _59.profile, 'access', _60 => _60.contentTile, 'optionalCall', _61 => _61(layer, r, this.sources)]), () => ( null));
3182
+ if (!this.isPixel(layer)) return _nullishCoalesce(_optionalChain([this, 'access', _65 => _65.profile, 'access', _66 => _66.contentTile, 'optionalCall', _67 => _67(layer, r, this.sources)]), () => ( null));
3075
3183
  const { surface, dx, dy, perPixel } = this.layerPixels(layer);
3076
3184
  const src = { x: r.x - dx, y: r.y - dy, width: r.width, height: r.height };
3077
3185
  const covered = _chunk7ISPWEJAcjs.tilesInRect.call(void 0, src).map((t) => surface.getTile(t.tx, t.ty));
@@ -3086,7 +3194,7 @@ var RasterCompositor = (_class = class {
3086
3194
  let byKey = this.contentCache.get(anchor);
3087
3195
  const refsKey = `${r.x},${r.y}:${fkey}`;
3088
3196
  if (aligned) {
3089
- const hit = _optionalChain([byKey, 'optionalAccess', _62 => _62.get, 'call', _63 => _63(refsKey)]);
3197
+ const hit = _optionalChain([byKey, 'optionalAccess', _68 => _68.get, 'call', _69 => _69(refsKey)]);
3090
3198
  if (hit) return hit;
3091
3199
  }
3092
3200
  const data = _chunk7ISPWEJAcjs.readRegion.call(void 0, surface, src);
@@ -3124,7 +3232,7 @@ var RasterCompositor = (_class = class {
3124
3232
  const H = this.sources.height;
3125
3233
  let v = new Float32Array(W * H);
3126
3234
  if (mask.source) {
3127
- const generated = _nullishCoalesce(_optionalChain([this, 'access', _64 => _64.profile, 'access', _65 => _65.maskSourcePlane, 'optionalCall', _66 => _66(mask.source, W, H, this.sources)]), () => ( null));
3235
+ const generated = _nullishCoalesce(_optionalChain([this, 'access', _70 => _70.profile, 'access', _71 => _71.maskSourcePlane, 'optionalCall', _72 => _72(mask.source, W, H, this.sources)]), () => ( null));
3128
3236
  if (!generated || generated.length !== W * H) v.fill(1);
3129
3237
  else v.set(generated);
3130
3238
  } else {
@@ -3143,8 +3251,8 @@ var RasterCompositor = (_class = class {
3143
3251
  maskTile(layer, r) {
3144
3252
  const mask = layer.mask;
3145
3253
  if (!mask || mask.enabled === false) return null;
3146
- const ox = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _67 => _67.offset, 'optionalAccess', _68 => _68.x]), () => ( 0)) : 0;
3147
- const oy = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _69 => _69.offset, 'optionalAccess', _70 => _70.y]), () => ( 0)) : 0;
3254
+ const ox = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _73 => _73.offset, 'optionalAccess', _74 => _74.x]), () => ( 0)) : 0;
3255
+ const oy = this.isPixel(layer) ? _nullishCoalesce(_optionalChain([layer, 'access', _75 => _75.offset, 'optionalAccess', _76 => _76.y]), () => ( 0)) : 0;
3148
3256
  const n = r.width * r.height;
3149
3257
  const out = new Float32Array(n);
3150
3258
  const density = _nullishCoalesce(mask.density, () => ( 1));
@@ -3228,7 +3336,7 @@ var RasterCompositor = (_class = class {
3228
3336
  return empty;
3229
3337
  }
3230
3338
  contentBlend(layer) {
3231
- return _nullishCoalesce(_optionalChain([this, 'access', _71 => _71.profile, 'access', _72 => _72.contentBlend, 'optionalCall', _73 => _73(layer)]), () => ( layer.blend));
3339
+ return _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.profile, 'access', _78 => _78.contentBlend, 'optionalCall', _79 => _79(layer)]), () => ( layer.blend));
3232
3340
  }
3233
3341
  blendOnto(acc, src, empty, mode, alpha, coverage) {
3234
3342
  if (!(alpha > 0)) return empty;
@@ -3282,7 +3390,7 @@ var RasterCompositor = (_class = class {
3282
3390
  }
3283
3391
  visible.push(node);
3284
3392
  }
3285
- if (visible.length) _optionalChain([this, 'access', _74 => _74.profile, 'access', _75 => _75.applyFilterRun, 'optionalCall', _76 => _76(visible, acc, r, masks, this.sources)]);
3393
+ if (visible.length) _optionalChain([this, 'access', _80 => _80.profile, 'access', _81 => _81.applyFilterRun, 'optionalCall', _82 => _82(visible, acc, r, masks, this.sources)]);
3286
3394
  }
3287
3395
  }, _class);
3288
3396
  function filterOverCanvas(surface, ox, oy, filters, width, height) {
@@ -4201,5 +4309,5 @@ function compositeSurfaceOver(base, top) {
4201
4309
 
4202
4310
 
4203
4311
 
4204
- 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.DeepCompositor = DeepCompositor; exports.workingToSamples = workingToSamples; exports.DIRECT_GAUSSIAN_MAX_SIGMA = DIRECT_GAUSSIAN_MAX_SIGMA; exports.gaussianBlur = gaussianBlur; exports.flattenLayers = flattenLayers; exports.findLayer = findLayer; exports.mapLayer = mapLayer; exports.insertLayer = insertLayer; exports.isLayerLocked = isLayerLocked; 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.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;
4205
- //# sourceMappingURL=chunk-LL3RAN55.cjs.map
4312
+ 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.DIRECT_GAUSSIAN_MAX_SIGMA = DIRECT_GAUSSIAN_MAX_SIGMA; exports.gaussianBlur = gaussianBlur; 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;
4313
+ //# sourceMappingURL=chunk-DFFBJV3U.cjs.map