emf-converter 4.7.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -11774,19 +11774,73 @@ function roundRectCorners(l, t, r, b, cw, ch, compatible = false, clockwise = fa
11774
11774
  ];
11775
11775
  }
11776
11776
  var TRIG_STEP = 2 * Math.PI / 128;
11777
- function tableTrig(fn) {
11777
+ var TRIG_NODES = [
11778
+ 1,
11779
+ 0.99879566,
11780
+ 0.99518639,
11781
+ 0.98917961,
11782
+ 0.98079146,
11783
+ 0.97003981,
11784
+ 0.95695228,
11785
+ 0.94155978,
11786
+ 0.92389844,
11787
+ 0.90401145,
11788
+ 0.88194619,
11789
+ 0.85775575,
11790
+ 0.83149879,
11791
+ 0.80323775,
11792
+ 0.77303903,
11793
+ 0.74098864,
11794
+ 0.70710648,
11795
+ 0.67151859,
11796
+ 0.63435836,
11797
+ 0.59565849,
11798
+ 0.55552672,
11799
+ 0.51405765,
11800
+ 0.47135039,
11801
+ 0.42750875,
11802
+ 0.38263811,
11803
+ 0.33684632,
11804
+ 0.29024443,
11805
+ 0.24294646,
11806
+ 0.19505974,
11807
+ 0.14670808,
11808
+ 0.0980012,
11809
+ 0.04906089,
11810
+ 0
11811
+ ];
11812
+ var TRIG_TABLE = (() => {
11813
+ const cos = [];
11814
+ const sin = [];
11815
+ for (let k = 0; k <= 128; k++) {
11816
+ const q = k >> 5;
11817
+ const i = k & 31;
11818
+ const c = TRIG_NODES[i];
11819
+ const s = TRIG_NODES[32 - i];
11820
+ if (k === 128) {
11821
+ cos.push(1);
11822
+ sin.push(0);
11823
+ continue;
11824
+ }
11825
+ cos.push([c, -s, -c, s][q]);
11826
+ sin.push([s, c, -s, -c][q]);
11827
+ }
11828
+ return { cos, sin };
11829
+ })();
11830
+ function tableTrig(table) {
11778
11831
  return (a) => {
11779
11832
  let b = a % (2 * Math.PI);
11780
11833
  if (b < 0) {
11781
11834
  b += 2 * Math.PI;
11782
11835
  }
11783
- const i = Math.floor(b / TRIG_STEP);
11784
- const f = b / TRIG_STEP - i;
11785
- return fn(i * TRIG_STEP) * (1 - f) + fn((i + 1) * TRIG_STEP) * f;
11836
+ const x = b / TRIG_STEP;
11837
+ const i = Math.min(127, Math.floor(x));
11838
+ const f = x - i;
11839
+ return table[i] * (1 - f) + table[i + 1] * f;
11786
11840
  };
11787
11841
  }
11788
- var tableCos = tableTrig(Math.cos);
11789
- var tableSin = tableTrig(Math.sin);
11842
+ var tableCos = tableTrig(TRIG_TABLE.cos);
11843
+ var tableSin = tableTrig(TRIG_TABLE.sin);
11790
11844
  function angleArcPieces(startDeg, sweepDeg) {
11791
11845
  const out = [];
11792
11846
  const arc = (from, to) => {
@@ -11857,6 +11911,38 @@ function angleArcFix(box, startDeg, sweepDeg) {
11857
11911
  }
11858
11912
  return out;
11859
11913
  }
11914
+ var SMALL_SWEEP = 3 * Math.PI / 180;
11915
+ function anchoredPiece(boundary, free, rx, ry, cx, cy, smallArc) {
11916
+ const sweep = Math.abs(free - boundary);
11917
+ const small = smallArc;
11918
+ const cos = small ? Math.cos : tableCos;
11919
+ const sin = small ? Math.sin : tableSin;
11920
+ const anchor = [Math.round(cx + rx * Math.cos(boundary)), Math.round(cy - ry * Math.sin(boundary))];
11921
+ const point = [cx + rx * cos(free), cy - ry * sin(free)];
11922
+ let t;
11923
+ let kappa;
11924
+ if (small) {
11925
+ t = Math.tan(sweep / 2);
11926
+ kappa = 2 / 3 * (1 - Math.tan(sweep / 4) ** 2);
11927
+ } else {
11928
+ const c = tableCos(sweep);
11929
+ const sn = tableSin(sweep);
11930
+ t = (1 - c) / sn;
11931
+ const q = t / (1 + Math.sqrt(1 + t * t));
11932
+ kappa = 2 / 3 * (1 - q * q);
11933
+ }
11934
+ const dir = free > boundary ? 1 : -1;
11935
+ const tx = -Math.round(Math.sin(boundary));
11936
+ const ty = -Math.round(Math.cos(boundary));
11937
+ const length = tx !== 0 ? rx : ry;
11938
+ const X = [anchor[0] + dir * tx * length * t, anchor[1] + dir * ty * length * t];
11939
+ return {
11940
+ anchor,
11941
+ free: point,
11942
+ cAnchor: [anchor[0] + kappa * (X[0] - anchor[0]), anchor[1] + kappa * (X[1] - anchor[1])],
11943
+ cFree: [point[0] + kappa * (X[0] - point[0]), point[1] + kappa * (X[1] - point[1])]
11944
+ };
11945
+ }
11860
11946
  function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
11861
11947
  const w = r - l;
11862
11948
  const h = b - t;
@@ -11895,6 +11981,21 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
11895
11981
  continue;
11896
11982
  }
11897
11983
  const e = s > 0 ? Math.min(next, a1) : Math.max(next, a1);
11984
+ const endOnBoundary = Math.abs(e / Q - Math.round(e / Q)) < 1e-9;
11985
+ if (onBoundary !== endOnBoundary) {
11986
+ const piece = anchoredPiece(onBoundary ? a : e, onBoundary ? e : a, rx, ry, cx, cy, Math.abs(a1 - a0) <= SMALL_SWEEP);
11987
+ if (onBoundary) {
11988
+ out.push(...[piece.cAnchor, piece.cFree, piece.free].flatMap((q) => [Math.round(q[0]), Math.round(q[1])]));
11989
+ } else {
11990
+ if (out.length === 2) {
11991
+ out[0] = Math.round(piece.free[0]);
11992
+ out[1] = Math.round(piece.free[1]);
11993
+ }
11994
+ out.push(...[piece.cFree, piece.cAnchor, piece.anchor].flatMap((q) => [Math.round(q[0]), Math.round(q[1])]));
11995
+ }
11996
+ a = e;
11997
+ continue;
11998
+ }
11898
11999
  const k = 4 / 3 * Math.tan((e - a) / 4);
11899
12000
  out.push(
11900
12001
  Math.round(px(a) - k * rx * tableSin(a)),
@@ -11989,6 +12090,10 @@ var GdiRasterPath = class {
11989
12090
  };
11990
12091
  const t0 = tangent(x0, y0, c1x, c1y, c2x, c2y, x3, y3);
11991
12092
  const t1 = tangent(c2x, c2y, x3, y3, x3, y3, x3, y3) ?? tangent(c1x, c1y, x3, y3, x3, y3, x3, y3) ?? tangent(x0, y0, x3, y3, x3, y3, x3, y3);
12093
+ f.curveSegs ?? (f.curveSegs = /* @__PURE__ */ new Set());
12094
+ for (let k = first; k <= last; k++) {
12095
+ f.curveSegs.add(k);
12096
+ }
11992
12097
  f.tangents ?? (f.tangents = /* @__PURE__ */ new Map());
11993
12098
  if (t0) f.tangents.set(first, t0);
11994
12099
  if (t1) f.tangents.set(last, t1);
@@ -12022,7 +12127,7 @@ var GdiRasterPath = class {
12022
12127
  /** Appends every figure of `other`. */
12023
12128
  append(other) {
12024
12129
  for (const f of other.figures) {
12025
- this.figures.push({ pts: f.pts.slice(), closed: f.closed, tangents: f.tangents && new Map(f.tangents), roundWiden: f.roundWiden });
12130
+ this.figures.push({ pts: f.pts.slice(), closed: f.closed, tangents: f.tangents && new Map(f.tangents), curveSegs: f.curveSegs && new Set(f.curveSegs), roundWiden: f.roundWiden });
12026
12131
  }
12027
12132
  for (let i = 0; i < other.getPath.types.length; i++) {
12028
12133
  this.log(other.getPath.pts[2 * i], other.getPath.pts[2 * i + 1], other.getPath.types[i]);
@@ -16439,23 +16544,241 @@ function applyTint(src, hue, amount) {
16439
16544
  function applyRedEyeCorrection(src, width, height, areas) {
16440
16545
  const out = new Uint8ClampedArray(src);
16441
16546
  for (const a of areas) {
16442
- const x0 = clamp(a.left, 0, width);
16443
- const x1 = clamp(a.right, 0, width);
16444
- const y0 = clamp(a.top, 0, height);
16445
- const y1 = clamp(a.bottom, 0, height);
16446
- for (let y = y0; y < y1; y++) {
16447
- for (let x = x0; x < x1; x++) {
16448
- const i = (y * width + x) * 4;
16449
- const r = out[i];
16450
- const g = out[i + 1];
16451
- const b = out[i + 2];
16452
- if (r >= 2 * g && r >= 2 * b && r > 64) {
16453
- out[i] = Math.round((g + b) / 2);
16547
+ correctRedEyeArea(out, width, clamp(a.left, 0, width), clamp(a.top, 0, height), clamp(a.right, 0, width), clamp(a.bottom, 0, height));
16548
+ }
16549
+ return out;
16550
+ }
16551
+ var RED_EYE_FALLOFF = new Float64Array(
16552
+ [
16553
+ 24930,
16554
+ 24570,
16555
+ 24201,
16556
+ 23836,
16557
+ 23471,
16558
+ 23107,
16559
+ 22744,
16560
+ 22367,
16561
+ 21976,
16562
+ 21587,
16563
+ 21198,
16564
+ 20824,
16565
+ 20490,
16566
+ 20165,
16567
+ 19832,
16568
+ 19499,
16569
+ 19157,
16570
+ 18817,
16571
+ 18480,
16572
+ 18151,
16573
+ 17820,
16574
+ 17490,
16575
+ 17160,
16576
+ 16831,
16577
+ 16506,
16578
+ 16189,
16579
+ 15878,
16580
+ 15569,
16581
+ 15273,
16582
+ 14973,
16583
+ 14668,
16584
+ 14362,
16585
+ 14059,
16586
+ 13768,
16587
+ 13484,
16588
+ 13203,
16589
+ 12923,
16590
+ 12642,
16591
+ 12366,
16592
+ 12094,
16593
+ 11828,
16594
+ 11564,
16595
+ 11301,
16596
+ 11034,
16597
+ 10770,
16598
+ 10507,
16599
+ 10253,
16600
+ 10011,
16601
+ 9771,
16602
+ 9530,
16603
+ 9290,
16604
+ 9053,
16605
+ 8819,
16606
+ 8588,
16607
+ 8359,
16608
+ 8134,
16609
+ 7914,
16610
+ 7697,
16611
+ 7481,
16612
+ 7267,
16613
+ 7056,
16614
+ 6851,
16615
+ 6651,
16616
+ 6453,
16617
+ 6256,
16618
+ 6061,
16619
+ 5871,
16620
+ 5684,
16621
+ 5499,
16622
+ 5317,
16623
+ 5138,
16624
+ 4962,
16625
+ 4789,
16626
+ 4619,
16627
+ 4452,
16628
+ 4289,
16629
+ 4130,
16630
+ 3974,
16631
+ 3820,
16632
+ 3669,
16633
+ 3520,
16634
+ 3375,
16635
+ 3232,
16636
+ 3093,
16637
+ 2958,
16638
+ 2825,
16639
+ 2695,
16640
+ 2568,
16641
+ 2444,
16642
+ 2325,
16643
+ 2207,
16644
+ 2092,
16645
+ 1980,
16646
+ 1872,
16647
+ 1768,
16648
+ 1666,
16649
+ 1567,
16650
+ 1470,
16651
+ 1377,
16652
+ 1287,
16653
+ 1200,
16654
+ 1116,
16655
+ 1034,
16656
+ 956,
16657
+ 881,
16658
+ 808,
16659
+ 739,
16660
+ 674,
16661
+ 612,
16662
+ 541,
16663
+ 462,
16664
+ 381,
16665
+ 299,
16666
+ 220,
16667
+ 147,
16668
+ 85,
16669
+ 36,
16670
+ 3,
16671
+ 0
16672
+ ].map((v) => v / 1e5)
16673
+ );
16674
+ function redEyeFalloff(u) {
16675
+ const t = u * 128;
16676
+ const i = Math.floor(t);
16677
+ if (i >= RED_EYE_FALLOFF.length - 1) {
16678
+ return 0;
16679
+ }
16680
+ return RED_EYE_FALLOFF[i] + (t - i) * (RED_EYE_FALLOFF[i + 1] - RED_EYE_FALLOFF[i]);
16681
+ }
16682
+ var RED_EYE_SECTORS = 60;
16683
+ var RED_EYE_BLUE_WEIGHT = 0.225;
16684
+ var RED_EYE_WEIGHT_CAP = 6;
16685
+ var RED_EYE_PURE_WEIGHT = RED_EYE_WEIGHT_CAP;
16686
+ var RED_EYE_DARK_STRENGTH = 0.49;
16687
+ var RED_EYE_DARK_RATIO = 0.6;
16688
+ var RED_EYE_GREEN_SHARE = 80 / 255;
16689
+ function correctRedEyeArea(out, stride, x0, y0, x1, y1) {
16690
+ const w = x1 - x0;
16691
+ const h = y1 - y0;
16692
+ const count = w * h;
16693
+ const redness = new Float64Array(count);
16694
+ const dark = new Float64Array(count);
16695
+ let sx = 0;
16696
+ let sy = 0;
16697
+ let sw = 0;
16698
+ for (let y = 0; y < h; y++) {
16699
+ for (let x = 0; x < w; x++) {
16700
+ const i = ((y0 + y) * stride + x0 + x) * 4;
16701
+ const r = out[i];
16702
+ const g = out[i + 1];
16703
+ const b = out[i + 2];
16704
+ const k = y * w + x;
16705
+ dark[k] = Math.min(g, b);
16706
+ const v = r - Math.max(g, b);
16707
+ if (v > 0) {
16708
+ redness[k] = v;
16709
+ const denominator = g + RED_EYE_BLUE_WEIGHT * b;
16710
+ {
16711
+ const weight = denominator >= 1 ? Math.min(RED_EYE_WEIGHT_CAP, v / denominator) : RED_EYE_PURE_WEIGHT;
16712
+ sx += weight * (x + 0.5);
16713
+ sy += weight * (y + 0.5);
16714
+ sw += weight;
16454
16715
  }
16455
16716
  }
16456
16717
  }
16457
16718
  }
16458
- return out;
16719
+ if (sw === 0) {
16720
+ if (!redness.some((v) => v > 0)) {
16721
+ return;
16722
+ }
16723
+ sx = w / 2;
16724
+ sy = h / 2;
16725
+ sw = 1;
16726
+ }
16727
+ const cx = sx / sw;
16728
+ const cy = sy / sw;
16729
+ const radius = Math.min(cx, cy) - 0.5;
16730
+ if (!(radius > 0)) {
16731
+ return;
16732
+ }
16733
+ const sector = new Uint8Array(count);
16734
+ const distance = new Float64Array(count);
16735
+ const sectorSum = new Float64Array(RED_EYE_SECTORS);
16736
+ const sectorDark = new Float64Array(RED_EYE_SECTORS);
16737
+ const sectorCount = new Float64Array(RED_EYE_SECTORS);
16738
+ const degrees = 180 / Math.PI;
16739
+ for (let y = 0; y < h; y++) {
16740
+ for (let x = 0; x < w; x++) {
16741
+ const dx = x + 0.5 - cx;
16742
+ const dy = y + 0.5 - cy;
16743
+ const k = y * w + x;
16744
+ const d = Math.hypot(dx, dy);
16745
+ distance[k] = d;
16746
+ let angle = Math.atan2(dy, dx) * degrees;
16747
+ if (angle < 0) {
16748
+ angle += 360;
16749
+ }
16750
+ const s = Math.min(RED_EYE_SECTORS - 1, Math.floor(angle / 6));
16751
+ sector[k] = s;
16752
+ if (d < radius) {
16753
+ sectorSum[s] += redness[k];
16754
+ sectorDark[s] += dark[k];
16755
+ sectorCount[s]++;
16756
+ }
16757
+ }
16758
+ }
16759
+ for (let y = 0; y < h; y++) {
16760
+ for (let x = 0; x < w; x++) {
16761
+ const k = y * w + x;
16762
+ const v = redness[k];
16763
+ if (v <= 0 || distance[k] >= radius) {
16764
+ continue;
16765
+ }
16766
+ const s = sector[k];
16767
+ const mean = sectorSum[s] / sectorCount[s];
16768
+ const meanDark = sectorDark[s] / sectorCount[s];
16769
+ const ratio = meanDark > 0 ? dark[k] / meanDark : 1;
16770
+ const falloff = Math.max(redEyeFalloff(distance[k] / radius), RED_EYE_DARK_STRENGTH * Math.max(0, 1 - ratio / RED_EYE_DARK_RATIO));
16771
+ const rest = (1 - falloff) * mean;
16772
+ if (rest >= v) {
16773
+ continue;
16774
+ }
16775
+ const removed = v - rest;
16776
+ const i = ((y0 + y) * stride + x0 + x) * 4;
16777
+ out[i] = Math.round(out[i] - (1 - RED_EYE_GREEN_SHARE) * removed);
16778
+ out[i + 1] = Math.round(out[i + 1] + RED_EYE_GREEN_SHARE * removed);
16779
+ out[i + 2] = Math.round(out[i + 2] + RED_EYE_GREEN_SHARE * removed);
16780
+ }
16781
+ }
16459
16782
  }
16460
16783
  function blurKernel(radius) {
16461
16784
  const taps = Math.ceil(radius);
@@ -16487,8 +16810,8 @@ function mirror(p, n) {
16487
16810
  function gdipBlur(src, w, h, radius, vRow = 0, vZeroAbove = false, verticalRows = Math.ceil(h / w)) {
16488
16811
  const k = blurKernel(radius);
16489
16812
  const taps = (k.length - 1) / 2;
16490
- const horizontalIndex = taps >= w ? (x) => Math.max(0, Math.min(w - 1, x)) : (x) => mirror(x, w);
16491
- const verticalIndex = taps >= h ? (y) => Math.max(0, Math.min(h - 1, y)) : (y) => mirror(y, h);
16813
+ const horizontalIndex = (taps | 1) >= w ? (x) => Math.max(0, Math.min(w - 1, x)) : (x) => mirror(x, w);
16814
+ const verticalIndex = (taps | 1) >= h ? (y) => Math.max(0, Math.min(h - 1, y)) : (y) => mirror(y, h);
16492
16815
  const out = new Float64Array(w * h * 4);
16493
16816
  for (let y = 0; y < h; y++) {
16494
16817
  const row2 = y * w * 4;
@@ -16499,11 +16822,12 @@ function gdipBlur(src, w, h, radius, vRow = 0, vZeroAbove = false, verticalRows
16499
16822
  let s3 = 0;
16500
16823
  for (let j = -taps; j <= taps; j++) {
16501
16824
  const p = row2 + horizontalIndex(x + j) * 4;
16502
- const kw = k[j + taps] * 256;
16503
- s0 += Math.round(kw * src[p]);
16504
- s1 += Math.round(kw * src[p + 1]);
16505
- s2 += Math.round(kw * src[p + 2]);
16506
- s3 += Math.round(kw * src[p + 3]);
16825
+ const kw = j === 0 ? k[taps] * 128 : k[j + taps] * 256;
16826
+ const times = j === 0 ? 2 : 1;
16827
+ s0 += times * Math.round(kw * src[p]);
16828
+ s1 += times * Math.round(kw * src[p + 1]);
16829
+ s2 += times * Math.round(kw * src[p + 2]);
16830
+ s3 += times * Math.round(kw * src[p + 3]);
16507
16831
  }
16508
16832
  const o = row2 + x * 4;
16509
16833
  out[o] = Math.floor((s0 + 128) / 256);
@@ -16523,8 +16847,10 @@ function gdipBlur(src, w, h, radius, vRow = 0, vZeroAbove = false, verticalRows
16523
16847
  continue;
16524
16848
  }
16525
16849
  const base = verticalIndex(yy) * w * 4;
16850
+ const kw = j === 0 ? k[taps] * 128 : k[j + taps] * 256;
16851
+ const times = j === 0 ? 2 : 1;
16526
16852
  for (let i = 0; i < w * 4; i++) {
16527
- col[i] += Math.round(k[j + taps] * horizontal[base + i] * 256) / 256;
16853
+ col[i] += times * Math.round(kw * horizontal[base + i]) / 256;
16528
16854
  }
16529
16855
  }
16530
16856
  out.set(col, row2 * w * 4);
@@ -16539,10 +16865,12 @@ function blurAxis(length, lanes, factor, k, edgeLength, get, put, span = { start
16539
16865
  const inner = Math.ceil(span.size / factor);
16540
16866
  const n = inner + 2 * span.pad;
16541
16867
  const taps = (k.length - 1) / 2;
16542
- const index = taps >= edgeLength ? (i) => clamp(i, 0, n - 1) : (i) => mirror(i, n);
16868
+ const index = (taps | 1) >= edgeLength ? (i) => clamp(i, 0, n - 1) : (i) => mirror(i, n);
16543
16869
  const reduced = new Float64Array(n);
16544
16870
  const filtered = new Float64Array(n);
16545
16871
  const k256 = k.map((w) => w * 256);
16872
+ const half = k256[taps] / 2;
16873
+ k256[taps] = 0;
16546
16874
  for (let lane = 0; lane < lanes; lane++) for (let c = 0; c < 4; c++) {
16547
16875
  for (let b = span.pad; b < span.pad + inner; b++) {
16548
16876
  const from = span.start + (b - span.pad) * factor;
@@ -16556,33 +16884,48 @@ function blurAxis(length, lanes, factor, k, edgeLength, get, put, span = { start
16556
16884
  if (b >= taps && b + taps < n) {
16557
16885
  for (let j = 0; j < k256.length; j++) sum += Math.round(k256[j] * reduced[b - taps + j]);
16558
16886
  } else {
16559
- for (let j = 0; j < k256.length; j++) sum += Math.round(k256[j] * reduced[index(b - taps + j)]);
16887
+ for (let j = 0; j < k256.length; j++) {
16888
+ const at = b - taps + j;
16889
+ sum += Math.round(k256[j] * (span.zeroOutside && (at < 0 || at >= n) ? 0 : reduced[index(at)]));
16890
+ }
16560
16891
  }
16892
+ sum += 2 * Math.round(half * reduced[b]);
16561
16893
  filtered[b] = Math.floor((sum + 128) / 256);
16562
16894
  }
16895
+ const lone = inner === 1 && span.pad > 0;
16896
+ const skipped2 = inner === 1 && span.size - Math.ceil(factor / 2) === 1 ? span.start + span.size - 1 : -1;
16563
16897
  for (let i = 0; i < length; i++) {
16564
- const p = (i - span.start + 0.5) / factor - 0.5 + span.pad;
16565
- const a = clamp(Math.floor(p), 0, Math.max(0, n - 2));
16898
+ if (i === skipped2) {
16899
+ if (span.pad > 0) put(i, lane, c, 0);
16900
+ continue;
16901
+ }
16902
+ const p = (i - span.start + 0.5) / factor - 0.5;
16903
+ if (lone) {
16904
+ const distance = Math.abs(i - span.start - (Math.min(span.size, factor / 2) - 0.5)) / factor;
16905
+ put(i, lane, c, clamp(Math.floor((1 + distance) * filtered[span.pad] + 1e-9), 0, 255));
16906
+ continue;
16907
+ }
16908
+ const a = clamp(Math.floor(p), 0, Math.max(0, inner - 2));
16566
16909
  const t = p - a;
16567
- put(i, lane, c, clamp(Math.floor((1 - t) * filtered[a] + t * filtered[Math.min(n - 1, a + 1)] + 1e-9), 0, 255));
16910
+ put(i, lane, c, clamp(Math.floor((1 - t) * filtered[span.pad + a] + t * filtered[span.pad + Math.min(inner - 1, a + 1)] + 1e-9), 0, 255));
16568
16911
  }
16569
16912
  }
16570
16913
  }
16571
- function effectBlur(src, width, height, radius, region) {
16914
+ function effectBlur(src, width, height, radius, region, expanded = false) {
16572
16915
  const factor = blurReduction(radius);
16573
16916
  if (factor === 1) {
16574
16917
  return gdipBlur(src, width, height, radius);
16575
16918
  }
16576
16919
  const k = blurKernel(radius / factor);
16577
16920
  const pad = region ? Math.ceil(Math.ceil(radius) / factor) : 0;
16578
- const spanX = region ? { start: region.x, size: region.w, pad } : void 0;
16579
- const spanY = region ? { start: region.y, size: region.h, pad } : void 0;
16580
- const rows = new Uint8Array(src.length);
16581
- blurAxis(width, height, factor, k, Math.floor(width / factor), (i, lane, c) => src[(lane * width + i) * 4 + c], (i, lane, c, v) => {
16921
+ const spanX = region ? { start: region.x, size: region.w, pad, zeroOutside: true } : expanded ? { start: 0, size: width, pad: 0, zeroOutside: true } : void 0;
16922
+ const spanY = region ? { start: region.y, size: region.h, pad, zeroOutside: true } : expanded ? { start: 0, size: height, pad: 0, zeroOutside: true } : void 0;
16923
+ const rows = new Uint8Array(src);
16924
+ blurAxis(width, height, factor, k, Math.ceil(width / factor), (i, lane, c) => src[(lane * width + i) * 4 + c], (i, lane, c, v) => {
16582
16925
  rows[(lane * width + i) * 4 + c] = v;
16583
16926
  }, spanX);
16584
- const out = new Float64Array(src.length);
16585
- blurAxis(height, width, factor, k, Math.floor(height / factor), (i, lane, c) => rows[(i * width + lane) * 4 + c], (i, lane, c, v) => {
16927
+ const out = Float64Array.from(rows);
16928
+ blurAxis(height, width, factor, k, Math.ceil(height / factor), (i, lane, c) => rows[(i * width + lane) * 4 + c], (i, lane, c, v) => {
16586
16929
  out[(i * width + lane) * 4 + c] = v;
16587
16930
  }, spanY);
16588
16931
  return out;
@@ -16670,7 +17013,7 @@ function expandedBlur(rgba, width, height, radius, x0, y0, x1, y1, cropped) {
16670
17013
  const gy1 = Math.min(height, y1 + r);
16671
17014
  copyBlock(rgba, width, gx0, gy0, gx1 - gx0, gy1 - gy0, buf, bw, gx0 - (x0 - r), gy0 - (y0 - r));
16672
17015
  }
16673
- const blurred = blurReduction(radius) > 1 ? effectBlur(buf, bw, bh, radius, cropped ? { x: r, y: r, w: x1 - x0, h: y1 - y0 } : void 0) : gdipBlur(buf, bw, bh, radius, cropped ? r : 0, cropped, Math.ceil((y1 - y0) / (x1 - x0)));
17016
+ const blurred = blurReduction(radius) > 1 ? effectBlur(buf, bw, bh, radius, cropped ? { x: r, y: r, w: x1 - x0, h: y1 - y0 } : void 0, true) : gdipBlur(buf, bw, bh, radius, cropped ? r : 0, cropped, Math.ceil((y1 - y0) / (x1 - x0)));
16674
17017
  const w = x1 - x0;
16675
17018
  const out = new Uint8ClampedArray(w * (y1 - y0) * 4);
16676
17019
  for (let y = 0; y < y1 - y0; y++) {
@@ -28735,118 +29078,19 @@ var HOBBY = [
28735
29078
  [[8, -48], [-8, -48], [-24, -40], [-40, -24], [-48, -8], [-48, 8], [-40, 24], [-24, 40], [-8, 48], [8, 48], [24, 40], [40, 24], [48, 8], [48, -8], [40, -24], [24, -40]]
28736
29079
  ];
28737
29080
  var HOBBY_LIMIT = 104;
28738
- var FLAT_SECTOR_BIAS = {
28739
- 7: [9, "cf..", "edededEdcDcdcd"],
28740
- 8: [9, "dFee", "ededededbdbdbd"],
28741
- 9: [9, "df..", "ddddddddbDbdbd"],
28742
- 10: [9, "de..", "dededeDebEbebE"],
28743
- 11: [9, "ce..", "eeeeeeEececece"],
28744
- 12: [13, "ce..", "eeeeeeeeeeeececEcecece"],
28745
- 13: [17, "ce..", "eeeeededdddddeDebebebdbdcdcdce"],
28746
- 14: [17, "df..", "ddedeeeededeeeedcDcebebecececd"],
28747
- 15: [17, "dF..", "ddedeeeeeeeedeDdbdbecececececd"],
28748
- 16: [17, "ce..", "eeeededededeeeeececebebebebece"],
28749
- 17: [17, "df..", "ddedededededdeddbdbebdbdbdbdcd"],
28750
- 18: [17, "de..", "deeededeededeeEdcDcecdcdbebece"],
28751
- 19: [17, "cf..", "ededeeeedddddeDebEbecdcdbebecd"],
28752
- 20: [17, "ce..", "eeeeddddeeeeddDdbdbdcecebdbdce"],
28753
- 21: [17, "dF..", "ddddededededddDdbdbdcdcdcdcdbd"],
28754
- 22: [17, "ce..", "eeeededeeeeedeDebebececebebece"],
28755
- 23: [17, "cf..", "edededededededEdcDcdcdcdcdcdcD"],
28756
- 24: [17, "dF..", "ddddddddddddddDdbdbdbdbdbdbdbd"],
28757
- 25: [17, "cE..", "eeeeededededeeEecEcecdcdcdcdce"],
28758
- 26: [17, "cf..", "ededdedeededdedebEbecdcdbebecd"],
28759
- 27: [17, "de..", "dedeededdedeededcDcdbebecdcdbe"],
28760
- 28: [17, "cf..", "ededddddeeeedeDebEbebebecdcdcd"],
28761
- 29: [17, "ce..", "eeeeeeeededededebebebebececece"],
28762
- 30: [17, "dF..", "dddddedeeeeeedEdcdcdcecebebebd"],
28763
- 31: [17, "de..", "dedeededededdeDebebecdcdcdcdbe"],
28764
- 32: [17, "cf..", "ededdededdddeeeecEcebdbdbebecd"],
28765
- 33: [17, "de..", "dedeeeeeededddDdbdbdcdcdcecebe"],
28766
- 34: [17, "de..", "dedeeeeeddddedEdcdcdbdbdcecebe"],
28767
- 35: [17, "cf..", "ededededdededeDebebebebecdcdcd"],
28768
- 36: [17, "deee", "eeeeeeeeddddddDdcdcdcdcDbebebe"],
28769
- 37: [17, "dF..", "dddddededededdDdbdbdcecececebd"],
28770
- 38: [17, "ce..", "eeeeddddddddeeEececebdbdbdbdce"],
28771
- 39: [17, "cF..", "ededddddddddededcdcdbdbDbdbdcd"],
28772
- 40: [17, "de..", "dededededdddddddbdbdbdbdbebebe"],
28773
- 41: [17, "ce..", "eeeeeeeeeeeeeeEececececececece"],
28774
- 42: [17, "cf..", "ededeeeedddddedebebebdbdcececd"],
28775
- 43: [17, "df..", "ddddeeeededeedEdcdcdbebececebd"],
28776
- 44: [17, "cF..", "ededdedeededdeDebebecdcdbebecd"],
28777
- 45: [17, "ce..", "eeeededededeeeeecEcebebebebece"],
28778
- 46: [17, "dF..", "ddddededddddedEdcDcdcdcdbdbdbd"],
28779
- 47: [17, "ce..", "dedededededededececececececece"],
28780
- 48: [25, "cf..", "ededeeeeeeeeededeeeeeeEecececececdcdcececececd"],
28781
- 49: [25, "cF..", "ededddddededeeeeededdeDebebecdcdcececdcdbdbdcd"],
28782
- 50: [25, "ce..", "eeeeddddededdededededeDebebebebebEbecdcdbdbdce"],
28783
- 51: [25, "ce..", "eeeeededddddeeeededeeeEececebebececebdbdcdcdce"],
28784
- 52: [25, "ce..", "eeeededededeededededeeEecececdcdcdcdbebebebece"],
28785
- 53: [25, "dF..", "ddedeeeedddddddddedeeeEdcdcebebebdbDbdbdcececd"],
28786
- 54: [25, "dF..", "ddedddddededededdddddEDdbdbebdbdcdcdcdcdbdbdcd"],
28787
- 55: [25, "dF..", "ddeddedeeeeeeeeedededeDdbdbebebebebebebebebecd"],
28788
- 56: [25, "dE..", "deeeeeeeededeeeededeeEedcdcebebecececdcdcecece"],
28789
- 57: [25, "de..", "deeedddddddddedeededeeEdcDcecDcdcececdcdbdbDce"],
28790
- 58: [25, "dF..", "ddedddddeeeedddddedeeeEdcdcebebebdbdcecebdbdcd"],
28791
- 59: [33, "cF..", "ededdedeededddddeeeeeeeedddddeDebebebdbdcecececebdbdcdcdbebecd"],
28792
- 60: [33, "cf..", "ededeeeeededededddddeeeeeeeedeDebebececececebdbdcdcdcdcdcececd"],
28793
- 61: [33, "ce..", "eeeeeeeeddddeeeeeeeeddddeeeeeeeececececebdbdcecececebdbdcecece"],
28794
- 62: [33, "ce..", "eeeeddddeeeeededededeeeeddddeeEecEcebdbdcececdcdcdcdcecebdbdce"],
28795
- 63: [33, "cf..", "ededededeeeededededeeeeeeeeeeeEececececececebebEbebecececdcdcd"],
28796
- 64: [33, "cF..", "ededeeeedddddedeeeeededeeeeedeDebebececebebececebebebdbdcececd"],
28797
- 65: [33, "df..", "ddedededededddddddddeeeeeeeedeDdbdbececececebdbdbdbdcdcdcdcdcd"],
28798
- 66: [33, "de..", "deeeededdedeeeeedddddededddddeDdbdbebdbdbebecdcdbebebebecdcdce"],
28799
- 67: [33, "de..", "deeeddddddddededdddddededdddeeEdcDcebdbdbebebdbdcdcdbdbdbdbdce"],
28800
- 68: [33, "dE..", "deeeeeeeeeeeeeeeddddeeeeeeeeeeEdcdcececececebdbdcecececececece"],
28801
- 69: [33, "df..", "ddedededdedeeeeeddddededededdeDdbdbecdcdcdcdbdbdcecebebecdcdcd"],
28802
- 70: [33, "dF..", "ddeddddddddddddddededededddddeDdbdbebdbdbebebebebdbdbdbdbdbDcd"],
28803
- 71: [33, "ce..", "eeeeddddeeeededeeeeededeededdeDebebecdcdbebececebebececebdbdce"],
28804
- 72: [33, "ce..", "eeeededededeededededddddddddeeEececebdbdbdbdcdcdcdcdbebebebece"],
28805
- 73: [33, "ce..", "eeeeededededddddededdedeeeeeeeEececececebebecdcdbdbdcdcDcdcdce"],
28806
- 74: [33, "cf..", "ededddddededededededdededddddeDebebebdbdbebecdcDcdcdcdcdbdbdcd"],
28807
- 75: [33, "cF..", "ededdededededdddddddeeeedddddeDebebebdbdcececdcdcdcdbebebebecd"],
28808
- 76: [33, "ce..", "eeeeeeeeeeeeeeeeeeeededeeeeedeDebebececebebecececececececececE"],
28809
- 77: [33, "ce..", "eeeeeeeedededddddededdddedededEdcDcdcdcdbdbdbebebdbdbebececece"],
28810
- 78: [33, "de..", "dedeededdedededeeeeeeeeededeedEdcdcdbebececececebebebebecdcdbe"],
28811
- 79: [33, "dF..", "ddddddddededdededdddeeeeedededEdcDcdcdcdcecebdbdbebecdcdbdbdbd"],
28812
- 80: [33, "dF..", "dddddededdddeeeeddddddddededddDdbdbdcdcdbdbdbdbDcecebdbdbebEbd"],
28813
- 81: [33, "de..", "dedeeeeeeeeededeededeeeedededdDdbdbdbebecececdcdbebececececebe"],
28814
- 82: [33, "de..", "dedeededdedeededdedededeedededEdcdcdcdcdbebebebecdcdbebecdcDbe"],
28815
- 83: [33, "de..", "dededededddddededdddeeeededeeeEececebebececebdbdbebebdbdbebebe"],
28816
- 84: [33, "cF..", "ededddddeeeeddddeeeeeeeeededeeEecececdcdcecebebecdcdcecebdbdcd"],
28817
- 85: [33, "cf..", "ededdddddededddddddddedeeeeedeDebebececebebebdbdbdbdbebebdbdcd"],
28818
- 86: [33, "ce..", "eeeeededddddeeeeeeeedededededeDebebebebebebebebebebebdbdcdcdce"],
28819
- 87: [33, "ce..", "eeeeddddeeeeddddddddeeeeddddeeeececebdbdcecebdbDbdbdcecebdbdce"],
28820
- 88: [33, "ce..", "eeeedededdddeeeeededededededeeeecececdcdcdcdcdcdcecebdbdbebece"],
28821
- 89: [33, "cF..", "ededeeeeddddddddededdedededeeeEecEcebebEbebecdcdbdbdbdbdcececd"],
28822
- 90: [33, "dF..", "ddddededeeeeededeeeedededededdDdbdbdbebebEbecececdcdcececdcdbd"],
28823
- 91: [33, "df..", "ddddeeeededededeededdddddededdDdbdbdbebebdbdcdcdbebebebececebd"],
28824
- 92: [33, "de..", "dedededeededdddddededededdddedEdcdcdbdbdbebebebebdbdcdcdbebebe"],
28825
- 93: [33, "de..", "dededddddddddedeededeeeeeeeeededcdcdcececececdcdbebebdbdbdbdbe"],
28826
- 94: [33, "dF..", "ddddeeeeddddeeeeddddeeeededeedEdcDcdbebececebdbDcecebdbdcecebd"],
28827
- 95: [33, "df..", "ddddddddededeeeedddddededdddddDdbdbDbdbdbebecdcdbebecdcdbdbdbd"],
28828
- 96: [33, "cf..", "ededeeeededeeeeedededdddeeeedeDebebececebdbdbebececebebecececd"],
28829
- 97: [33, "ce..", "eeeedededededededdddeeeedddddeDebebebdbdcEcebdbdbebebEbebebece"],
28830
- 98: [33, "ce..", "eeeeededededeeeeeeeededededeeeEececebebebebecececececdcdcdcdce"],
28831
- 99: [33, "cf..", "ededededddddddddddddededdedeeeEececebebecdcdbdbdbdbdbdbdcdcdcd"],
28832
- 100: [33, "cf..", "ededdedeeeeededededeeeeeededdeDebebecdcdcecebebebebececebebecd"]
28833
- };
28834
- function sectorBias(code) {
28835
- return code >= 97 ? (code - 97) / 2 - 1.5 : (code - 65) / 2 - 1.5 - 1 / 64;
29081
+ function oddEdgeAdjustment(odd, firstEdge) {
29082
+ return odd ? firstEdge ? 0.5 : -0.5 : 0;
28836
29083
  }
28837
- var VERTICAL_STEP_EARLY = "120002002002002002202200200200200220220020000022222220000002222220000002222220000";
28838
- var VERTICAL_STEP_FIRST = 7;
28839
- function verticalSideOffset(width) {
28840
- if (width < HOBBY_LIMIT || width > 1400) {
28841
- return void 0;
29084
+ function floorDivision(a, b) {
29085
+ if (Number.isSafeInteger(a) && Number.isSafeInteger(b)) {
29086
+ return Math.floor(a / b);
28842
29087
  }
28843
- let m = VERTICAL_STEP_FIRST;
28844
- for (let i = 1; i < VERTICAL_STEP_EARLY.length; i++) {
28845
- if (width >= 16 * (i + VERTICAL_STEP_FIRST) - 7 - +VERTICAL_STEP_EARLY[i]) {
28846
- m = i + VERTICAL_STEP_FIRST;
28847
- }
29088
+ const A = BigInt(Math.round(a)), B = BigInt(Math.round(b));
29089
+ let q = A / B;
29090
+ if (A % B !== 0n && A < 0n !== B < 0n) {
29091
+ q -= 1n;
28848
29092
  }
28849
- return 8 * m;
29093
+ return Number(q);
28850
29094
  }
28851
29095
  var penCache = /* @__PURE__ */ new Map();
28852
29096
  function penPolygon(width) {
@@ -28918,6 +29162,9 @@ function perpendicularVectors(width, dx0, dy0) {
28918
29162
  best = i;
28919
29163
  }
28920
29164
  }
29165
+ if (flip && best === 0 && nx * pen[n - 1][0] + ny * pen[n - 1][1] === bh) {
29166
+ best = n - 1;
29167
+ }
28921
29168
  const P = pen[(best + n - 1) % n];
28922
29169
  const N = pen[(best + 1) % n];
28923
29170
  const D = pen[best];
@@ -28926,20 +29173,19 @@ function perpendicularVectors(width, dx0, dy0) {
28926
29173
  const [B, hB, hS] = hP >= hN ? [P, hP, hN] : [N, hN, hP];
28927
29174
  const den = 2 * (bh - hB + (bh - hS));
28928
29175
  const w = den === 0 ? 0 : (hB - hS) / den;
28929
- const r = (v) => 8 * Math.floor((v + 4) / 8);
28930
29176
  const x = D[0] + (B[0] - D[0]) * w, y = D[1] + (B[1] - D[1]) * w;
28931
- let cx = 0.5 * Math.sign(dy), cy = 0.5 * Math.sign(dx);
28932
- const table = width % 16 === 0 ? FLAT_SECTOR_BIAS[width / 16] : void 0;
28933
- if (table) {
28934
- const key = best * 2 + (hP >= hN ? 0 : 1);
28935
- const pair = key === 0 ? table[1].slice(0, 2) : key >= table[0] ? table[2].slice((key - table[0]) * 2, (key - table[0]) * 2 + 2) : "..";
28936
- if (pair[0] !== ".") {
28937
- cx = sectorBias(pair.charCodeAt(0));
28938
- cy = sectorBias(pair.charCodeAt(1));
28939
- }
28940
- }
28941
- const side = dx === 0 ? verticalSideOffset(width) : void 0;
28942
- const vx = side === void 0 ? r(x + cx) : -side, vy = r(y + cy);
29177
+ const signs = [dx === 0 ? 0 : Math.sign(dy), Math.sign(dx)];
29178
+ const firstEdge = best === 0 && hP >= hN;
29179
+ const num = hB - hS;
29180
+ const rounded = [0, 1].map((c) => {
29181
+ const bias2 = signs[c] + 2 * oddEdgeAdjustment(Math.abs(B[c] - D[c]) % 2 === 1, firstEdge);
29182
+ if (den === 0) {
29183
+ return 8 * (c === 1 && dy < 0 ? Math.ceil((D[c] + bias2 / 2 + 4) / 8) - 1 : Math.floor((D[c] + bias2 / 2 + 4) / 8));
29184
+ }
29185
+ const top = D[c] * den + (B[c] - D[c]) * num;
29186
+ return 8 * floorDivision(2 * top + den * (bias2 + 8) - (c === 1 && dy < 0 ? 1 : 0), 16 * den);
29187
+ });
29188
+ const vx = rounded[0], vy = rounded[1];
28943
29189
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
28944
29190
  }
28945
29191
  function squareExtension(width, dx, dy) {
@@ -28969,7 +29215,6 @@ var Outliner = class {
28969
29215
  this.n = this.pen.length;
28970
29216
  this.rr = opts.cap === "round" && opts.join === "round";
28971
29217
  this.originalRoundJoinSides = opts.join === "round" && opts.cap !== "flat";
28972
- this.roundJoinSides = !!opts.roundCurveJoins || this.originalRoundJoinSides;
28973
29218
  this.maxX = Math.max(...this.pen.map((q) => Math.abs(q[0])));
28974
29219
  }
28975
29220
  /**
@@ -28977,14 +29222,14 @@ var Outliner = class {
28977
29222
  * `drawDir` (a curve's end tangent) only picks the draw vertices, the
28978
29223
  * perpendicular following the chord (measured on Bezier ends).
28979
29224
  */
28980
- seg(a, b, dir, drawDir) {
29225
+ seg(a, b, dir, drawDir, curve = false) {
28981
29226
  const dx = dir ? dir[0] : b[0] - a[0];
28982
29227
  const dy = dir ? dir[1] : b[1] - a[1];
28983
29228
  const d = drawDir ?? [dx, dy];
28984
29229
  const [L, R] = drawVertices(this.pen, d[0], d[1]);
28985
- const perpendicular = this.opts.roundCurveJoins && drawDir ? drawDir : [dx, dy];
29230
+ const perpendicular = curve && drawDir ? drawDir : [dx, dy];
28986
29231
  const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1]);
28987
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, dx, dy), curveEnd: !!drawDir };
29232
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1]), curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
28988
29233
  }
28989
29234
  push(p, v) {
28990
29235
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29019,7 +29264,7 @@ var Outliner = class {
29019
29264
  * vertex exactly on `A`'s ray is included when `startIncl`, one on `B`'s
29020
29265
  * ray when `endIncl`.
29021
29266
  */
29022
- wedge(p, A, B, startIncl, endIncl) {
29267
+ wedge(p, A, B, startIncl, endIncl, tail = -1) {
29023
29268
  const TWO = Math.PI * 2;
29024
29269
  const aA = Math.atan2(A[1], A[0]);
29025
29270
  const angleOf = (Q) => {
@@ -29050,13 +29295,21 @@ var Outliner = class {
29050
29295
  }
29051
29296
  }
29052
29297
  list.sort((x, y) => x[0] - y[0]);
29298
+ if (tail >= 0 && !list.some(([, k]) => k === tail)) {
29299
+ list.push([Infinity, tail]);
29300
+ }
29053
29301
  for (const [, k] of list) {
29054
29302
  this.penAt(p, k);
29055
29303
  }
29056
29304
  }
29305
+ /** The pen's extreme-x vertex `k` that a steep segment `s` rests on, or -1 when the rule does not apply. */
29306
+ extremeTail(applies, k, s) {
29307
+ const q = this.pen[k];
29308
+ return applies && Math.abs(s.dy) > Math.abs(s.dx) && Math.abs(q[0]) === this.maxX && q[1] === 0 ? k : -1;
29309
+ }
29057
29310
  /** Side offset of segment `s` at a join. */
29058
29311
  joinSide(s, side) {
29059
- if (this.roundJoinSides) {
29312
+ if (this.originalRoundJoinSides || s.curve) {
29060
29313
  const q = this.pen[side === "L" ? s.L : s.R];
29061
29314
  return [halfPixel(q[0]), halfPixel(q[1])];
29062
29315
  }
@@ -29104,32 +29357,36 @@ var Outliner = class {
29104
29357
  */
29105
29358
  join(p, a, b, side, outer) {
29106
29359
  const { cap, width, miterLimit } = this.opts;
29107
- const join = this.opts.roundCurveJoins ? "round" : this.opts.join;
29360
+ const curveJoin = a.curve && b.curve;
29361
+ const join = curveJoin ? "round" : this.opts.join;
29362
+ const roundSides = this.originalRoundJoinSides || curveJoin;
29108
29363
  let sa = this.joinSide(a, side);
29109
29364
  let sb = this.joinSide(b, side);
29110
29365
  const rayA = side === "R" ? a.vRaw : [-a.vRaw[0], -a.vRaw[1]];
29111
29366
  const rayB = side === "R" ? b.vRaw : [-b.vRaw[0], -b.vRaw[1]];
29112
- if (this.opts.roundCurveJoins && !this.originalRoundJoinSides && a.curveEnd && b.curveEnd) {
29113
- sa = side === "R" ? a.v : [-a.v[0], -a.v[1]];
29114
- sb = side === "R" ? b.v : [-b.v[0], -b.v[1]];
29367
+ if (curveJoin && !this.originalRoundJoinSides && a.curveEnd && b.curveEnd) {
29368
+ const t = a.tangentLength >= b.tangentLength ? a : b;
29369
+ sa = sb = side === "R" ? t.v : [-t.v[0], -t.v[1]];
29115
29370
  }
29116
29371
  const Da = side === "R" ? a.R : a.L;
29117
29372
  const Db = side === "R" ? b.R : b.L;
29118
- if (this.roundJoinSides && (Da === Db || this.opts.roundCurveJoins && sa[0] === sb[0] && sa[1] === sb[1])) {
29373
+ if (roundSides && (Da === Db || curveJoin && sa[0] === sb[0] && sa[1] === sb[1])) {
29119
29374
  this.push(p, sa);
29120
29375
  return;
29121
29376
  }
29122
29377
  this.push(p, sa);
29123
29378
  if (outer) {
29124
29379
  if (join === "round") {
29125
- if (this.roundJoinSides) {
29380
+ if (roundSides) {
29126
29381
  const q = this.pen[Db];
29127
29382
  const steep = Math.abs(b.dy) > Math.abs(b.dx);
29128
29383
  const incl = side === "L" && steep && Math.abs(q[0]) === this.maxX && q[0] * q[1] <= 0;
29129
29384
  this.walk(p, Da, Db, false, incl);
29130
29385
  } else {
29131
29386
  const anti = sa[0] === -sb[0] && sa[1] === -sb[1];
29132
- this.wedge(p, rayA, rayB, !anti, !anti);
29387
+ if (Da !== Db || anti) {
29388
+ this.wedge(p, rayA, rayB, !anti, false, this.extremeTail(side === "L" && !anti, Db, b));
29389
+ }
29133
29390
  }
29134
29391
  } else if (join === "miter") {
29135
29392
  const m = miterPoint(sa, [a.dx, a.dy], sb, [b.dx, b.dy], width, miterLimit, side);
@@ -29139,14 +29396,16 @@ var Outliner = class {
29139
29396
  }
29140
29397
  } else {
29141
29398
  this.pts.push([p[0], p[1]]);
29142
- if (this.opts.roundCurveJoins && !this.originalRoundJoinSides) {
29399
+ if (curveJoin && !this.originalRoundJoinSides) {
29143
29400
  this.push(p, sb);
29144
29401
  this.push(p, sa);
29145
29402
  this.pts.push([p[0], p[1]]);
29146
29403
  }
29147
- if (join === "round" && cap === "flat" && !this.opts.roundCurveJoins) {
29404
+ if (join === "round" && cap === "flat" && !curveJoin) {
29148
29405
  this.push(p, sb);
29149
- this.wedge(p, rayB, rayA, false, false);
29406
+ if (Da !== Db) {
29407
+ this.wedge(p, rayB, rayA, false, false, this.extremeTail(side === "L", Da, a));
29408
+ }
29150
29409
  this.push(p, sa);
29151
29410
  this.pts.push([p[0], p[1]]);
29152
29411
  }
@@ -29179,17 +29438,17 @@ var Outliner = class {
29179
29438
  * lets a single point stand for a zero-length dash along `dirs[0]`;
29180
29439
  * `draws` (curve end tangents) picks draw vertices only.
29181
29440
  */
29182
- open(P, dirs, draws) {
29441
+ open(P, dirs, draws, curves) {
29183
29442
  if (P.length < 2 && !dirs?.[0]) {
29184
29443
  this.dot(P[0]);
29185
29444
  return;
29186
29445
  }
29187
29446
  const segs2 = [];
29188
29447
  for (let i = 0; i + 1 < P.length; i++) {
29189
- segs2.push(this.seg(P[i], P[i + 1], dirs?.[i], draws?.[i]));
29448
+ segs2.push(this.seg(P[i], P[i + 1], dirs?.[i], draws?.[i], curves?.[i]));
29190
29449
  }
29191
29450
  if (segs2.length === 0) {
29192
- const s = this.seg(P[0], P[0], dirs?.[0], draws?.[0]);
29451
+ const s = this.seg(P[0], P[0], dirs?.[0], draws?.[0], curves?.[0]);
29193
29452
  this.cap(P[0], s, true);
29194
29453
  this.cap(P[0], s, false);
29195
29454
  this.flush();
@@ -29220,11 +29479,11 @@ var Outliner = class {
29220
29479
  this.flush();
29221
29480
  }
29222
29481
  /** Outlines a closed polygon (distinct consecutive points, not repeating the first). */
29223
- closed(P, draws) {
29482
+ closed(P, draws, curves) {
29224
29483
  const m = P.length;
29225
29484
  const segs2 = [];
29226
29485
  for (let i = 0; i < m; i++) {
29227
- segs2.push(this.seg(P[i], P[(i + 1) % m], void 0, draws?.[i]));
29486
+ segs2.push(this.seg(P[i], P[(i + 1) % m], void 0, draws?.[i], curves?.[i]));
29228
29487
  }
29229
29488
  for (let j = 1; j <= m; j++) {
29230
29489
  const i = j % m;
@@ -29316,9 +29575,10 @@ function widenPath(path, opts) {
29316
29575
  const out = [];
29317
29576
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29318
29577
  for (const fig of path.figures) {
29319
- const outliner = new Outliner(fig.roundWiden ? { ...opts, roundCurveJoins: true } : opts, out);
29578
+ const outliner = new Outliner(opts, out);
29320
29579
  let P = [];
29321
29580
  const dirs = [];
29581
+ const curves = [];
29322
29582
  for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29323
29583
  const q = [fig.pts[i], fig.pts[i + 1]];
29324
29584
  const last = P[P.length - 1];
@@ -29327,6 +29587,7 @@ function widenPath(path, opts) {
29327
29587
  }
29328
29588
  if (last) {
29329
29589
  dirs.push(fig.tangents?.get(i / 2 - 1));
29590
+ curves.push(!!fig.roundWiden || !!fig.curveSegs?.has(i / 2 - 1));
29330
29591
  }
29331
29592
  P.push(q);
29332
29593
  }
@@ -29353,14 +29614,14 @@ function widenPath(path, opts) {
29353
29614
  pdraws.push(piece.draws[i - 1]);
29354
29615
  }
29355
29616
  }
29356
- outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]]);
29617
+ outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]], pts.map(() => !!fig.roundWiden));
29357
29618
  }
29358
29619
  } else if (closed && P.length >= 3) {
29359
- outliner.closed(P, dirs);
29620
+ outliner.closed(P, dirs, curves);
29360
29621
  } else if (closed && P.length === 2) {
29361
29622
  outliner.open([P[0], P[1], P[0]]);
29362
29623
  } else {
29363
- outliner.open(P, void 0, dirs);
29624
+ outliner.open(P, void 0, dirs, curves);
29364
29625
  }
29365
29626
  }
29366
29627
  return out;
@@ -31105,6 +31366,10 @@ function hasIlluminant(ca) {
31105
31366
  return illuminantCube(ca.illuminant) !== null;
31106
31367
  }
31107
31368
  var PALETTE = Array.from({ length: 32 }, (_, n) => Math.round(n * 255 / 31));
31369
+ function exactPaletteLevel(v) {
31370
+ const n = Math.round(v * 31 / 255);
31371
+ return PALETTE[n] === v ? 255 * n / 31 : v;
31372
+ }
31108
31373
  function paletteIndex(v) {
31109
31374
  const x = clamp012(v) * 255;
31110
31375
  let n = Math.min(30, Math.floor(x * 31 / 255));
@@ -31190,6 +31455,7 @@ function invert3(m) {
31190
31455
  }
31191
31456
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
31192
31457
  var clamp255 = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
31458
+ var roundHalfUp = (v) => Math.floor(v + 0.5 + 1e-7);
31193
31459
  function adjustChroma(r, g, b, scale, angle) {
31194
31460
  const x = RGB_TO_XYZ[0][0] * r + RGB_TO_XYZ[0][1] * g + RGB_TO_XYZ[0][2] * b;
31195
31461
  const y = RGB_TO_XYZ[1][0] * r + RGB_TO_XYZ[1][1] * g + RGB_TO_XYZ[1][2] * b;
@@ -31241,7 +31507,7 @@ function colorAdjustmentMapper(ca) {
31241
31507
  if (negative) {
31242
31508
  v = 255 - clamp255(v);
31243
31509
  }
31244
- return Math.round(clamp255(v));
31510
+ return roundHalfUp(clamp255(v));
31245
31511
  };
31246
31512
  if (!illuminant && !chroma) {
31247
31513
  const tables = [0, 1, 2].map((channel) => Uint8Array.from({ length: 256 }, (_, i) => curve(i, channel)));
@@ -31254,7 +31520,11 @@ function colorAdjustmentMapper(ca) {
31254
31520
  c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
31255
31521
  }
31256
31522
  if (chroma) {
31523
+ if (!illuminant) {
31524
+ c = c.map(exactPaletteLevel);
31525
+ }
31257
31526
  c = adjustChroma(clamp255(c[0]), clamp255(c[1]), clamp255(c[2]), scale, angle);
31527
+ c = c.map(roundHalfUp);
31258
31528
  }
31259
31529
  return curve(c[0], 0) << 16 | curve(c[1], 1) << 8 | curve(c[2], 2);
31260
31530
  };
@@ -31288,27 +31558,6 @@ function colorAdjustRgb(rgbs, ca) {
31288
31558
  rgbs[i + 2] = v & 255;
31289
31559
  }
31290
31560
  }
31291
- function applyColorAdjustment(pixels, ca) {
31292
- if (!ca || isIdentityColorAdjustment(ca)) {
31293
- return;
31294
- }
31295
- const map = colorAdjustmentMapper(ca);
31296
- const d = pixels.data;
31297
- const cache2 = /* @__PURE__ */ new Map();
31298
- for (let i = 0; i + 3 < d.length; i += 4) {
31299
- const rgb2 = d[i] << 16 | d[i + 1] << 8 | d[i + 2];
31300
- let v = cache2.get(rgb2);
31301
- if (v === void 0) {
31302
- v = map(rgb2);
31303
- if (cache2.size < 65536) {
31304
- cache2.set(rgb2, v);
31305
- }
31306
- }
31307
- d[i] = v >> 16 & 255;
31308
- d[i + 1] = v >> 8 & 255;
31309
- d[i + 2] = v & 255;
31310
- }
31311
- }
31312
31561
 
31313
31562
  // src/emf-gdi-halftone-dither.ts
31314
31563
  var THRESHOLDS = [
@@ -31467,22 +31716,22 @@ function halftoneAxis(start, srcLen, dstLen, reverse) {
31467
31716
  if (reverse) taps.reverse();
31468
31717
  return taps;
31469
31718
  }
31719
+ var REDUCE_BITS = 13;
31470
31720
  function halftoneReduceTaps(srcLen, dstLen, reverse) {
31471
31721
  if (dstLen >= srcLen) return halftoneAxis(0, srcLen, dstLen, reverse);
31722
+ const shares = 2 ** REDUCE_BITS;
31723
+ const scale = FIX / shares;
31472
31724
  const taps = [];
31473
31725
  for (let i = 0; i < dstLen; i++) {
31474
31726
  const from = i * srcLen;
31475
31727
  const to = (i + 1) * srcLen;
31476
31728
  const run = [];
31477
- let rest = 0;
31478
31729
  for (let k = Math.floor(from / dstLen); k * dstLen < to; k++) {
31479
- const overlap = Math.min(to, (k + 1) * dstLen) - Math.max(from, k * dstLen);
31480
- if (overlap <= 0) continue;
31481
- const w = Math.ceil(overlap * FIX / srcLen);
31482
- run.push([k, w]);
31483
- if (run.length > 1) rest += w;
31730
+ const lo = Math.max(from, k * dstLen) - from;
31731
+ const hi = Math.min(to, (k + 1) * dstLen) - from;
31732
+ if (hi <= lo) continue;
31733
+ run.push([k, (Math.floor(hi * shares / srcLen) - Math.floor(lo * shares / srcLen)) * scale]);
31484
31734
  }
31485
- if (run.length > 1) run[0][1] = FIX - rest;
31486
31735
  taps.push(run);
31487
31736
  }
31488
31737
  if (reverse) taps.reverse();
@@ -31556,7 +31805,7 @@ function halftoneEnlargeTaps(src, dst) {
31556
31805
  }
31557
31806
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
31558
31807
  for (let y = 0; y < h; y++) {
31559
- const yy = phaseY ? phaseY[y] : flipY ? h - 1 - y : y;
31808
+ const yy = phaseY ? phaseY[y] : y;
31560
31809
  for (let x = 0; x < w; x++) {
31561
31810
  const xx = phaseX ? phaseX[x] : x;
31562
31811
  const threshold = ditherThreshold(dither.startX, dither.startY, xx, yy);
@@ -31643,11 +31892,33 @@ function halftoneSharpen(px, w, h) {
31643
31892
  }
31644
31893
  }
31645
31894
  }
31895
+ function halftonePairDespeckle(px, w, h, rows) {
31896
+ const n = rows ? w : h;
31897
+ const at = (k, side) => (rows ? side * w + k : k * w + side) * 3;
31898
+ const same = (i, j) => px[i] === px[j] && px[i + 1] === px[j + 1] && px[i + 2] === px[j + 2];
31899
+ const checker = (k) => k >= 0 && k + 1 < n && same(at(k, 0), at(k + 1, 1)) && same(at(k, 1), at(k + 1, 0)) && !same(at(k, 0), at(k, 1));
31900
+ const mean = Array.from({ length: n }, (_, k) => checker(k - 1) || checker(k));
31901
+ for (let k = 0; k < n; k++) {
31902
+ if (!mean[k]) continue;
31903
+ const first = at(k, 0);
31904
+ const last = at(k, 1);
31905
+ for (let c = 0; c < 3; c++) px[first + c] = px[last + c] = px[first + c] + px[last + c] + 1 >> 1;
31906
+ }
31907
+ }
31908
+ function halftoneKeepLast(px, w, h, rows) {
31909
+ const n = rows ? w : h;
31910
+ const out = new Int32Array(n * 3);
31911
+ for (let k = 0; k < n; k++) {
31912
+ const last = (rows ? w + k : k * w + 1) * 3;
31913
+ for (let c = 0; c < 3; c++) out[k * 3 + c] = px[last + c];
31914
+ }
31915
+ return out;
31916
+ }
31646
31917
  function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false, dither, curves) {
31647
31918
  const W = Math.max(0, Math.round(Math.abs(dw)));
31648
31919
  const H = Math.max(0, Math.round(Math.abs(dh)));
31649
- const SW = Math.round(Math.abs(sw));
31650
- const SH = Math.round(Math.abs(sh));
31920
+ let SW = Math.round(Math.abs(sw));
31921
+ let SH = Math.round(Math.abs(sh));
31651
31922
  const x0 = Math.round(Math.min(sx, sx + sw));
31652
31923
  const y0 = Math.round(Math.min(sy, sy + sh));
31653
31924
  const flipX = dw < 0 !== sw < 0;
@@ -31656,7 +31927,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31656
31927
  if (W === 0 || H === 0 || SW === 0 || SH === 0) {
31657
31928
  return { width: W, height: H, data };
31658
31929
  }
31659
- const rect = new Int32Array(SW * SH * 3);
31930
+ let rect = new Int32Array(SW * SH * 3);
31660
31931
  for (let y = 0; y < SH; y++) {
31661
31932
  const yy = y0 + y;
31662
31933
  for (let x = 0; x < SW; x++) {
@@ -31671,19 +31942,40 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31671
31942
  rect[o + 2] = src.data[i + 2];
31672
31943
  }
31673
31944
  }
31945
+ const pairRows = SH === 2 && H === 1 && W > SW && (!adjust || adjustAfterSampling || !!dither);
31946
+ const pairColumns = SW === 2 && W === 1 && H > SH && (!adjust || adjustAfterSampling || !!dither);
31947
+ if (pairRows || pairColumns) {
31948
+ if (!directDib) halftonePairDespeckle(rect, SW, SH, pairRows);
31949
+ if (pairRows && W >= 2 * SW) {
31950
+ rect = halftoneKeepLast(rect, SW, SH, true);
31951
+ SH = 1;
31952
+ } else if (pairColumns && H >= 2 * SH) {
31953
+ rect = halftoneKeepLast(rect, SW, SH, false);
31954
+ SW = 1;
31955
+ }
31956
+ }
31674
31957
  const enlarging = W >= SW && H >= SH && (W > SW || H > SH);
31675
31958
  const reducing = W < SW && H < SH;
31676
31959
  const mixed = W > SW && H < SH || W < SW && H > SH;
31677
31960
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
31678
31961
  const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
31679
31962
  const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31680
- if ((enlarging || nearestMixed) && !directDib) {
31963
+ if ((enlarging || nearestMixed) && !directDib && !pairRows && !pairColumns) {
31681
31964
  halftoneDespeckle(rect, SW, SH);
31682
31965
  }
31683
31966
  const reducedEven = W < SW ? SW % 2 === 0 && H % SH === 0 : SH % 2 === 0 && W % SW === 0;
31684
31967
  const ditherAtSource = dithered && (W >= SW && H >= SH || nativeMixed && reducedEven);
31685
31968
  if (ditherAtSource) {
31686
- ditherPixels(rect, SW, SH, dither, false, flipY);
31969
+ ditherPixels(
31970
+ rect,
31971
+ SW,
31972
+ SH,
31973
+ dither,
31974
+ false,
31975
+ false,
31976
+ void 0,
31977
+ flipY ? Int32Array.from({ length: SH }, (_, j) => H - 1 - j) : void 0
31978
+ );
31687
31979
  }
31688
31980
  if (adjust && !adjustAfterSampling && (!dithered || ditherAtSource)) {
31689
31981
  adjust(rect);
@@ -31799,17 +32091,13 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31799
32091
  }
31800
32092
  }
31801
32093
  if (dithered && !ditherAtSource) {
31802
- const phase = (n, src2, dst, selectSource) => Int32Array.from({ length: n }, (_, i) => dst > src2 ? Math.floor(i * src2 / dst) : selectSource ? Math.max(0, Math.min(src2 - 1, Math.floor(((i + 1) * 2 * src2 - dst) / (2 * dst)))) : i);
31803
- ditherPixels(
31804
- out,
31805
- W,
31806
- H,
31807
- dither,
31808
- false,
31809
- false,
31810
- nearestMixed ? phase(W, SW, W, true) : void 0,
31811
- nearestMixed ? phase(H, SH, H, false) : void 0
31812
- );
32094
+ const phase = (n, src2, dst, selectSource) => Int32Array.from({ length: n }, (_, i) => dst > src2 ? Math.max(0, Math.ceil((2 * i + 1) * src2 / (2 * dst)) - 1) : selectSource ? Math.max(0, Math.min(src2 - 1, Math.floor(((i + 1) * 2 * src2 - dst) / (2 * dst)))) : i);
32095
+ const sourcePhase = nearestMixed && W * H > SW * SH;
32096
+ let phaseX = sourcePhase ? phase(W, SW, W, true) : void 0;
32097
+ let phaseY = sourcePhase ? phase(H, SH, H, false) : void 0;
32098
+ if (phaseX && flipX) phaseX = phaseX.slice().reverse();
32099
+ if (phaseY && flipY && H > SH) phaseY = phaseY.slice().reverse().map((v) => H - 1 - v);
32100
+ ditherPixels(out, W, H, dither, false, false, phaseX, phaseY);
31813
32101
  adjust(out);
31814
32102
  }
31815
32103
  if (adjust && adjustAfterSampling) adjust(out);
@@ -31872,7 +32160,7 @@ function drawSourceMapped(target, decoded, req, offsetX, offsetY, mode, brushOrg
31872
32160
  canvasDrawImage(target, tile.canvas, Math.round(dLeft), Math.round(dTop), px.width, px.height);
31873
32161
  target.restore();
31874
32162
  }
31875
- function decodeSource(rCtx, req) {
32163
+ function decodeSource(rCtx, req, rotated = false) {
31876
32164
  if (!req.source) {
31877
32165
  return null;
31878
32166
  }
@@ -31887,6 +32175,9 @@ function decodeSource(rCtx, req) {
31887
32175
  return null;
31888
32176
  }
31889
32177
  const ca = rCtx.state.colorAdjustment;
32178
+ if (req.stretch && rCtx.state.stretchBltMode === HALFTONE && rCtx.halftoneRotatedAdjusts === void 0) {
32179
+ rCtx.halftoneRotatedAdjusts = !rotated && !!ca;
32180
+ }
31890
32181
  const halftone = req.stretch && rCtx.state.stretchBltMode === HALFTONE && ca;
31891
32182
  const channelOnly = isChannelOnlyColorAdjustment(ca);
31892
32183
  const split = halftone && !channelOnly ? splitColorAdjustment(ca) : void 0;
@@ -32034,6 +32325,7 @@ function executeRotatedBlit(rCtx, logDx, logDy, logDw, logDh, rop, source, sx, s
32034
32325
  let src = null;
32035
32326
  let srcX = sx;
32036
32327
  let srcY = sy;
32328
+ let adjustTexel;
32037
32329
  if (operands.usesS) {
32038
32330
  const decoded = decodeSource(rCtx, {
32039
32331
  plan: { kind: "ternary", index, operands },
@@ -32048,13 +32340,30 @@ function executeRotatedBlit(rCtx, logDx, logDy, logDw, logDh, rop, source, sx, s
32048
32340
  sh,
32049
32341
  dibOrigin,
32050
32342
  stretch
32051
- });
32343
+ }, true);
32052
32344
  if (!decoded) {
32053
32345
  return;
32054
32346
  }
32055
32347
  src = decoded.decoded.pixels;
32056
- if (decoded.decoded.adjust) {
32057
- applyColorAdjustment(src, rCtx.state.colorAdjustment);
32348
+ if (decoded.decoded.adjust && rCtx.halftoneRotatedAdjusts) {
32349
+ const { adjust, adjustAfterSampling, curves } = decoded.decoded;
32350
+ const startX = ditherStartX(0, rCtx.state.brushOrgX);
32351
+ const startY = ditherStartY(0, rCtx.state.brushOrgY);
32352
+ const triple = new Int32Array(3);
32353
+ adjustTexel = (rgb2, x, y) => {
32354
+ triple[0] = rgb2 >> 16 & 255;
32355
+ triple[1] = rgb2 >> 8 & 255;
32356
+ triple[2] = rgb2 & 255;
32357
+ if (!adjustAfterSampling) {
32358
+ const t = ditherThreshold(startX, startY, x, y);
32359
+ for (let c = 0; c < 3; c++) {
32360
+ triple[c] = ditherQuantize(triple[c], t);
32361
+ }
32362
+ }
32363
+ adjust(triple);
32364
+ curves?.(triple);
32365
+ return triple[0] << 16 | triple[1] << 8 | triple[2];
32366
+ };
32058
32367
  }
32059
32368
  srcX = decoded.req.sx;
32060
32369
  srcY = decoded.req.sy;
@@ -32078,7 +32387,10 @@ function executeRotatedBlit(rCtx, logDx, logDy, logDw, logDh, rop, source, sx, s
32078
32387
  sw,
32079
32388
  sh,
32080
32389
  (ix, iy, x, y, d) => {
32081
- const s = operands.usesS ? texel(ix, iy) : 0;
32390
+ let s = operands.usesS ? texel(ix, iy) : 0;
32391
+ if (adjustTexel && operands.usesS) {
32392
+ s = adjustTexel(s, x, y);
32393
+ }
32082
32394
  const p = typeof pattern === "function" ? pattern(x, y) : pattern;
32083
32395
  return evalRop3(index, p, s, d);
32084
32396
  }
@@ -32133,6 +32445,19 @@ function alignMirroredDest(rCtx, req) {
32133
32445
  dy: req.dh < 0 ? req.dy + pxY : req.dy
32134
32446
  };
32135
32447
  }
32448
+ function executePlgBltAsStretch(rCtx, dx, dy, dw, dh, source, r) {
32449
+ executeBlit(rCtx, {
32450
+ plan: classifyRop3(13369376),
32451
+ dx,
32452
+ dy,
32453
+ dw,
32454
+ dh,
32455
+ source,
32456
+ ...r,
32457
+ dibOrigin: "top-left",
32458
+ stretch: true
32459
+ });
32460
+ }
32136
32461
  function executeBlit(rCtx, request) {
32137
32462
  const { ctx } = rCtx;
32138
32463
  const req = alignMirroredDest(rCtx, request);
@@ -32635,6 +32960,18 @@ function handlePlgBlt(rCtx, offset, dataOff, recSize) {
32635
32960
  if (b[1] === a[1] && q[0] === a[0]) {
32636
32961
  const W = Math.round(Math.abs(b[0] - a[0]) / 16);
32637
32962
  const H = Math.round(Math.abs(q[1] - a[1]) / 16);
32963
+ if (!mask && rCtx.state.stretchBltMode === HALFTONE && W > 0 && H > 0) {
32964
+ executePlgBltAsStretch(
32965
+ rCtx,
32966
+ Math.round(a[0] / 16),
32967
+ Math.round(a[1] / 16),
32968
+ b[0] < a[0] ? -W : W,
32969
+ q[1] < a[1] ? -H : H,
32970
+ sourceOf(offset, view.getUint32(dataOff + 88, true), view.getUint32(dataOff + 92, true), view.getUint32(dataOff + 96, true), view.getUint32(dataOff + 100, true), view.getUint32(dataOff + 84, true)),
32971
+ r
32972
+ );
32973
+ return;
32974
+ }
32638
32975
  const left = Math.round(a[0] / 16) + (b[0] < a[0] ? 1 - W : 0);
32639
32976
  const top = Math.round(a[1] / 16) + (q[1] < a[1] ? 1 - H : 0);
32640
32977
  const aw = Math.abs(r.sw);
@@ -32655,6 +32992,9 @@ function handlePlgBlt(rCtx, offset, dataOff, recSize) {
32655
32992
  });
32656
32993
  return;
32657
32994
  }
32995
+ if (rCtx.state.stretchBltMode === HALFTONE && rCtx.halftoneRotatedAdjusts === void 0) {
32996
+ rCtx.halftoneRotatedAdjusts = false;
32997
+ }
32658
32998
  paintParallelogram(rCtx, a, b, q, r.sw, r.sh, (ix, iy) => texel(ix, iy));
32659
32999
  }
32660
33000
  function readBand(rCtx, offset, offBmi, cbBmi, offBits, cbBits, usage, scans) {
@@ -34783,6 +35123,7 @@ function flattenBracketPath(rCtx) {
34783
35123
  }
34784
35124
  for (const f of rCtx.rasterPath.figures) {
34785
35125
  delete f.tangents;
35126
+ delete f.curveSegs;
34786
35127
  delete f.roundWiden;
34787
35128
  }
34788
35129
  syncPathCmds(rCtx);
@@ -38874,7 +39215,7 @@ function wmfRectangle(p, l, t, r, b) {
38874
39215
  axisRect: { interior: rectInterior(p, box) }
38875
39216
  });
38876
39217
  }
38877
- function compatCorner(p, w, h, box) {
39218
+ function compatCorner(p, w, h, box, logical) {
38878
39219
  const m = gdiDeviceMatrix(p.rCtx);
38879
39220
  const cw = Math.round(Math.abs(w * m[0]) * 16);
38880
39221
  const ch = Math.round(Math.abs(h * m[3]) * 16);
@@ -38882,24 +39223,21 @@ function compatCorner(p, w, h, box) {
38882
39223
  const uy = 16 * p.ky;
38883
39224
  if ((p.rCtx.state.penStyle & 15) === PS_INSIDEFRAME && !penIsCosmetic(p.rCtx)) {
38884
39225
  const penWidth = p.rCtx.state.penWidth * Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2])) * 16;
38885
- const width = box.x1 - box.x0, height = box.y1 - box.y0;
38886
- return [Math.floor(Math.min(cw, width + penWidth) * width / (width + penWidth)), Math.floor(Math.min(ch, height + penWidth) * height / (height + penWidth))];
39226
+ const width2 = box.x1 - box.x0, height2 = box.y1 - box.y0;
39227
+ return [Math.floor(Math.min(cw, width2 + penWidth) * width2 / (width2 + penWidth)), Math.floor(Math.min(ch, height2 + penWidth) * height2 / (height2 + penWidth))];
38887
39228
  }
38888
- if (!penIsNull(p) && penIsCosmetic(p.rCtx)) {
38889
- const width = box.x1 - box.x0, height = box.y1 - box.y0;
38890
- return [Math.min(cw, width + ux) * width / (width + ux), Math.min(ch, height + uy) * height / (height + uy)];
38891
- }
38892
- if (!penIsNull(p) && !penIsCosmetic(p.rCtx)) {
38893
- return [Math.round(Math.floor(cw / (2 * ux)) * 2 * ux), Math.round(Math.floor(ch / (2 * uy)) * 2 * uy)];
38894
- }
38895
- return [Math.round(Math.floor(Math.round(cw / ux) / 2) * 2 * ux), Math.round(Math.floor(Math.round(ch / uy) / 2) * 2 * uy)];
39229
+ const width = box.x1 - box.x0, height = box.y1 - box.y0;
39230
+ const fullW = Math.abs((logical[2] - logical[0]) * m[0]) * 16 || width + ux;
39231
+ const fullH = Math.abs((logical[3] - logical[1]) * m[3]) * 16 || height + uy;
39232
+ const scaled2 = [Math.min(Math.abs(w * m[0]) * 16, fullW) * width / fullW, Math.min(Math.abs(h * m[3]) * 16, fullH) * height / fullH];
39233
+ return penIsCosmetic(p.rCtx) && !penIsNull(p) ? scaled2 : [Math.floor(scaled2[0]), Math.floor(scaled2[1])];
38896
39234
  }
38897
39235
  function wmfRoundRect(p, l, t, r, b, w, h) {
38898
39236
  const box = compatBox(p, l, t, r, b, { curved: true });
38899
39237
  if (box.x1 < box.x0 || box.y1 < box.y0) {
38900
39238
  return;
38901
39239
  }
38902
- const [cw, ch] = compatCorner(p, w, h, box);
39240
+ const [cw, ch] = compatCorner(p, w, h, box, [l, t, r, b]);
38903
39241
  const cr = canvasRect(box);
38904
39242
  paintGdiShape(p.rCtx, {
38905
39243
  build: (c) => {
@@ -38952,10 +39290,14 @@ function compatArc(p, kind, l, t, r, b, xs, ys, xe, ye) {
38952
39290
  if (box.x1 < box.x0 || box.y1 < box.y0) {
38953
39291
  return null;
38954
39292
  }
38955
- const raw = compatBox(p, l, t, r, b, { exclusive: false });
39293
+ const m = gdiDeviceMatrix(p.rCtx);
39294
+ const deviceFix = (x, y) => [(m[0] * x + m[2] * y + m[4]) * 16, (m[1] * x + m[3] * y + m[5]) * 16];
39295
+ const [ax, ay] = deviceFix(l, t);
39296
+ const [bx, by] = deviceFix(r, b);
39297
+ const raw = { x0: Math.min(ax, bx), x1: Math.max(ax, bx), y0: Math.min(ay, by), y1: Math.max(ay, by) };
38956
39298
  const onBox = (v, r0, r1, b0, b1) => (b0 + b1) / 2 + (r1 !== r0 ? (v - (r0 + r1) / 2) * (b1 - b0) / (r1 - r0) : v - (r0 + r1) / 2);
38957
39299
  const radial = (x, y) => {
38958
- const [fx, fy] = fixPoint(p.rCtx, x, y);
39300
+ const [fx, fy] = deviceFix(x, y);
38959
39301
  return [onBox(fx, raw.x0, raw.x1, box.x0, box.x1), onBox(fy, raw.y0, raw.y1, box.y0, box.y1)];
38960
39302
  };
38961
39303
  return { box, s: radial(xs, ys), e: radial(xe, ye) };