emf-converter 4.17.0 → 4.18.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/browser.js CHANGED
@@ -10445,12 +10445,12 @@ function cmykPlanesToRgba(planes, width, height, ycck) {
10445
10445
  const fracOf = FRAC_OF;
10446
10446
  const strides = [N * N * N * 3, N * N * 3, N * 3, 3];
10447
10447
  const out = new Uint8Array(width * height * 4);
10448
- const fix = (x) => Math.floor(x * 65536 + 0.5);
10448
+ const fix2 = (x) => Math.floor(x * 65536 + 0.5);
10449
10449
  const half = 1 << 15;
10450
- const crR = fix(1.402);
10451
- const cbB = fix(1.772);
10452
- const crG = -fix(0.71414);
10453
- const cbG = -fix(0.34414);
10450
+ const crR = fix2(1.402);
10451
+ const cbB = fix2(1.772);
10452
+ const crG = -fix2(0.71414);
10453
+ const cbG = -fix2(0.34414);
10454
10454
  const inks = [0, 0, 0, 0];
10455
10455
  const frac = [0, 0, 0, 0];
10456
10456
  const order = [0, 1, 2, 3];
@@ -11361,12 +11361,12 @@ function convertPlanes({ width, height, planes: full, ids, adobe }, colorTransfo
11361
11361
  }
11362
11362
  } else {
11363
11363
  const clamp2 = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
11364
- const fix = (x) => Math.floor(x * 65536 + 0.5);
11364
+ const fix2 = (x) => Math.floor(x * 65536 + 0.5);
11365
11365
  const half = 1 << 15;
11366
- const crR = fix(1.402);
11367
- const cbB = fix(1.772);
11368
- const crG = -fix(0.71414);
11369
- const cbG = -fix(0.34414);
11366
+ const crR = fix2(1.402);
11367
+ const cbB = fix2(1.772);
11368
+ const crG = -fix2(0.71414);
11369
+ const cbG = -fix2(0.34414);
11370
11370
  for (let i = 0; i < width * height; i++) {
11371
11371
  const y = full[0][i];
11372
11372
  const cb = full[1][i] - 128;
@@ -12333,7 +12333,7 @@ function flattenBezierPath(pts) {
12333
12333
  }
12334
12334
  return out;
12335
12335
  }
12336
- function roundRectCorners(l, t, r, b, cw, ch, compatible = false, clockwise = false) {
12336
+ function roundRectCorners(l, t, r, b, cw, ch, compatible = false, clockwise = false, floorH = false) {
12337
12337
  const w = r - l;
12338
12338
  const h = b - t;
12339
12339
  let ew = Math.min(Math.abs(cw), w);
@@ -12346,7 +12346,7 @@ function roundRectCorners(l, t, r, b, cw, ch, compatible = false, clockwise = fa
12346
12346
  const topX = compatible ? Math.round(r - ew / 2) : Math.floor(r - ew / 2);
12347
12347
  const hx = r - topX;
12348
12348
  const verticalControl = clockwise ? Math.ceil(KAPPA * hy) : Math.floor(KAPPA * hy);
12349
- const horizontalControl = Math.ceil(KAPPA * hx);
12349
+ const horizontalControl = floorH ? Math.floor(KAPPA * hx) : Math.ceil(KAPPA * hx);
12350
12350
  const q = [r, t + hy, r, t + hy - verticalControl, r - hx + horizontalControl, t, topX, t];
12351
12351
  const mx = (x) => l + r - x;
12352
12352
  const my = (y) => t + b - y;
@@ -12473,8 +12473,8 @@ var POLYGON_NODES = (() => {
12473
12473
  const cos = [];
12474
12474
  const sin = [];
12475
12475
  for (let k = 0; k <= 129; k++) {
12476
- cos.push(Math.cos(k * TRIG_STEP));
12477
- sin.push(Math.sin(k * TRIG_STEP));
12476
+ cos.push(Math.fround(Math.cos(k * TRIG_STEP)));
12477
+ sin.push(Math.fround(Math.sin(k * TRIG_STEP)));
12478
12478
  }
12479
12479
  for (let k = 0; k <= 128; k += 32) {
12480
12480
  cos[k] = [1, 0, -1, 0, 1][k / 32];
@@ -12487,7 +12487,7 @@ function polygonTrig(angle) {
12487
12487
  if (b < 0) {
12488
12488
  b += 2 * Math.PI;
12489
12489
  }
12490
- const x = b / TRIG_STEP;
12490
+ const x = Math.fround(b / TRIG_STEP);
12491
12491
  const i = Math.min(127, Math.floor(x));
12492
12492
  const f = x - i;
12493
12493
  return [
@@ -12507,16 +12507,38 @@ function approximateArcAngle(x, y) {
12507
12507
  if (ax === 0 && ay === 0) {
12508
12508
  return 0;
12509
12509
  }
12510
- const a = ay <= ax ? interpolatedAtan(ay / ax) : Math.PI / 2 - interpolatedAtan(ax / ay);
12510
+ const a = ay <= ax ? interpolatedAtan(Math.fround(ay / ax)) : Math.PI / 2 - interpolatedAtan(Math.fround(ax / ay));
12511
12511
  if (x >= 0) {
12512
12512
  return y >= 0 ? a : 2 * Math.PI - a;
12513
12513
  }
12514
12514
  return y >= 0 ? Math.PI - a : Math.PI + a;
12515
12515
  }
12516
- function unitPiece(from, to, small) {
12516
+ function unitPiece(from, to, small, radius = Infinity) {
12517
12517
  const trig = small ? (a) => [Math.cos(a), Math.sin(a)] : polygonTrig;
12518
12518
  const p0 = trig(from);
12519
12519
  const p3 = trig(to);
12520
+ if (small && 6e-8 * radius / Math.abs(Math.sin(to - from)) > 0.5) {
12521
+ const f = Math.fround;
12522
+ const q0 = [f(p0[0]), f(p0[1])];
12523
+ const q3 = [f(p3[0]), f(p3[1])];
12524
+ const det32 = f(f(q0[0] * q3[1]) - f(q0[1] * q3[0]));
12525
+ if (det32 !== 0) {
12526
+ const X = [f(f(q3[1] - q0[1]) / det32), f(f(q0[0] - q3[0]) / det32)];
12527
+ const c = f(polygonTrig(Math.abs(to - from) / 2)[0]);
12528
+ const kappa = f(f(f(4 / 3) * c) / f(1 + c));
12529
+ return {
12530
+ start: p0,
12531
+ ctrl: [
12532
+ f(q0[0] + f(kappa * f(X[0] - q0[0]))),
12533
+ f(q0[1] + f(kappa * f(X[1] - q0[1]))),
12534
+ f(q3[0] + f(kappa * f(X[0] - q3[0]))),
12535
+ f(q3[1] + f(kappa * f(X[1] - q3[1]))),
12536
+ p3[0],
12537
+ p3[1]
12538
+ ]
12539
+ };
12540
+ }
12541
+ }
12520
12542
  const det = p0[0] * p3[1] - p0[1] * p3[0];
12521
12543
  let ctrl;
12522
12544
  if (Math.abs(det) < 1e-12) {
@@ -12536,7 +12558,7 @@ function unitPiece(from, to, small) {
12536
12558
  }
12537
12559
  return { start: p0, ctrl };
12538
12560
  }
12539
- function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise, halfX = false, framed = false) {
12561
+ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise, halfX = false, framed = false, mirrorX = false) {
12540
12562
  const w = r - l;
12541
12563
  const h = b - t;
12542
12564
  const Q = Math.PI / 2;
@@ -12549,16 +12571,21 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise, halfX = false, framed
12549
12571
  const angle = (x, y) => approximateArcAngle((x - tcx) / (w / 2 || 1), -(y - tcy) / (h / 2 || 1));
12550
12572
  const a0 = angle(xs, ys);
12551
12573
  let a1 = angle(xe, ye);
12552
- const small = a1 !== a0 && Math.abs(a1 - a0) <= SMALL_SWEEP;
12574
+ const mirrored = (a2) => clockwise ? (2 * Math.PI - a2) % (2 * Math.PI) : a2;
12575
+ const small = a1 !== a0 && Math.abs(mirrored(a1) - mirrored(a0)) <= SMALL_SWEEP;
12553
12576
  const s = clockwise ? -1 : 1;
12554
12577
  if (s > 0) {
12555
12578
  while (a1 <= a0) a1 += 2 * Math.PI;
12556
12579
  } else {
12557
12580
  while (a1 >= a0) a1 -= 2 * Math.PI;
12558
12581
  }
12559
- const px = (u, v) => clockwise && halfX ? Math.ceil(cx + rx * u + 0.5 - v) : Math.round(cx + rx * u + (halfX ? 1 + v : 0));
12560
- const py = (v) => Math.round(cy - ry * v);
12561
- const eb = axisBox(l, t, r, b);
12582
+ const axis = (r2, c) => Math.fround(r2 * Math.fround(c));
12583
+ const px = (u, v) => mirrorX ? (
12584
+ // The mirrored circle sits on the same centre but its horizontal radius rounds down (native playback, 144 arcs under a mirrored x).
12585
+ Math.round(cx - axis(Math.floor(w / 2), u))
12586
+ ) : clockwise && halfX ? Math.ceil(cx + axis(rx, u) + 0.5 - v) : Math.round(cx + axis(rx, u) + (halfX ? 1 + v : 0));
12587
+ const py = (v) => Math.round(cy - axis(ry, v));
12588
+ const eb = mirrorX ? axisBox(r, t, l, b) : axisBox(l, t, r, b);
12562
12589
  if (halfX) eb.halfX = true;
12563
12590
  const E = ellipseBeziersBox(eb);
12564
12591
  if (clockwise) {
@@ -12594,7 +12621,7 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise, halfX = false, framed
12594
12621
  continue;
12595
12622
  }
12596
12623
  const e = s > 0 ? Math.min(next, a1) : Math.max(next, a1);
12597
- const piece = unitPiece(a, e, small);
12624
+ const piece = unitPiece(a, e, small, Math.max(rx, ry));
12598
12625
  for (let i = 0; i < 6; i += 2) {
12599
12626
  out.push(px(piece.ctrl[i], piece.ctrl[i + 1]), py(piece.ctrl[i + 1]));
12600
12627
  }
@@ -16262,6 +16289,21 @@ function decodeBmpFile(bytes) {
16262
16289
  return image ? { kind: "rgba", data: image.data, width: image.width, height: image.height } : null;
16263
16290
  }
16264
16291
 
16292
+ // src/float32-down.ts
16293
+ var float32 = new Float32Array(1);
16294
+ var float32Bits = new Uint32Array(float32.buffer);
16295
+ function down32(x) {
16296
+ const r = Math.fround(x);
16297
+ if (r <= x || Number.isNaN(r)) return r;
16298
+ if (r === 0) {
16299
+ float32Bits[0] = 2147483649;
16300
+ return float32[0];
16301
+ }
16302
+ float32[0] = r;
16303
+ float32Bits[0] += r > 0 ? -1 : 1;
16304
+ return float32[0];
16305
+ }
16306
+
16265
16307
  // src/emf-plus-linear-ramp.ts
16266
16308
  var GAMMA = 2.2;
16267
16309
  function linearRampIntervals(pointCount, rect) {
@@ -16537,30 +16579,76 @@ function pathGradientQuantum(boundary, matrix = IDENTITY) {
16537
16579
  let x1 = -Infinity;
16538
16580
  let y1 = -Infinity;
16539
16581
  for (const p of boundary) {
16540
- const x = matrix[0] * p.x + matrix[2] * p.y + matrix[4];
16541
- const y = matrix[1] * p.x + matrix[3] * p.y + matrix[5];
16542
- x0 = Math.min(x0, x);
16543
- y0 = Math.min(y0, y);
16544
- x1 = Math.max(x1, x);
16545
- y1 = Math.max(y1, y);
16582
+ x0 = Math.min(x0, p.x);
16583
+ y0 = Math.min(y0, p.y);
16584
+ x1 = Math.max(x1, p.x);
16585
+ y1 = Math.max(y1, p.y);
16546
16586
  }
16547
- const steps = Math.ceil(2 * Math.hypot(x1 - x0, y1 - y0));
16587
+ const w = x1 - x0;
16588
+ const h = y1 - y0;
16589
+ const first = Math.hypot(matrix[0] * w + matrix[2] * h, matrix[1] * w + matrix[3] * h);
16590
+ const second = Math.hypot(matrix[0] * w - matrix[2] * h, matrix[1] * w - matrix[3] * h);
16591
+ const steps = Math.ceil(first + second);
16548
16592
  return Number.isFinite(steps) && steps > 0 ? steps : 0;
16549
16593
  }
16594
+ var TIE_LEVEL = 1e-9;
16550
16595
  var TIE_EPSILON = 1e-7;
16596
+ function pathGradientRatio(shape, x, y, focusPoint) {
16597
+ const report = { s: NaN };
16598
+ return pathGradientColorAt(shape, x, y, focusPoint, 0, report) === null ? null : report.s;
16599
+ }
16551
16600
  function quantisedPathArgb(surround, centre, t, quantum) {
16552
16601
  const scaled2 = t * quantum;
16553
16602
  const tie = Math.abs(scaled2 - Math.floor(scaled2) - 0.5) < TIE_EPSILON;
16554
- const k = tie ? scaled2 : Math.floor(scaled2 + 0.5);
16555
- const fromBoundary = t < 0.5;
16603
+ return quantisedStepArgb(surround, centre, tie ? scaled2 : Math.floor(scaled2 + 0.5), quantum, t < 0.5);
16604
+ }
16605
+ function roundTowards(v, target) {
16606
+ const floor = Math.floor(v);
16607
+ const fraction = v - floor;
16608
+ if (Math.abs(fraction - 0.5) < TIE_LEVEL) return target > v ? floor + 1 : floor;
16609
+ return fraction > 0.5 ? floor + 1 : floor;
16610
+ }
16611
+ var centreWeightTables = /* @__PURE__ */ new Map();
16612
+ function centreWeight(quantum, j) {
16613
+ let table2 = centreWeightTables.get(quantum);
16614
+ if (!table2) {
16615
+ table2 = new Float64Array(quantum + 1);
16616
+ const step = down32(1 / quantum);
16617
+ let w = 0;
16618
+ for (let i = 1; i <= quantum; i++) {
16619
+ w = down32(w + step);
16620
+ table2[i] = w;
16621
+ }
16622
+ if (centreWeightTables.size > 64) centreWeightTables.clear();
16623
+ centreWeightTables.set(quantum, table2);
16624
+ }
16625
+ return table2[j];
16626
+ }
16627
+ function centreWeightArgb(surround, centre, k, quantum) {
16628
+ const w = centreWeight(quantum, quantum - k);
16629
+ const aS = surround >>> 24 & 255;
16630
+ const aC = centre >>> 24 & 255;
16631
+ const level2 = (s, c) => roundTowards(c + (s - c) * w, c);
16632
+ const alpha = level2(aS, aC);
16633
+ if (alpha <= 0) return 0;
16634
+ const ch = (shift) => {
16635
+ const p = level2((surround >>> shift & 255) * aS / 255, (centre >>> shift & 255) * aC / 255);
16636
+ return Math.min(255, Math.max(0, Math.round(p * 255 / alpha)));
16637
+ };
16638
+ return (alpha << 24 | ch(16) << 16 | ch(8) << 8 | ch(0)) >>> 0;
16639
+ }
16640
+ function quantisedStepArgb(surround, centre, k, quantum, fromBoundary) {
16641
+ if (Number.isInteger(k)) return centreWeightArgb(surround, centre, k, quantum);
16556
16642
  const w = (fromBoundary ? k : quantum - k) / quantum;
16557
16643
  const aS = surround >>> 24 & 255;
16558
16644
  const aC = centre >>> 24 & 255;
16559
16645
  const mix2 = (s, c) => fromBoundary ? s + (c - s) * w : c + (s - c) * w;
16560
- const alpha = Math.floor(mix2(aS, aC) + 0.5);
16646
+ const whole = Number.isInteger(k);
16647
+ const level2 = (s, c) => whole ? roundTowards(mix2(s, c), c) : Math.floor(mix2(s, c) + 0.5);
16648
+ const alpha = level2(aS, aC);
16561
16649
  if (alpha <= 0) return 0;
16562
16650
  const ch = (shift) => {
16563
- const p = Math.floor(mix2((surround >>> shift & 255) * aS / 255, (centre >>> shift & 255) * aC / 255) + 0.5);
16651
+ const p = level2((surround >>> shift & 255) * aS / 255, (centre >>> shift & 255) * aC / 255);
16564
16652
  return Math.min(255, Math.max(0, Math.round(p * 255 / alpha)));
16565
16653
  };
16566
16654
  return (alpha << 24 | ch(16) << 16 | ch(8) << 8 | ch(0)) >>> 0;
@@ -16570,6 +16658,24 @@ function quantisedPosition(pos, quantum) {
16570
16658
  const tie = Math.abs(scaled2 - Math.floor(scaled2) - 0.5) < TIE_EPSILON;
16571
16659
  return (tie ? scaled2 : Math.floor(scaled2 + 0.5)) / quantum;
16572
16660
  }
16661
+ function pathGradientStepColor(shape, k, quantum) {
16662
+ const pos = k / quantum;
16663
+ if (shape.preset && shape.preset.positions.length > 0) {
16664
+ const { positions, argb } = shape.preset;
16665
+ if (pos <= positions[0]) return argb[0];
16666
+ for (let i = 1; i < positions.length; i++) {
16667
+ if (pos <= positions[i]) {
16668
+ const span = positions[i] - positions[i - 1];
16669
+ return lerpArgb(argb[i - 1], argb[i], span > 0 ? (pos - positions[i - 1]) / span : 1);
16670
+ }
16671
+ }
16672
+ return argb[positions.length - 1];
16673
+ }
16674
+ const surround = shape.boundaryArgb[0] ?? shape.centerArgb;
16675
+ if (!shape.blend) return quantisedStepArgb(surround, shape.centerArgb, k, quantum, k * 2 < quantum);
16676
+ const t = Math.min(1, Math.max(0, piecewise2(shape.blend.positions, shape.blend.factors, pos)));
16677
+ return surround >>> 24 !== shape.centerArgb >>> 24 ? lerpUniformPathArgb(surround, shape.centerArgb, t) : lerpArgb(surround, shape.centerArgb, t);
16678
+ }
16573
16679
  function piecewise2(xs, ys, x) {
16574
16680
  const n = Math.min(xs.length, ys.length);
16575
16681
  if (n === 0) {
@@ -16604,7 +16710,7 @@ function stopColorAt(stops, t) {
16604
16710
  }
16605
16711
  return stops[stops.length - 1].argb;
16606
16712
  }
16607
- function pathGradientColorAt(shape, x, y, focusPoint, quantum) {
16713
+ function pathGradientColorAt(shape, x, y, focusPoint, quantum, report) {
16608
16714
  const { center, boundary, boundaryArgb } = shape;
16609
16715
  const n = boundary.length;
16610
16716
  const px = x - center.x;
@@ -16710,6 +16816,7 @@ function pathGradientColorAt(shape, x, y, focusPoint, quantum) {
16710
16816
  }
16711
16817
  }
16712
16818
  if (found < 0 || !Number.isFinite(s)) return null;
16819
+ if (report) report.s = s;
16713
16820
  const exactPos = 1 - s;
16714
16821
  const pos = quantum && quantum > 0 ? quantisedPosition(exactPos, quantum) : exactPos;
16715
16822
  if (shape.preset && shape.preset.positions.length > 0) {
@@ -17306,19 +17413,31 @@ function applyTint(src, hue, amount) {
17306
17413
  var TINT_FULL = 254;
17307
17414
  function applyRedEyeCorrection(src, width, height, areas) {
17308
17415
  const out = new Uint8ClampedArray(src);
17309
- const carry = { x: 0, y: 0 };
17416
+ const carry = { x: 0, y: 0, set: false };
17310
17417
  for (const a of areas) {
17311
17418
  correctRedEyeArea(out, width, clamp(a.left, 0, width), clamp(a.top, 0, height), clamp(a.right, 0, width), clamp(a.bottom, 0, height), carry);
17312
17419
  }
17313
17420
  return out;
17314
17421
  }
17315
17422
  var RED_EYE_SECTORS = 60;
17316
- var RED_EYE_BLUE_WEIGHT = 0.225;
17317
- var RED_EYE_PURE_WEIGHT = 1 / (1 + RED_EYE_BLUE_WEIGHT);
17318
- var RED_EYE_CARRY = 0.81;
17423
+ var RED_EYE_LEGACY = {
17424
+ blueWeight: 0.225,
17425
+ pureWeight: 1 / 1.225,
17426
+ carry: 0.81
17427
+ };
17428
+ var RED_EYE_CENTRE_SECTOR = 15;
17429
+ var RED_EYE_BLUE_WEIGHT = 2 / 9;
17430
+ var RED_EYE_PURE_WEIGHT = 1;
17431
+ var RED_EYE_CARRY = 1;
17432
+ function redEyeLuma(g, b) {
17433
+ return Math.floor((9 * g + 2 * b + 5) / 11);
17434
+ }
17319
17435
  var RED_EYE_GREEN_SHARE = 5 / 16;
17320
- var RED_EYE_SPREAD_STEPS = [31.5, 50, 98.78];
17436
+ var RED_EYE_SPREAD_STEPS = [25, 40, 80];
17321
17437
  var RED_EYE_STRENGTHS = [0.25, 0.5, 0.661, 0.75];
17438
+ var RED_EYE_HIGHLIGHT_RISE = 40;
17439
+ var RED_EYE_FALLBACK_SLOPE = 0.33;
17440
+ var RED_EYE_HIGHLIGHT_REST = 5;
17322
17441
  function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17323
17442
  const w = x1 - x0;
17324
17443
  const h = y1 - y0;
@@ -17328,9 +17447,19 @@ function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17328
17447
  }
17329
17448
  const redness = new Float64Array(count);
17330
17449
  const dark = new Float64Array(count);
17450
+ const lumas = new Int32Array(count);
17331
17451
  let sx = 0;
17332
17452
  let sy = 0;
17333
17453
  let sw = 0;
17454
+ let sxL = 0;
17455
+ let syL = 0;
17456
+ let swL = 0;
17457
+ let redCount = 0;
17458
+ let sx32 = 0;
17459
+ let sy32 = 0;
17460
+ let sw32 = 0;
17461
+ let firstRed = -1;
17462
+ let uniformRed = true;
17334
17463
  for (let y = 0; y < h; y++) {
17335
17464
  for (let x = 0; x < w; x++) {
17336
17465
  const i = ((y0 + y) * stride + x0 + x) * 4;
@@ -17340,24 +17469,53 @@ function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17340
17469
  const k = y * w + x;
17341
17470
  const d = g + RED_EYE_BLUE_WEIGHT * b;
17342
17471
  dark[k] = d;
17472
+ const dL = g + RED_EYE_LEGACY.blueWeight * b;
17473
+ const luma = redEyeLuma(g, b);
17474
+ lumas[k] = luma;
17343
17475
  const v = r - Math.max(g, b);
17344
17476
  if (v > 0) {
17345
17477
  redness[k] = v;
17346
- const weight = d >= 1 ? v / d : RED_EYE_PURE_WEIGHT;
17478
+ const weight = luma >= 1 ? v / luma : RED_EYE_PURE_WEIGHT;
17347
17479
  sx += weight * (x + 0.5);
17348
17480
  sy += weight * (y + 0.5);
17349
17481
  sw += weight;
17482
+ redCount++;
17483
+ const weight32 = Math.fround(weight);
17484
+ sx32 = Math.fround(sx32 + Math.fround(weight32 * Math.fround(x + 0.5)));
17485
+ sy32 = Math.fround(sy32 + Math.fround(weight32 * Math.fround(y + 0.5)));
17486
+ sw32 = Math.fround(sw32 + weight32);
17487
+ const triple = r << 16 | g << 8 | b;
17488
+ if (firstRed < 0) {
17489
+ firstRed = triple;
17490
+ } else if (triple !== firstRed) {
17491
+ uniformRed = false;
17492
+ }
17493
+ const weightL = dL >= 1 ? v / dL : RED_EYE_LEGACY.pureWeight;
17494
+ sxL += weightL * (x + 0.5);
17495
+ syL += weightL * (y + 0.5);
17496
+ swL += weightL;
17350
17497
  }
17351
17498
  }
17352
17499
  }
17353
17500
  if (sw === 0) {
17354
17501
  return;
17355
17502
  }
17356
- let cx = (sx + RED_EYE_CARRY * carry.x) / sw;
17357
- let cy = (sy + RED_EYE_CARRY * carry.y) / sw;
17503
+ const snap2 = (v) => Math.round(v * 1e9) / 1e9;
17504
+ const lumaCx = snap2((sx + (carry.set ? carry.x - 0.5 : 0) * RED_EYE_CARRY) / sw);
17505
+ const lumaCy = snap2((sy + (carry.set ? carry.y - 0.5 : 0) * RED_EYE_CARRY) / sw);
17506
+ const onPixelCentre = (v) => Number.isInteger(snap2(v - 0.5));
17507
+ const symmetric = redCount > 1 && (onPixelCentre(lumaCx) || onPixelCentre(lumaCy));
17508
+ const exactCentre = (c, sum32) => !onPixelCentre(c) || Math.fround(sum32 / sw32) === c;
17509
+ const exactSymmetric = symmetric && !uniformRed && !carry.set && exactCentre(lumaCx, sx32) && exactCentre(lumaCy, sy32);
17510
+ const legacyWeights = symmetric && !exactSymmetric;
17511
+ let cx = legacyWeights ? (sxL + RED_EYE_LEGACY.carry * (carry.set ? carry.x : 0)) / swL : lumaCx;
17512
+ let cy = legacyWeights ? (syL + RED_EYE_LEGACY.carry * (carry.set ? carry.y : 0)) / swL : lumaCy;
17358
17513
  carry.x = x0 + cx;
17359
17514
  carry.y = y0 + cy;
17360
- if (Math.hypot(cx - w / 2, cy - h / 2) >= Math.max(Math.min(w, h) / 2, (w + h) / 6)) {
17515
+ carry.set = true;
17516
+ let fellBack = false;
17517
+ if (Math.hypot(cx - w / 2, cy - h / 2) >= (w + h) / 6) {
17518
+ fellBack = true;
17361
17519
  cx = w / 2;
17362
17520
  cy = h / 2;
17363
17521
  }
@@ -17369,10 +17527,17 @@ function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17369
17527
  if (!(radius > 0)) {
17370
17528
  return;
17371
17529
  }
17372
- const sorted = Float64Array.from(dark).sort();
17373
- const spread = sorted[Math.floor(0.7 * count)] - sorted[Math.floor(0.3 * count)];
17530
+ const sorted = Int32Array.from(lumas).sort();
17531
+ const p70 = sorted[Math.floor(0.7 * count)];
17532
+ const spread = p70 - sorted[Math.floor(0.3 * count)];
17533
+ const brightest = sorted[count - 1];
17534
+ const second = count > 1 ? sorted[count - 2] : -1;
17535
+ let highlight = -1;
17536
+ if (brightest > second && brightest - p70 >= RED_EYE_HIGHLIGHT_RISE) {
17537
+ highlight = lumas.indexOf(brightest);
17538
+ }
17374
17539
  let level2 = 0;
17375
- while (level2 < RED_EYE_SPREAD_STEPS.length && spread >= RED_EYE_SPREAD_STEPS[level2]) {
17540
+ while (level2 < RED_EYE_SPREAD_STEPS.length && spread > RED_EYE_SPREAD_STEPS[level2]) {
17376
17541
  level2++;
17377
17542
  }
17378
17543
  const strength = RED_EYE_STRENGTHS[level2];
@@ -17393,7 +17558,7 @@ function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17393
17558
  if (angle < 0) {
17394
17559
  angle += 360;
17395
17560
  }
17396
- const s = Math.min(RED_EYE_SECTORS - 1, Math.floor(angle / 6));
17561
+ const s = dx === 0 && dy === 0 ? RED_EYE_CENTRE_SECTOR : dy === 0 ? 0 : Math.min(RED_EYE_SECTORS - 1, Math.floor(angle / 6));
17397
17562
  sector[k] = s;
17398
17563
  if (d < radius) {
17399
17564
  sectorSum[s] += redness[k];
@@ -17415,8 +17580,13 @@ function correctRedEyeArea(out, stride, x0, y0, x1, y1, carry) {
17415
17580
  const ratio = meanDark > 0 ? dark[k] / meanDark : 1;
17416
17581
  const u = distance[k] / radius;
17417
17582
  const darknessFalloff = ratio < 2 ? 0.5 * (1 - ratio) ** 2 : 0;
17418
- const falloff = Math.max(strength * (1 - u) * (1 - u), darknessFalloff);
17419
- const rest = (1 - falloff) * mean;
17583
+ const falloff = Math.max(strength * (1 - u) * (1 - u), darknessFalloff, fellBack ? RED_EYE_FALLBACK_SLOPE * (1 - u) : 0);
17584
+ let rest = (1 - falloff) * mean;
17585
+ if (highlight >= 0) {
17586
+ const hdx = x - highlight % w;
17587
+ const hdy = y - Math.floor(highlight / w);
17588
+ rest = Math.min(rest, RED_EYE_HIGHLIGHT_REST * (hdx * hdx + hdy * hdy));
17589
+ }
17420
17590
  if (rest >= v) {
17421
17591
  continue;
17422
17592
  }
@@ -19636,13 +19806,13 @@ function recordDeviceFigures(buildPath, device) {
19636
19806
  const f = fig;
19637
19807
  f.curved = true;
19638
19808
  const n = f.pts.length;
19639
- const fix = (v) => toPlusFix(v);
19640
- const p0x = fix(f.pts[n - 2]);
19641
- const p0y = fix(f.pts[n - 1]);
19809
+ const fix2 = (v) => toPlusFix(v);
19810
+ const p0x = fix2(f.pts[n - 2]);
19811
+ const p0y = fix2(f.pts[n - 1]);
19642
19812
  f.pts[n - 2] = p0x / 16;
19643
19813
  f.pts[n - 1] = p0y / 16;
19644
19814
  const out = [];
19645
- const ctrl = [p0x, p0y, fix(dx(c1x, c1y)), fix(dy(c1x, c1y)), fix(dx(c2x, c2y)), fix(dy(c2x, c2y)), fix(dx(x, y)), fix(dy(x, y))];
19815
+ const ctrl = [p0x, p0y, fix2(dx(c1x, c1y)), fix2(dy(c1x, c1y)), fix2(dx(c2x, c2y)), fix2(dy(c2x, c2y)), fix2(dx(x, y)), fix2(dy(x, y))];
19646
19816
  flattenBezierGdiplus(ctrl, out);
19647
19817
  for (const v of out) {
19648
19818
  f.pts.push(v / 16);
@@ -19916,7 +20086,7 @@ function frame(a, b) {
19916
20086
  const uy = (b.y - a.y) / len;
19917
20087
  return { ux, uy, nx: -uy, ny: ux };
19918
20088
  }
19919
- function joinPoints(p, f1, f2, o, pen) {
20089
+ function joinPoints(p, f1, f2, o, pen, meetInside = false) {
19920
20090
  const a = { x: p.x + f1.nx * o, y: p.y + f1.ny * o };
19921
20091
  const b = { x: p.x + f2.nx * o, y: p.y + f2.ny * o };
19922
20092
  if (o === 0) {
@@ -19928,6 +20098,11 @@ function joinPoints(p, f1, f2, o, pen) {
19928
20098
  }
19929
20099
  const outer = cross * o < 0;
19930
20100
  if (!outer) {
20101
+ if (meetInside) {
20102
+ const den2 = f1.ux * f2.uy - f1.uy * f2.ux;
20103
+ const t2 = ((b.x - a.x) * f2.uy - (b.y - a.y) * f2.ux) / den2;
20104
+ return [{ x: a.x + f1.ux * t2, y: a.y + f1.uy * t2 }];
20105
+ }
19931
20106
  return [a, b];
19932
20107
  }
19933
20108
  if (pen.join === 2) {
@@ -19995,7 +20170,7 @@ function sidePoints(pts, closed, o, pen) {
19995
20170
  const inIdx = i - 1 >= 0 ? i - 1 : closed ? segs2 - 1 : -1;
19996
20171
  const outIdx = i < segs2 ? i : -1;
19997
20172
  if (inIdx >= 0 && outIdx >= 0) {
19998
- out.push(...joinPoints(pts[i], frames[inIdx], frames[outIdx], o, pen));
20173
+ out.push(...joinPoints(pts[i], frames[inIdx], frames[outIdx], o, pen, closed && !!pen.compound));
19999
20174
  } else {
20000
20175
  const f = frames[outIdx >= 0 ? outIdx : inIdx];
20001
20176
  out.push({ x: pts[i].x + f.nx * o, y: pts[i].y + f.ny * o });
@@ -20102,6 +20277,50 @@ function signedArea(pts) {
20102
20277
  }
20103
20278
  return a / 2;
20104
20279
  }
20280
+ function insidePolygon(pts, q) {
20281
+ let inside = false;
20282
+ for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {
20283
+ const a = pts[i];
20284
+ const b = pts[j];
20285
+ if (a.y > q.y !== b.y > q.y && q.x < (b.x - a.x) * (q.y - a.y) / (b.y - a.y) + a.x) {
20286
+ inside = !inside;
20287
+ }
20288
+ }
20289
+ return inside;
20290
+ }
20291
+ function insetCollapses(pts, d) {
20292
+ const sign = signedArea(pts) > 0 ? 1 : -1;
20293
+ const n = pts.length;
20294
+ const frames = Array.from({ length: n }, (_, i) => frame(pts[i], pts[(i + 1) % n]));
20295
+ const moved = pts.map((v, i) => {
20296
+ const f1 = frames[(i + n - 1) % n];
20297
+ const f2 = frames[i];
20298
+ const n1x = f1.nx * sign, n1y = f1.ny * sign, n2x = f2.nx * sign, n2y = f2.ny * sign;
20299
+ const k = 1 + n1x * n2x + n1y * n2y;
20300
+ return k < 1e-9 ? { x: v.x + n1x * d, y: v.y + n1y * d } : { x: v.x + (n1x + n2x) * d / k, y: v.y + (n1y + n2y) * d / k };
20301
+ });
20302
+ return Math.sign(signedArea(moved)) !== sign || moved.some((q) => !insidePolygon(pts, q));
20303
+ }
20304
+ function innerBoundary(pts, d, pen) {
20305
+ const sign = signedArea(pts) > 0 ? 1 : -1;
20306
+ const n = pts.length;
20307
+ const frames = Array.from({ length: n }, (_, i) => frame(pts[i], pts[(i + 1) % n]));
20308
+ const out = [];
20309
+ for (let i = 0; i < n; i++) {
20310
+ const f1 = frames[(i + n - 1) % n];
20311
+ const f2 = frames[i];
20312
+ const o = sign * d;
20313
+ const cross = f1.ux * f2.uy - f1.uy * f2.ux;
20314
+ if (cross * o < 0) {
20315
+ out.push(...joinPoints(pts[i], f1, f2, o, pen));
20316
+ } else {
20317
+ const n1x = f1.nx * sign, n1y = f1.ny * sign, n2x = f2.nx * sign, n2y = f2.ny * sign;
20318
+ const k = 1 + n1x * n2x + n1y * n2y;
20319
+ out.push(k < 1e-9 ? { x: pts[i].x + n1x * d, y: pts[i].y + n1y * d } : { x: pts[i].x + (n1x + n2x) * d / k, y: pts[i].y + (n1y + n2y) * d / k });
20320
+ }
20321
+ }
20322
+ return out;
20323
+ }
20105
20324
  function widenFigures(figures, pen) {
20106
20325
  const polys = [];
20107
20326
  const h = pen.half;
@@ -20113,6 +20332,13 @@ function widenFigures(figures, pen) {
20113
20332
  const closed = fig.closed && pts.length > 2;
20114
20333
  let lo = -h;
20115
20334
  let hi = h;
20335
+ if (pen.inset && closed && !pen.dash && !pen.compound) {
20336
+ polys.push(pts.slice());
20337
+ if (!insetCollapses(pts, 2 * h)) {
20338
+ polys.push(innerBoundary(pts, 2 * h, pen).reverse());
20339
+ }
20340
+ continue;
20341
+ }
20116
20342
  if (pen.inset && closed) {
20117
20343
  if (signedArea(pts) > 0) {
20118
20344
  lo = 0;
@@ -21022,6 +21248,106 @@ async function preDecodeMetafileCaches(view, depth = 0) {
21022
21248
  };
21023
21249
  }
21024
21250
 
21251
+ // src/emf-plus-hq-cubic-weights.ts
21252
+ var HQ_CUBIC_HALF_TABLE = [
21253
+ [-1675, 5953, 56660, 6337, -1739],
21254
+ [-1612, 5575, 56650, 6727, -1804],
21255
+ [-1550, 5203, 56630, 7123, -1870],
21256
+ [-1489, 4837, 56600, 7525, -1937],
21257
+ [-1429, 4477, 56561, 7931, -2004],
21258
+ [-1371, 4125, 56510, 8345, -2073],
21259
+ [-1313, 3777, 56451, 8763, -2142],
21260
+ [-1257, 3437, 56381, 9187, -2212],
21261
+ [-1202, 3103, 56301, 9617, -2283],
21262
+ [-1148, 2775, 56211, 10053, -2355],
21263
+ [-1095, 2453, 56112, 10493, -2427],
21264
+ [-1044, 2139, 56002, 10939, -2500],
21265
+ [-993, 1829, 55884, 11389, -2573],
21266
+ [-945, 1529, 55754, 11845, -2647],
21267
+ [-897, 1233, 55616, 12305, -2721],
21268
+ [-851, 945, 55467, 12771, -2796],
21269
+ [-806, 663, 55309, 13241, -2871],
21270
+ [-762, 387, 55142, 13715, -2946],
21271
+ [-720, 119, 54964, 14195, -3022],
21272
+ [-679, -143, 54778, 14677, -3097],
21273
+ [-639, -399, 54582, 15165, -3173],
21274
+ [-600, -649, 54377, 15657, -3249],
21275
+ [-563, -891, 54162, 16153, -3325],
21276
+ [-528, -1125, 53937, 16653, -3401],
21277
+ [-493, -1355, 53705, 17155, -3476],
21278
+ [-460, -1577, 53462, 17663, -3552],
21279
+ [-429, -1791, 53210, 18173, -3627],
21280
+ [-398, -2001, 52950, 18687, -3702],
21281
+ [-369, -2203, 52681, 19203, -3776],
21282
+ [-341, -2399, 52403, 19723, -3850],
21283
+ [-315, -2587, 52116, 20245, -3923],
21284
+ [-289, -2771, 51821, 20771, -3996],
21285
+ [-265, -2947, 51517, 21299, -4068],
21286
+ [-243, -3115, 51204, 21829, -4139],
21287
+ [-221, -3279, 50884, 22361, -4209],
21288
+ [-201, -3435, 50554, 22897, -4279],
21289
+ [-182, -3585, 50217, 23433, -4347],
21290
+ [-164, -3729, 49872, 23971, -4414],
21291
+ [-147, -3867, 49518, 24513, -4481],
21292
+ [-131, -3999, 49158, 25053, -4545],
21293
+ [-117, -4123, 48788, 25597, -4609],
21294
+ [-103, -4243, 48412, 26141, -4671],
21295
+ [-90, -4357, 48029, 26685, -4731],
21296
+ [-79, -4463, 47637, 27231, -4790],
21297
+ [-68, -4565, 47239, 27777, -4847],
21298
+ [-59, -4659, 46833, 28323, -4902],
21299
+ [-50, -4749, 46421, 28869, -4955],
21300
+ [-42, -4833, 46002, 29415, -5006],
21301
+ [-35, -4911, 45576, 29961, -5055],
21302
+ [-29, -4983, 45143, 30507, -5102],
21303
+ [-24, -5049, 44704, 31051, -5146],
21304
+ [-19, -5111, 44259, 31595, -5188],
21305
+ [-15, -5167, 43807, 32139, -5228],
21306
+ [-11, -5219, 43351, 32679, -5264],
21307
+ [-8, -5265, 42888, 33219, -5298],
21308
+ [-6, -5305, 42419, 33757, -5329],
21309
+ [-4, -5341, 41944, 34295, -5358],
21310
+ [-3, -5371, 41464, 34829, -5383],
21311
+ [-2, -5397, 40980, 35359, -5404],
21312
+ [-1, -5419, 40490, 35889, -5423],
21313
+ [0, -5437, 39996, 36415, -5438],
21314
+ [0, -5449, 39497, 36937, -5449],
21315
+ [0, -5457, 38993, 37457, -5457],
21316
+ [0, -5461, 38485, 37973, -5461]
21317
+ ];
21318
+ function hqCubicBinWeights(bin) {
21319
+ if (bin < 64) {
21320
+ return { first: -2, weights: HQ_CUBIC_HALF_TABLE[bin] };
21321
+ }
21322
+ return { first: -1, weights: HQ_CUBIC_HALF_TABLE[127 - bin].slice().reverse() };
21323
+ }
21324
+ var HQ_CUBIC_CDF = (() => {
21325
+ const cdf = new Int32Array(512).fill(Number.NaN);
21326
+ for (let bin = 0; bin < 128; bin++) {
21327
+ const { first, weights } = hqCubicBinWeights(bin);
21328
+ let acc = -32768;
21329
+ for (let i = 0; i <= 5; i++) {
21330
+ const m = 128 * (first + i) - 64 - bin - 1;
21331
+ if (m >= -256 && m <= 255) {
21332
+ cdf[m + 256] = acc;
21333
+ }
21334
+ if (i < 5) {
21335
+ acc += weights[i];
21336
+ }
21337
+ }
21338
+ }
21339
+ return cdf;
21340
+ })();
21341
+ function hqCubicCdf(m) {
21342
+ if (m < -256) {
21343
+ return -32768;
21344
+ }
21345
+ if (m > 255) {
21346
+ return 32768;
21347
+ }
21348
+ return HQ_CUBIC_CDF[m + 256];
21349
+ }
21350
+
21025
21351
  // src/emf-plus-image-resample.ts
21026
21352
  var INTERPOLATION_KERNELS = {
21027
21353
  0: "bilinear",
@@ -21074,6 +21400,20 @@ function snapToDeviceGrid(spec) {
21074
21400
  const [a, b, c, d] = m;
21075
21401
  return [a, b, c, d, ox - a * spec.srcX - c * spec.srcY, oy - b * spec.srcX - d * spec.srcY];
21076
21402
  }
21403
+ function snapOriginKeepCorners(spec) {
21404
+ const m = spec.toDevice;
21405
+ const map = (u, v) => [m[0] * u + m[2] * v + m[4], m[1] * u + m[3] * v + m[5]];
21406
+ const [rx, ry] = map(spec.srcX, spec.srcY);
21407
+ const ox = Math.round(rx * SUBPIXEL_GRID) / SUBPIXEL_GRID;
21408
+ const oy = Math.round(ry * SUBPIXEL_GRID) / SUBPIXEL_GRID;
21409
+ const [ux, uy] = map(spec.srcX + spec.srcW, spec.srcY);
21410
+ const [vx, vy] = map(spec.srcX, spec.srcY + spec.srcH);
21411
+ const a = (ux - ox) / spec.srcW;
21412
+ const b = (uy - oy) / spec.srcW;
21413
+ const c = (vx - ox) / spec.srcH;
21414
+ const d = (vy - oy) / spec.srcH;
21415
+ return [a, b, c, d, ox - a * spec.srcX - c * spec.srcY, oy - b * spec.srcX - d * spec.srcY];
21416
+ }
21077
21417
  function cubicKernel(t, a) {
21078
21418
  const x = Math.abs(t);
21079
21419
  if (x < 1) {
@@ -21100,18 +21440,6 @@ function cubicIntegral(t, a) {
21100
21440
  }
21101
21441
  return Math.sign(t) * v;
21102
21442
  }
21103
- var FAR_FADE = [1, 1, 0.985, 0.95, 0.91, 0.85, 0.8, 0.745, 0.69, 0.63, 0.56, 0.5, 0.43, 0.35, 0.28, 0.22, 0.16, 0.11, 0.065, 0.03, 0];
21104
- function fadeAt(d, bilinear) {
21105
- if (d >= 1) {
21106
- return 0;
21107
- }
21108
- if (bilinear) {
21109
- return 1 - Math.max(0, d);
21110
- }
21111
- const x = Math.max(0, d) * 20;
21112
- const i = Math.floor(x);
21113
- return FAR_FADE[i] + (FAR_FADE[i + 1] - FAR_FADE[i]) * (x - i);
21114
- }
21115
21443
  function ceilExtent(len) {
21116
21444
  return Math.ceil(len * (1 - 15e-8));
21117
21445
  }
@@ -21119,6 +21447,17 @@ function nearSourceExtent(deviceLen, srcLen) {
21119
21447
  const d = ceilExtent(deviceLen) - srcLen;
21120
21448
  return d >= -1 && d <= 1;
21121
21449
  }
21450
+ function unitCopyOffset(t, other, spec) {
21451
+ const f = t - Math.round(t);
21452
+ if (f > -1 / 64 + 1e-9) {
21453
+ return f <= 1 / 64 + 1e-9;
21454
+ }
21455
+ if (Math.abs(f + 1 / 64) > 1e-9 || !isPowerOfTwo(spec.srcW) || !isPowerOfTwo(spec.srcH)) {
21456
+ return false;
21457
+ }
21458
+ const g = (other - Math.round(other)) * 128;
21459
+ return spec.srcW * spec.srcH * Math.max(spec.srcW, spec.srcH) <= 256 || Math.abs(g - Math.round(g)) < 1e-9;
21460
+ }
21122
21461
  var BICUBIC_A = -0.5;
21123
21462
  var HQ_BICUBIC_A = -1;
21124
21463
  function axisFilter(kernel, scale, copy) {
@@ -21238,6 +21577,9 @@ function resampleImage(rgba, width, height, spec, surface, options2 = {}) {
21238
21577
  }
21239
21578
  return resampleImage(grown, width + 1, height, { ...spec, rightHalo: void 0 }, surface);
21240
21579
  }
21580
+ if (spec.wrap === "clamp" && (spec.clampArgb ?? 0) >>> 24 === 0 && (spec.kernel === "hq-bicubic" || spec.kernel === "hq-bilinear")) {
21581
+ return resampleImage(rgba, width, height, { ...spec, wrap: void 0, clampArgb: void 0 }, surface, options2);
21582
+ }
21241
21583
  if (spec.kernel === "nearest" && !spec.wrap) {
21242
21584
  return resampleNearest(rgba, width, height, spec, surface);
21243
21585
  }
@@ -21248,32 +21590,21 @@ function resampleImage(rgba, width, height, spec, surface, options2 = {}) {
21248
21590
  m = [m[0], 0, 0, m[3], m[4], m[5]];
21249
21591
  }
21250
21592
  const axisAligned = m[1] === 0 && m[2] === 0;
21593
+ if (hq && !axisAligned && !keepOrigin) {
21594
+ m = snapOriginKeepCorners(spec);
21595
+ }
21251
21596
  let plainRotated = plainRotatedPass;
21252
- const unitBicubicCopy = kernel === "bicubic" && axisAligned && !spec.halfPixelOffset && m[0] === 1 && m[3] === 1 && m[4] - Math.round(m[4]) > -1 / 64 && m[4] - Math.round(m[4]) <= 1 / 64 && m[5] - Math.round(m[5]) > -1 / 64 && m[5] - Math.round(m[5]) <= 1 / 64;
21253
- let farFade = false;
21597
+ const unitBicubicCopy = kernel === "bicubic" && axisAligned && !spec.halfPixelOffset && m[0] === 1 && m[3] === 1 && unitCopyOffset(m[4], m[5], spec) && unitCopyOffset(m[5], m[4], spec);
21254
21598
  let shiftX = 0;
21255
21599
  let shiftY = 0;
21256
21600
  if (hq && !axisAligned) {
21257
21601
  const extentU = Math.hypot(m[0], m[1]) * spec.srcW;
21258
21602
  const extentV = Math.hypot(m[2], m[3]) * spec.srcH;
21259
21603
  const near = nearSourceExtent(extentU, spec.srcW) || nearSourceExtent(extentV, spec.srcH);
21260
- if (!spec.wrap) {
21261
- return resampleRotatedTwoStage(rgba, width, height, spec, surface, m, kernel, near);
21262
- } else if (near) {
21263
- kernel = kernel === "hq-bicubic" ? "bicubic" : "bilinear";
21264
- plainRotated = true;
21265
- } else {
21266
- farFade = true;
21267
- if (spec.halfPixelOffset) {
21268
- const lu = Math.hypot(m[0], m[1]);
21269
- const lv = Math.hypot(m[2], m[3]);
21270
- shiftX = 0.5 * m[0] / lu + 0.5 * m[2] / lv;
21271
- shiftY = 0.5 * m[1] / lu + 0.5 * m[3] / lv;
21272
- }
21273
- }
21604
+ return resampleRotatedTwoStage(rgba, width, height, spec, surface, m, kernel, near);
21274
21605
  }
21275
21606
  const integerBicubic = kernel === "bicubic" && (axisAligned || plainRotated);
21276
- if (hq && axisAligned && !spec.wrap && !premultSource) {
21607
+ if (hq && axisAligned && !premultSource) {
21277
21608
  const phased = resampleHqAxisAligned(rgba, width, height, spec, surface, m, premultOut);
21278
21609
  if (phased !== void 0) {
21279
21610
  return phased;
@@ -21334,8 +21665,8 @@ function resampleImage(rgba, width, height, spec, surface, options2 = {}) {
21334
21665
  const vMax = spec.srcY + spec.srcH;
21335
21666
  const wu = [];
21336
21667
  const wv = [];
21337
- const gradU = Math.hypot(inv2[0], inv2[2]);
21338
- const gradV = Math.hypot(inv2[1], inv2[3]);
21668
+ Math.hypot(inv2[0], inv2[2]);
21669
+ Math.hypot(inv2[1], inv2[3]);
21339
21670
  const c = spec.clampArgb ?? 0;
21340
21671
  const edge = {
21341
21672
  wrap: spec.wrap,
@@ -21391,18 +21722,6 @@ function resampleImage(rgba, width, height, spec, surface, options2 = {}) {
21391
21722
  return blendSeparable(rgba, width, box, iu0, wu, iv0, wv, kernel === "bicubic", edge, integerBicubic, premultSource);
21392
21723
  };
21393
21724
  let [r, g, b, a] = sampleAt(u, v);
21394
- if (farFade && !spec.wrap && a > 0) {
21395
- const du = (uMax - u) / gradU;
21396
- const dv = (vMax - v) / gradV;
21397
- const k = 1 - (du < 1 ? fadeAt(du, kernel === "hq-bilinear") * (sampleAt(uMax, v)[3] / a) : 0) - (dv < 1 ? fadeAt(dv, kernel === "hq-bilinear") * (sampleAt(u, vMax)[3] / a) : 0);
21398
- if (k < 1) {
21399
- const f = Math.max(0, k);
21400
- r *= f;
21401
- g *= f;
21402
- b *= f;
21403
- a *= f;
21404
- }
21405
- }
21406
21725
  if (a <= 0) {
21407
21726
  continue;
21408
21727
  }
@@ -21430,21 +21749,74 @@ function resampleImage(rgba, width, height, spec, surface, options2 = {}) {
21430
21749
  return { x: bx0, y: by0, w, h, rgba: out };
21431
21750
  }
21432
21751
  var HQ_PHASES = 128;
21752
+ function isPowerOfTwo(v) {
21753
+ return Number.isInteger(v) && v > 0 && (v & v - 1) === 0;
21754
+ }
21755
+ function mirroredUnitIsExact(spec) {
21756
+ return !spec.pointsForm || isPowerOfTwo(spec.srcW) && isPowerOfTwo(spec.srcH);
21757
+ }
21758
+ function mirroredBias(spec, scale, fractionalEdge) {
21759
+ if (mirroredUnitIsExact(spec)) {
21760
+ return scale === 1 ? -(fractionalEdge ? 2 : 1) * 65536 + (spec.kernel === "hq-bicubic" ? 1 : 0) : 0;
21761
+ }
21762
+ return scale <= 1 ? 1 : 0;
21763
+ }
21764
+ function hqStep(scale) {
21765
+ return Math.round(65536 / scale);
21766
+ }
21767
+ function hqTentCdf(j) {
21768
+ if (j <= -128) {
21769
+ return -32768;
21770
+ }
21771
+ if (j >= 128) {
21772
+ return 32768;
21773
+ }
21774
+ return j < 0 ? -(512 * -j - 2 * j * j) : 512 * j - 2 * j * j;
21775
+ }
21776
+ function hqReductionTaps(cubic, scale, step, position, origin, from, to) {
21777
+ const taps = [];
21778
+ const s = Math.fround(scale);
21779
+ const radius = (cubic ? 2 : 1) * (step / 65536) + 1;
21780
+ for (let k = from; k <= to; k++) {
21781
+ const p = position(k);
21782
+ const centre = origin + p / 65536;
21783
+ const first = Math.ceil(centre - radius);
21784
+ const last = Math.floor(centre + radius);
21785
+ const weights = [];
21786
+ let prev = Number.NaN;
21787
+ for (let t = first; t <= last + 1; t++) {
21788
+ const q = 128 * s * (t - 0.5 - origin - p / 65536);
21789
+ const edge = Math.floor(q);
21790
+ const cdf = cubic ? hqCubicCdf(edge) : hqTentCdf(edge);
21791
+ if (t > first) {
21792
+ weights.push((cdf - prev) / 65536);
21793
+ }
21794
+ prev = cdf;
21795
+ }
21796
+ taps.push({ first, weights });
21797
+ }
21798
+ return taps;
21799
+ }
21433
21800
  function resampleHqAxisAligned(rgba, width, height, spec, surface, m, premultOut) {
21434
21801
  const kernel = spec.kernel;
21435
- const scaleU = m[0];
21802
+ const mirrorU = m[0] < 0;
21803
+ const scaleU = Math.abs(m[0]);
21436
21804
  const scaleV = m[3];
21437
- if (!(scaleU >= 1 && scaleV >= 1) || spec.rightHalo) {
21805
+ if (!(scaleU > 0 && scaleV > 0) || spec.rightHalo) {
21438
21806
  return void 0;
21439
21807
  }
21440
21808
  const integral = (v) => Math.abs(v - Math.round(v)) < 1e-9;
21441
- if (scaleU === 1 && scaleV === 1 && integral(m[4]) && integral(m[5])) {
21809
+ if (scaleU === 1 && scaleV === 1 && !mirrorU && integral(m[4]) && integral(m[5])) {
21442
21810
  return void 0;
21443
21811
  }
21812
+ const unitMirror = mirrorU && scaleU === 1;
21444
21813
  const shift = spec.halfPixelOffset ? 0.5 : 0;
21445
- const left = m[0] * spec.srcX + m[4] - shift;
21814
+ const edge0 = m[0] * spec.srcX + m[4] - shift;
21815
+ const edge1 = edge0 + m[0] * spec.srcW;
21816
+ const rawLeft = spec.toDevice[0] * (spec.srcX + spec.srcW) + spec.toDevice[4] - shift;
21817
+ const left = mirrorU ? Math.round(rawLeft * SUBPIXEL_GRID) / SUBPIXEL_GRID : Math.min(edge0, edge1);
21446
21818
  const top = m[3] * spec.srcY + m[5] - shift;
21447
- const right = left + m[0] * spec.srcW;
21819
+ const right = mirrorU ? left + scaleU * spec.srcW : Math.max(edge0, edge1);
21448
21820
  const bottom = top + m[3] * spec.srcH;
21449
21821
  const xFirst = Math.ceil(left - COVERAGE_NUDGE_X);
21450
21822
  const xLast = Math.ceil(right - COVERAGE_NUDGE_X) - 1;
@@ -21464,43 +21836,86 @@ function resampleHqAxisAligned(rgba, width, height, spec, surface, m, premultOut
21464
21836
  }
21465
21837
  const cubic = kernel === "hq-bicubic";
21466
21838
  const bin = cubic ? 0.5 : 1;
21467
- const stepU = Math.round(65536 / scaleU);
21468
- const stepV = Math.round(65536 / scaleV);
21469
- const dx = Math.max(0, xFirst - left);
21839
+ const stepU = hqStep(scaleU);
21840
+ const stepV = hqStep(scaleV);
21841
+ const rawLeftEdge = mirrorU ? rawLeft : spec.toDevice[0] * spec.srcX + spec.toDevice[4] - shift;
21842
+ const dxRaw = xFirst - rawLeftEdge;
21843
+ const dx = dxRaw < 1e-5 ? 0 : dxRaw;
21470
21844
  const dy = Math.max(0, yFirst - top);
21471
- const offsetU = dx > 1e-9 ? Math.round((1 - dx) * stepU) : 0;
21845
+ if (mirrorU && (spec.halfPixelOffset || !integral(spec.srcX) || !integral(spec.srcW))) {
21846
+ return void 0;
21847
+ }
21848
+ const mirroredPixels = xLast - xFirst + 1 + dx;
21849
+ const offsetU = !mirrorU && dx > 1e-9 ? Math.round((1 - dx) * stepU) : 0;
21472
21850
  const offsetV = dy > 1e-9 ? Math.round(dy * stepV) : 0;
21473
21851
  const filterU = axisFilter(kernel, scaleU, false);
21474
21852
  const filterV = axisFilter(kernel, scaleV, false);
21475
- const tapsFor = (filter, step, offset, origin, from, to) => {
21853
+ const tapsFor = (filter, step, offset, origin, from, to, scale, mirror2 = false) => {
21476
21854
  const taps = [];
21855
+ const farBias = ((step & step - 1) === 0 ? 0 : Math.round(spec.srcW / 170)) + (mirror2 ? mirroredBias(spec, scale, dx > 1e-9) : 0);
21856
+ const position = (k) => mirror2 ? Math.round((mirroredPixels - k) * step) + farBias : k * step + offset;
21857
+ if (mirror2 && unitMirror && dx <= 1e-9 && mirroredUnitIsExact(spec)) {
21858
+ for (let k = from; k <= to; k++) {
21859
+ taps.push({ first: Math.round(origin + position(k) / 65536), weights: [1] });
21860
+ }
21861
+ return taps;
21862
+ }
21863
+ const originBins = origin * HQ_PHASES;
21864
+ const wholeBins = Math.abs(originBins - Math.round(originBins)) < 1e-6;
21865
+ if (scale < 1 && wholeBins) {
21866
+ return hqReductionTaps(cubic, scale, step, position, origin, from, to);
21867
+ }
21868
+ const tabulated = cubic && wholeBins;
21477
21869
  for (let k = from; k <= to; k++) {
21478
- const phase = Math.floor((k * step + offset - 1) / (65536 / HQ_PHASES));
21479
- const c = origin + (phase + bin) / HQ_PHASES;
21480
- const first = Math.ceil(c - filter.radius);
21481
- const last = Math.floor(c + filter.radius);
21870
+ const phase = Math.floor((position(k) - 1) / (65536 / HQ_PHASES));
21871
+ if (tabulated) {
21872
+ const total = Math.round(originBins) + phase;
21873
+ const bins = hqCubicBinWeights((total % HQ_PHASES + HQ_PHASES) % HQ_PHASES);
21874
+ taps.push({
21875
+ first: Math.floor(total / HQ_PHASES) + bins.first,
21876
+ weights: bins.weights.map((w2) => w2 / 65536)
21877
+ });
21878
+ continue;
21879
+ }
21880
+ const c2 = origin + (phase + bin) / HQ_PHASES;
21881
+ const first = Math.ceil(c2 - filter.radius);
21882
+ const last = Math.floor(c2 + filter.radius);
21482
21883
  const weights = [];
21483
21884
  for (let t = first; t <= last; t++) {
21484
- weights.push(filter.weight(t, c));
21885
+ weights.push(filter.weight(t, c2));
21485
21886
  }
21486
21887
  taps.push({ first, weights });
21487
21888
  }
21488
21889
  return taps;
21489
21890
  };
21490
- const colTaps = tapsFor(filterU, stepU, offsetU, spec.srcX, cx0 - xFirst, cx1 - xFirst);
21491
- const rowTaps = tapsFor(filterV, stepV, offsetV, spec.srcY, cy0 - yFirst, cy1 - yFirst);
21891
+ const colTaps = tapsFor(filterU, stepU, offsetU, spec.srcX, cx0 - xFirst, cx1 - xFirst, scaleU, mirrorU);
21892
+ const rowTaps = tapsFor(filterV, stepV, offsetV, spec.srcY, cy0 - yFirst, cy1 - yFirst, scaleV);
21492
21893
  let rowMin = Infinity;
21493
21894
  let rowMax = -Infinity;
21494
21895
  for (const t of rowTaps) {
21495
21896
  rowMin = Math.min(rowMin, t.first);
21496
21897
  rowMax = Math.max(rowMax, t.first + t.weights.length - 1);
21497
21898
  }
21498
- rowMin = Math.max(0, rowMin);
21499
- rowMax = Math.min(height - 1, rowMax);
21899
+ const c = spec.clampArgb ?? 0;
21900
+ const edge = spec.wrap ? {
21901
+ wrap: spec.wrap,
21902
+ clamp: [c >>> 16 & 255, c >>> 8 & 255, c & 255, c >>> 24 & 255],
21903
+ mirrorX: spec.wrap === "tile-flip-x" || spec.wrap === "tile-flip-xy",
21904
+ mirrorY: spec.wrap === "tile-flip-y" || spec.wrap === "tile-flip-xy"
21905
+ } : null;
21906
+ if (!edge) {
21907
+ rowMin = Math.max(0, rowMin);
21908
+ rowMax = Math.min(height - 1, rowMax);
21909
+ }
21500
21910
  const rows = Math.max(0, rowMax - rowMin + 1);
21911
+ const rowMargin = edge || Math.abs(scaleV - 1) < 1e-9 ? Infinity : Math.ceil((cubic ? 2 : 1) / Math.min(1, scaleV));
21501
21912
  const inter = new Uint8Array(rows * w * 4);
21502
21913
  for (let r = 0; r < rows; r++) {
21503
- const srcRow = (rowMin + r) * width;
21914
+ const rowTexel = edge ? wrapTap(rowMin + r, 0, height, edge.mirrorY, edge) : rowMin + r;
21915
+ if (rowTexel === OUTSIDE_TRANSPARENT || rowTexel < spec.srcY - rowMargin || rowTexel > spec.srcY + spec.srcH + rowMargin - 1) {
21916
+ continue;
21917
+ }
21918
+ const srcRow = rowTexel * width;
21504
21919
  for (let i = 0; i < w; i++) {
21505
21920
  const t = colTaps[i];
21506
21921
  let pr = 0;
@@ -21508,19 +21923,30 @@ function resampleHqAxisAligned(rgba, width, height, spec, surface, m, premultOut
21508
21923
  let pb = 0;
21509
21924
  let pa = 0;
21510
21925
  for (let q = 0; q < t.weights.length; q++) {
21511
- const tx = t.first + q;
21512
- if (tx < 0 || tx >= width) {
21926
+ let tx = t.first + q;
21927
+ let px = rgba;
21928
+ let o = 0;
21929
+ if (edge) {
21930
+ tx = wrapTap(tx, 0, width, edge.mirrorX, edge);
21931
+ if (tx === OUTSIDE_TRANSPARENT) {
21932
+ continue;
21933
+ }
21934
+ } else if (tx < 0 || tx >= width) {
21513
21935
  continue;
21514
21936
  }
21515
- const o = (srcRow + tx) * 4;
21516
- const a = rgba[o + 3];
21937
+ if (tx === OUTSIDE_CLAMP || rowTexel === OUTSIDE_CLAMP) {
21938
+ px = edge?.clamp ?? [0, 0, 0, 0];
21939
+ } else {
21940
+ o = (srcRow + tx) * 4;
21941
+ }
21942
+ const a = px[o + 3];
21517
21943
  if (a === 0) {
21518
21944
  continue;
21519
21945
  }
21520
21946
  const wq = t.weights[q];
21521
- pr += wq * Math.round(rgba[o] * a / 255);
21522
- pg += wq * Math.round(rgba[o + 1] * a / 255);
21523
- pb += wq * Math.round(rgba[o + 2] * a / 255);
21947
+ pr += wq * Math.round(px[o] * a / 255);
21948
+ pg += wq * Math.round(px[o + 1] * a / 255);
21949
+ pb += wq * Math.round(px[o + 2] * a / 255);
21524
21950
  pa += wq * a;
21525
21951
  }
21526
21952
  const alpha = Math.min(255, Math.max(0, Math.round(pa)));
@@ -21566,7 +21992,7 @@ function resampleHqAxisAligned(rgba, width, height, spec, surface, m, premultOut
21566
21992
  return { x: cx0, y: cy0, w, h, rgba: out, premultiplied: premultOut };
21567
21993
  }
21568
21994
  function resampleRotatedTwoStage(rgba, width, height, spec, surface, m, kernel, near) {
21569
- const pad = 2;
21995
+ const pad = spec.wrap ? 0 : 2;
21570
21996
  let img;
21571
21997
  let pw;
21572
21998
  let ph;
@@ -21607,7 +22033,9 @@ function resampleRotatedTwoStage(rgba, width, height, spec, surface, m, kernel,
21607
22033
  srcH: spec.srcH,
21608
22034
  toDevice: [kx, 0, 0, ky, -spec.srcX * kx, -spec.srcY * ky],
21609
22035
  kernel,
21610
- halfPixelOffset: false
22036
+ halfPixelOffset: false,
22037
+ wrap: spec.wrap,
22038
+ clampArgb: spec.clampArgb
21611
22039
  }, { w: W, h: H }, { premultOut: true });
21612
22040
  if (!pre) {
21613
22041
  return null;
@@ -21648,7 +22076,9 @@ function resampleRotatedTwoStage(rgba, width, height, spec, surface, m, kernel,
21648
22076
  srcH: ph,
21649
22077
  toDevice: [a, b, c, d, ex - a * pad - c * pad, ey - b * pad - d * pad],
21650
22078
  kernel: kernel === "hq-bicubic" ? "bicubic" : "bilinear",
21651
- halfPixelOffset: false
22079
+ halfPixelOffset: false,
22080
+ wrap: spec.wrap,
22081
+ clampArgb: spec.clampArgb
21652
22082
  }, surface, { plainRotated: true, keepOrigin: true, premultSource: true });
21653
22083
  if (!block) {
21654
22084
  return block;
@@ -23772,21 +24202,21 @@ function popState(rCtx, stackId) {
23772
24202
  if (idx !== void 0 && idx < rCtx.saveStack.length) {
23773
24203
  const saved = rCtx.saveStack[idx];
23774
24204
  rCtx.worldTransform = [...saved.transform];
23775
- const snap = saved.snapshot;
23776
- if (snap) {
23777
- rCtx.clipRegion = snap.clipRegion;
23778
- rCtx.antiAlias = snap.antiAlias;
23779
- rCtx.interpolationMode = snap.interpolationMode;
23780
- rCtx.pixelOffsetMode = snap.pixelOffsetMode;
23781
- rCtx.textRenderingHint = snap.textRenderingHint;
23782
- rCtx.pageUnit = snap.pageUnit;
23783
- rCtx.pageScale = snap.pageScale;
24205
+ const snap2 = saved.snapshot;
24206
+ if (snap2) {
24207
+ rCtx.clipRegion = snap2.clipRegion;
24208
+ rCtx.antiAlias = snap2.antiAlias;
24209
+ rCtx.interpolationMode = snap2.interpolationMode;
24210
+ rCtx.pixelOffsetMode = snap2.pixelOffsetMode;
24211
+ rCtx.textRenderingHint = snap2.textRenderingHint;
24212
+ rCtx.pageUnit = snap2.pageUnit;
24213
+ rCtx.pageScale = snap2.pageScale;
23784
24214
  const ext = plusExt(rCtx);
23785
24215
  const { multiFormatSkip, pendingEffect } = ext;
23786
24216
  for (const key of Object.keys(ext)) {
23787
24217
  delete ext[key];
23788
24218
  }
23789
- Object.assign(ext, snap.ext, { multiFormatSkip, pendingEffect });
24219
+ Object.assign(ext, snap2.ext, { multiFormatSkip, pendingEffect });
23790
24220
  }
23791
24221
  rCtx.saveStack.length = idx;
23792
24222
  const newMap = /* @__PURE__ */ new Map();
@@ -23796,7 +24226,7 @@ function popState(rCtx, stackId) {
23796
24226
  }
23797
24227
  }
23798
24228
  rCtx.saveIdMap = newMap;
23799
- if (snap) {
24229
+ if (snap2) {
23800
24230
  reapplyPlusClip(rCtx);
23801
24231
  }
23802
24232
  }
@@ -25265,6 +25695,7 @@ function defaultGS() {
25265
25695
  deltaShift: 3,
25266
25696
  instructControl: 0,
25267
25697
  scanControl: false,
25698
+ scanSet: false,
25268
25699
  scanType: 0,
25269
25700
  gep0: 1,
25270
25701
  gep1: 1,
@@ -25277,6 +25708,13 @@ function defaultGS() {
25277
25708
  var HintError = class extends Error {
25278
25709
  };
25279
25710
  var MAX_INSTRUCTIONS = 1e6;
25711
+ var SIZE_TWEAK_BODIES = [
25712
+ // MPPEM GTEQ SWAP MPPEM LTEQ AND IF SHPIX ELSE POP POP EIF
25713
+ [75, 83, 35, 75, 81, 90, 88, 56, 27, 33, 33, 89],
25714
+ // MPPEM EQ IF SHPIX ELSE POP POP EIF
25715
+ [75, 84, 88, 56, 27, 33, 33, 89]
25716
+ ];
25717
+ var DEFAULT_DROPOUT_PPEM = 32;
25280
25718
  var HintedSize = class _HintedSize {
25281
25719
  constructor(font, ppemX, ppemY, env, hinting = true) {
25282
25720
  this.fdefs = [];
@@ -25293,6 +25731,8 @@ var HintedSize = class _HintedSize {
25293
25731
  this.callFrames = [];
25294
25732
  /** The glyph program being run belongs to a composite glyph. */
25295
25733
  this.inComposite = false;
25734
+ /** IUP[y] has run in the current glyph program. */
25735
+ this.iupy = false;
25296
25736
  this.count = 0;
25297
25737
  this.font = font;
25298
25738
  this.env = env;
@@ -25360,7 +25800,7 @@ var HintedSize = class _HintedSize {
25360
25800
  }
25361
25801
  /** The scan-conversion mode prep left, used when a glyph program doesn't set its own. */
25362
25802
  get defaultScan() {
25363
- return { scanControl: this.gs0.scanControl, scanType: this.gs0.scanType };
25803
+ return { scanControl: this.gs0.scanControl, scanSet: this.gs0.scanSet, scanType: this.gs0.scanType };
25364
25804
  }
25365
25805
  // -----------------------------------------------------------------------
25366
25806
  // Glyph loading
@@ -25388,6 +25828,7 @@ var HintedSize = class _HintedSize {
25388
25828
  advance: pp2x - pp1x,
25389
25829
  linearAdvance: mulFix(advance, this.xScale),
25390
25830
  scanControl: res2.scanControl,
25831
+ scanSet: res2.scanSet,
25391
25832
  scanType: res2.scanType
25392
25833
  };
25393
25834
  }
@@ -25452,7 +25893,7 @@ var HintedSize = class _HintedSize {
25452
25893
  let lastScan = scan;
25453
25894
  for (const comp of glyph.components) {
25454
25895
  const sub = this.loadRecursive(comp.glyphIndex, depth + 1);
25455
- lastScan = { scanControl: sub.scanControl, scanType: sub.scanType };
25896
+ lastScan = { scanControl: sub.scanControl, scanSet: sub.scanSet, scanType: sub.scanType };
25456
25897
  const z = sub.zone;
25457
25898
  const m = z.n - 4;
25458
25899
  if (comp.flags & (WE_HAVE_A_SCALE | WE_HAVE_AN_X_AND_Y_SCALE | WE_HAVE_A_TWO_BY_TWO)) {
@@ -25588,12 +26029,13 @@ var HintedSize = class _HintedSize {
25588
26029
  this.pts = zone;
25589
26030
  this.zp0 = this.zp1 = this.zp2 = zone;
25590
26031
  this.stack = [];
26032
+ this.iupy = false;
25591
26033
  this.computeFuncs();
25592
26034
  try {
25593
26035
  this.execute(instructions);
25594
26036
  } catch {
25595
26037
  }
25596
- return { zone, scanControl: this.gs.scanControl, scanType: this.gs.scanType };
26038
+ return { zone, scanControl: this.gs.scanControl, scanSet: this.gs.scanSet, scanType: this.gs.scanType };
25597
26039
  }
25598
26040
  // -----------------------------------------------------------------------
25599
26041
  // Vector / projection machinery
@@ -25693,14 +26135,21 @@ var HintedSize = class _HintedSize {
25693
26135
  }
25694
26136
  /**
25695
26137
  * Backward-compatible ClearType reads storage 22 (TypeMan Talk
25696
- * DStroke/IStroke), 24 (spacing functions) and 8 (VacuFormRound) as 0
25697
- * inside the functions whose signatures Microsoft documents, which
25698
- * bypasses them.
26138
+ * DStroke/IStroke) and 24 (spacing functions) as 0 inside the functions
26139
+ * whose signatures Microsoft documents, which bypasses them, and storage
26140
+ * 8 (VacuFormRound) as 0 wherever it is read: the Monotype fonts store
26141
+ * there whether the size is small (`MPPEM <= limit`) and, when it is,
26142
+ * run a block of corner-squaring ALIGNRP and SHPIX calls after the IUPs
26143
+ * that native ClearType never runs (Arial and Times New Roman bowls at
26144
+ * 9 to 17 ppem; 2,890 to 3,059 of 3,720 size-sheet captures exact).
25699
26145
  */
25700
26146
  ctBypassStorage(i) {
25701
26147
  if (!this.ctCompat() || i !== 22 && i !== 24 && i !== 8) {
25702
26148
  return false;
25703
26149
  }
26150
+ if (i === 8) {
26151
+ return true;
26152
+ }
25704
26153
  const frame2 = this.callFrames[this.callFrames.length - 1];
25705
26154
  if (!frame2) {
25706
26155
  return false;
@@ -25711,10 +26160,7 @@ var HintedSize = class _HintedSize {
25711
26160
  if (i === 22) {
25712
26161
  return at([176, 22, 67, 88]);
25713
26162
  }
25714
- if (i === 24) {
25715
- return at([1, 176, 24, 67, 88]) || at([1, 24, 176, 24, 67, 88]);
25716
- }
25717
- return at([69, 35, 70, 96, 32, 176, 38]);
26163
+ return at([1, 176, 24, 67, 88]) || at([1, 24, 176, 24, 67, 88]);
25718
26164
  }
25719
26165
  /** True when the projection vector points (mostly) along x, ClearType's direction. */
25720
26166
  ctDirection() {
@@ -25884,6 +26330,27 @@ var HintedSize = class _HintedSize {
25884
26330
  this.stack.push(v | 0);
25885
26331
  }
25886
26332
  /** Returns the length of the instruction at `ip` (for skipping). */
26333
+ /**
26334
+ * True for the two generic per-size tweak helpers of Monotype-hinted fonts
26335
+ * (Arial, Times New Roman, Tahoma), whose whole body is `MPPEM >= lo and
26336
+ * MPPEM <= hi: SHPIX` or `MPPEM == ppem: SHPIX`. Native ClearType ignores
26337
+ * the x shifts they issue; the mode-selected variants (the same body behind
26338
+ * `RS 2` / `EQ`), inline shifts and every other function are applied. Measured on
26339
+ * private fonts (`shpix-*.ttf`): any other body, such as extra bytes before
26340
+ * or after the helper, strict comparisons or a missing ELSE branch, is
26341
+ * applied, and the function number does not matter.
26342
+ */
26343
+ static isSizeTweak(def) {
26344
+ if (def.sizeTweak === void 0) {
26345
+ const n = def.end - def.start;
26346
+ def.sizeTweak = SIZE_TWEAK_BODIES.some((body) => body.length === n && body.every((b, i) => def.code[def.start + i] === b));
26347
+ }
26348
+ return def.sizeTweak;
26349
+ }
26350
+ inSizeTweak() {
26351
+ const frame2 = this.callFrames[this.callFrames.length - 1];
26352
+ return !!frame2 && _HintedSize.isSizeTweak(frame2.def);
26353
+ }
25887
26354
  static insLength(code, ip) {
25888
26355
  const op = code[ip];
25889
26356
  if (op === 64) {
@@ -25903,6 +26370,7 @@ var HintedSize = class _HintedSize {
25903
26370
  execute(code) {
25904
26371
  const calls = [];
25905
26372
  this.callFrames = calls;
26373
+ this.count = 0;
25906
26374
  let ip = 0;
25907
26375
  let cur = code;
25908
26376
  while (true) {
@@ -26350,7 +26818,7 @@ var HintedSize = class _HintedSize {
26350
26818
  while (gs.loop > 0) {
26351
26819
  const p = this.pop();
26352
26820
  if (p >= 0 && p < this.zp2.n) {
26353
- const keep = !this.ctCompat() || this.inComposite || gs.fvx === 0 && (this.zp2.tags[p] & TOUCH_Y) !== 0;
26821
+ const keep = !this.ctCompat() || this.inComposite || gs.fvx === 0 && (this.zp2.tags[p] & TOUCH_Y) !== 0 || gs.fvx !== 0 && !this.env.grayscale && !this.inSizeTweak();
26354
26822
  if (keep) {
26355
26823
  this.moveZp2(p, dx, dy, true);
26356
26824
  }
@@ -26382,7 +26850,7 @@ var HintedSize = class _HintedSize {
26382
26850
  this.zp1.curY[p] - this.zp0.curY[gs.rp0]
26383
26851
  );
26384
26852
  let target = d;
26385
- if (this.ctCompat() && gs.gep0 !== 0 && gs.gep1 !== 0) {
26853
+ if (this.ctCompat() && this.ctDirection() && gs.gep0 !== 0 && gs.gep1 !== 0) {
26386
26854
  const org = this.dualProjectOrus(
26387
26855
  this.zp1.orusX[p] - this.zp0.orusX[gs.rp0],
26388
26856
  this.zp1.orusY[p] - this.zp0.orusY[gs.rp0]
@@ -26675,6 +27143,7 @@ var HintedSize = class _HintedSize {
26675
27143
  case 133: {
26676
27144
  const v = this.pop();
26677
27145
  const a = v & 255;
27146
+ gs.scanSet = true;
26678
27147
  if (a === 255) {
26679
27148
  gs.scanControl = true;
26680
27149
  return true;
@@ -26685,10 +27154,10 @@ var HintedSize = class _HintedSize {
26685
27154
  }
26686
27155
  if (v & 256 && this.ppem <= a) gs.scanControl = true;
26687
27156
  if (v & 512 && this.env.rotated) gs.scanControl = true;
26688
- if (v & 1024 && this.stretched) gs.scanControl = true;
27157
+ if (v & 1024 && (this.stretched || this.env.reportStretched)) gs.scanControl = true;
26689
27158
  if (v & 2048 && this.ppem > a) gs.scanControl = false;
26690
27159
  if (v & 4096 && this.env.rotated) gs.scanControl = false;
26691
- if (v & 8192 && this.stretched) gs.scanControl = false;
27160
+ if (v & 8192 && (this.stretched || this.env.reportStretched)) gs.scanControl = false;
26692
27161
  return true;
26693
27162
  }
26694
27163
  case 134:
@@ -26700,7 +27169,7 @@ var HintedSize = class _HintedSize {
26700
27169
  let k = 0;
26701
27170
  if (sel & 1) k = this.env.version;
26702
27171
  if (sel & 2 && this.env.rotated) k |= 1 << 8;
26703
- if (sel & 4 && this.stretched) k |= 1 << 9;
27172
+ if (sel & 4 && (this.stretched || this.env.reportStretched)) k |= 1 << 9;
26704
27173
  if (sel & 32 && this.env.grayscale) k |= 1 << 12;
26705
27174
  if (sel & 64 && this.env.clearType) k |= 1 << 13;
26706
27175
  if (sel & 128 && this.env.clearType && this.env.compatibleWidths !== false) k |= 1 << 14;
@@ -27002,6 +27471,7 @@ var HintedSize = class _HintedSize {
27002
27471
  return this.dualProject(mulFix(dx, this.xScale), mulFix(dy, this.yScale));
27003
27472
  }
27004
27473
  insIUP(xAxis) {
27474
+ if (!xAxis) this.iupy = true;
27005
27475
  const z = this.pts;
27006
27476
  const mask = xAxis ? TOUCH_X : TOUCH_Y;
27007
27477
  const orgs = xAxis ? z.orgX : z.orgY;
@@ -27133,7 +27603,7 @@ var HintedSize = class _HintedSize {
27133
27603
  let s = (b & 15) - 8;
27134
27604
  if (s >= 0) s++;
27135
27605
  s *= 1 << 6 - this.gs.deltaShift;
27136
- if (this.ctCompat() && !(this.gs.fvx === 0 && (this.zp0.tags[a] & TOUCH_Y) !== 0)) {
27606
+ if (this.ctCompat() && (this.iupy || !(this.gs.fvx === 0 && (this.zp0.tags[a] & TOUCH_Y) !== 0))) {
27137
27607
  continue;
27138
27608
  }
27139
27609
  this.move(this.zp0, a, s);
@@ -27812,7 +28282,7 @@ function monoBox(o) {
27812
28282
  }
27813
28283
  return { xMin, xMax, yMin, yMax };
27814
28284
  }
27815
- function rasterizeMono(o, dropout, fixedBox) {
28285
+ function rasterizeMono(o, dropout, fixedBox, stubOvershoot = true) {
27816
28286
  const box = fixedBox ?? monoBox(o);
27817
28287
  if (!box) {
27818
28288
  return null;
@@ -27868,10 +28338,10 @@ function rasterizeMono(o, dropout, fixedBox) {
27868
28338
  break;
27869
28339
  case 1:
27870
28340
  case 5:
27871
- if (left.next === right && left.height <= 0 && !(left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
28341
+ if (left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= r.half)) {
27872
28342
  return;
27873
28343
  }
27874
- if (right.next === left && left.start === y && !(left.flags & OVERSHOOT_BOTTOM && x2 - x1 >= r.half)) {
28344
+ if (right.next === left && left.start === y && !(stubOvershoot && left.flags & OVERSHOOT_BOTTOM && x2 - x1 >= r.half)) {
27875
28345
  return;
27876
28346
  }
27877
28347
  pxl = mode === 1 ? e2 : r.floorPub(Math.floor((x1 + x2 + Math.floor(P * 63 / 64)) / 2));
@@ -27927,10 +28397,10 @@ function rasterizeMono(o, dropout, fixedBox) {
27927
28397
  break;
27928
28398
  case 1:
27929
28399
  case 5:
27930
- if (left.next === right && left.height <= 0 && !(left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
28400
+ if (left.next === right && left.height <= 0 && !(stubOvershoot && left.flags & OVERSHOOT_TOP && x2 - x1 >= h.half)) {
27931
28401
  return;
27932
28402
  }
27933
- if (right.next === left && left.start === col && !(left.flags & OVERSHOOT_BOTTOM && x2 - x1 >= h.half)) {
28403
+ if (right.next === left && left.start === col && !(stubOvershoot && left.flags & OVERSHOOT_BOTTOM && x2 - x1 >= h.half)) {
27934
28404
  return;
27935
28405
  }
27936
28406
  pxl = mode === 1 ? e2 : h.floorPub(Math.floor((x1 + x2 + Math.floor(P * 63 / 64)) / 2));
@@ -27956,7 +28426,7 @@ function rasterizeMono(o, dropout, fixedBox) {
27956
28426
  return { width, height, left: box.xMin, top: box.yMax, data };
27957
28427
  }
27958
28428
  var GRAY_OVERSAMPLE = 4;
27959
- function rasterizeSamples(o, kx, ky, padX = 0) {
28429
+ function rasterizeSamples(o, kx, ky, padX = 0, dropout = 2, stubOvershoot = true) {
27960
28430
  const n = o.xs.length;
27961
28431
  if (n === 0) {
27962
28432
  return null;
@@ -27985,10 +28455,10 @@ function rasterizeSamples(o, kx, ky, padX = 0) {
27985
28455
  onCurve: o.onCurve,
27986
28456
  endPts: o.endPts
27987
28457
  };
27988
- const hi = rasterizeMono(big, 2, { xMin: box.xMin * kx, xMax: box.xMax * kx, yMin: box.yMin * ky, yMax: box.yMax * ky });
28458
+ const hi = rasterizeMono(big, dropout, { xMin: box.xMin * kx, xMax: box.xMax * kx, yMin: box.yMin * ky, yMax: box.yMax * ky }, stubOvershoot);
27989
28459
  return hi ? { box, hi } : null;
27990
28460
  }
27991
- function rasterizeGray(o) {
28461
+ function rasterizeGray(o, dropout = 2) {
27992
28462
  const n = o.xs.length;
27993
28463
  if (n === 0) {
27994
28464
  return null;
@@ -28018,7 +28488,7 @@ function rasterizeGray(o) {
28018
28488
  onCurve: o.onCurve,
28019
28489
  endPts: o.endPts
28020
28490
  };
28021
- const hi = rasterizeMono(big, 2, { xMin: box.xMin * k, xMax: box.xMax * k, yMin: box.yMin * k, yMax: box.yMax * k });
28491
+ const hi = rasterizeMono(big, dropout, { xMin: box.xMin * k, xMax: box.xMax * k, yMin: box.yMin * k, yMax: box.yMax * k }, false);
28022
28492
  if (!hi) {
28023
28493
  return null;
28024
28494
  }
@@ -28076,7 +28546,8 @@ function slantRows(b) {
28076
28546
  }
28077
28547
  return { ...b, width, data };
28078
28548
  }
28079
- var RASTER_STRETCH_COST = [0, 0, 120, 150, 250, 250];
28549
+ var RASTER_STRETCH_COST = [0, 0, 120, 150, 250, 250, 1150, 1280, 1840];
28550
+ var RASTER_MAX_X_SCALE = 5;
28080
28551
  function unitOf(f) {
28081
28552
  return Math.max(1, f.pixHeight - f.internalLeading);
28082
28553
  }
@@ -28499,8 +28970,7 @@ var RealizedFont = class {
28499
28970
  const skew = m && !(Math.abs(m[1]) < 1e-9 && Math.abs(m[2]) < 1e-9) && !(Math.abs(m[0]) < 1e-9 && Math.abs(m[3]) < 1e-9);
28500
28971
  const src = skew ? this.rotatedOutline(index) : this.outline(index);
28501
28972
  if (skew && m) {
28502
- const p = this.ppem;
28503
- m = [Math.round(m[0] * p) / p, Math.round(m[1] * p) / p, Math.round(m[2] * p) / p, Math.round(m[3] * p) / p];
28973
+ m = roundedRotationMatrix(m, this.ppem);
28504
28974
  }
28505
28975
  let o = this.mode === "cleartype" && !m && !this.syntheticItalic ? this.ctOutline(index) : src;
28506
28976
  if (this.syntheticItalic || m || subX || subY) {
@@ -28526,11 +28996,12 @@ var RealizedFont = class {
28526
28996
  }
28527
28997
  let bitmap;
28528
28998
  if (this.mode === "mono") {
28529
- bitmap = rasterizeMono(o, dropoutMode(src.scanControl, src.scanType));
28999
+ bitmap = rasterizeMono(o, dropoutMode(src.scanSet ? src.scanControl : this.ppem <= DEFAULT_DROPOUT_PPEM, src.scanType));
28530
29000
  } else if (this.mode === "cleartype") {
28531
- bitmap = rasterizeClearType(o, this.gdiPlus);
29001
+ const dropout = src.scanSet ? dropoutMode(src.scanControl, src.scanType) : 2;
29002
+ bitmap = rasterizeClearType(o, this.gdiPlus, this.gdiPlus ? clearTypeSpread(this.ttf) : void 0, dropout);
28532
29003
  } else {
28533
- bitmap = rasterizeGray(o);
29004
+ bitmap = rasterizeGray(o, src.scanSet ? dropoutMode(src.scanControl, src.scanType) : 2);
28534
29005
  }
28535
29006
  if (bitmap && this.syntheticBold) {
28536
29007
  bitmap = embolden(bitmap, this.mode === "mono" ? 1 : 16);
@@ -28540,6 +29011,19 @@ var RealizedFont = class {
28540
29011
  return g;
28541
29012
  }
28542
29013
  };
29014
+ function roundedRotationMatrix(m, ppem) {
29015
+ const isRotation = Math.abs(m[0] - m[3]) < 1e-6 && Math.abs(m[1] + m[2]) < 1e-6;
29016
+ if (isRotation && ppem > 0) {
29017
+ const major = ppem * Math.max(Math.abs(m[0]), Math.abs(m[1]));
29018
+ const target = Math.round(major);
29019
+ if (target >= 1) {
29020
+ const k = target / major;
29021
+ return [m[0] * k, m[1] * k, m[2] * k, m[3] * k];
29022
+ }
29023
+ }
29024
+ const p = ppem;
29025
+ return [Math.round(m[0] * p) / p, Math.round(m[1] * p) / p, Math.round(m[2] * p) / p, Math.round(m[3] * p) / p];
29026
+ }
28543
29027
  function embolden(b, full) {
28544
29028
  const w = b.width + 1;
28545
29029
  const data = new Uint8Array(w * b.height);
@@ -28638,8 +29122,9 @@ var GdiFontCollection = class _GdiFontCollection {
28638
29122
  * heights for a negative lfHeight and cell heights for a positive one.
28639
29123
  * The cost model is fitted to GetTextMetrics over lfHeight -60..60 for
28640
29124
  * MS Sans Serif, MS Serif, Courier, Small Fonts, System and Terminal
28641
- * (98% exact): 150 per pixel too small; 290 plus 350 per pixel too big;
28642
- * a stretch cost by factor (120, 150, 250, 250 for 2x..5x) plus 100 per
29125
+ * (98% exact): 150 per pixel too small; 290 plus 340 per pixel too big;
29126
+ * a stretch cost by factor (120, 150, 250, 250 for 2x..5x and 1,150,
29127
+ * 1,280 and 1,840 for 6x..8x, the largest GDI uses) plus 100 per
28643
29128
  * extra factor divided by the face's character height (small faces
28644
29129
  * stretch less readily); ties go to the smaller stretch, then to the
28645
29130
  * 96 dpi face. A weight mismatch costs 3 per 10 units (so Terminal's
@@ -28659,9 +29144,9 @@ var GdiFontCollection = class _GdiFontCollection {
28659
29144
  let bestCost = Infinity;
28660
29145
  for (const f of pool) {
28661
29146
  const unit = height < 0 ? unitOf(f) : f.pixHeight;
28662
- for (let n = 1; n <= 5; n++) {
29147
+ for (let n = 1; n < RASTER_STRETCH_COST.length; n++) {
28663
29148
  const d = unit * n - target;
28664
- const cost = (d < 0 ? -d * 150 : d > 0 ? 290 + d * 350 : 0) + RASTER_STRETCH_COST[n] + (n > 1 ? 100 * (n - 1) / unitOf(f) : 0) + Math.abs(f.weight - weight) * 3 / 10 + n * 0.01 + (f.vertRes === 96 ? 0 : 1e-3);
29149
+ const cost = (d < 0 ? -d * 150 : d > 0 ? 290 + d * 340 : 0) + RASTER_STRETCH_COST[n] + (n > 1 ? 100 * (n - 1) / unitOf(f) : 0) + Math.abs(f.weight - weight) * 3 / 10 + n * 0.01 + (f.vertRes === 96 ? 0 : 1e-3);
28665
29150
  if (cost < bestCost) {
28666
29151
  bestCost = cost;
28667
29152
  best = { face: f, scale: n };
@@ -28677,7 +29162,7 @@ var GdiFontCollection = class _GdiFontCollection {
28677
29162
  return null;
28678
29163
  }
28679
29164
  const { face, scale } = pick;
28680
- const scaleX = spec.width > 0 && face.avgWidth > 0 ? Math.max(1, Math.ceil(spec.width / face.avgWidth - 0.5)) : scale;
29165
+ const scaleX = spec.width > 0 && face.avgWidth > 0 ? Math.max(1, Math.ceil(spec.width / face.avgWidth - 0.5)) : Math.min(scale, RASTER_MAX_X_SCALE);
28681
29166
  return new RasterRealizedFont(face, scale, weight >= 600 && face.weight < 600, scaleX, spec.italic && !face.italic);
28682
29167
  }
28683
29168
  /**
@@ -28828,9 +29313,15 @@ function resolvePpem(font, height) {
28828
29313
  return ppem;
28829
29314
  }
28830
29315
  var CLEARTYPE_OVERSAMPLE = 6;
28831
- function rasterizeClearType(o, truncate = false) {
29316
+ function clearTypeSpread(ttf) {
29317
+ if (ttf.family.toLowerCase() !== "courier new") {
29318
+ return void 0;
29319
+ }
29320
+ return { left: 1, right: ttf.weightClass >= 600 ? 1 : 2 };
29321
+ }
29322
+ function rasterizeClearType(o, truncate = false, spread, dropout = 2) {
28832
29323
  const S = CLEARTYPE_OVERSAMPLE / 3;
28833
- const r = rasterizeSamples(o, CLEARTYPE_OVERSAMPLE, 1, 1);
29324
+ const r = rasterizeSamples(o, CLEARTYPE_OVERSAMPLE, 1, 1, dropout, false);
28834
29325
  if (!r) {
28835
29326
  return null;
28836
29327
  }
@@ -28844,12 +29335,23 @@ function rasterizeClearType(o, truncate = false) {
28844
29335
  sub.fill(0);
28845
29336
  const row2 = y * hi.width;
28846
29337
  for (let x = 0; x < hi.width; x++) {
28847
- if (hi.data[row2 + x]) {
29338
+ let on = hi.data[row2 + x] !== 0;
29339
+ if (spread && !on) {
29340
+ for (let k = x - spread.right; k <= x + spread.left && !on; k++) {
29341
+ on = k >= 0 && k < hi.width && hi.data[row2 + k] !== 0;
29342
+ }
29343
+ }
29344
+ if (on) {
28848
29345
  sub[Math.floor(x / S)] += 1;
28849
29346
  }
28850
29347
  }
28851
29348
  for (let j = 0; j < n; j++) {
28852
- const acc = (j > 0 ? sub[j - 1] : 0) + sub[j] + (j + 1 < n ? sub[j + 1] : 0);
29349
+ const before = j > 0 ? sub[j - 1] : 0;
29350
+ const after = j + 1 < n ? sub[j + 1] : 0;
29351
+ let acc = before + sub[j] + after;
29352
+ if (spread && acc === 1 && sub[j] === 0 && (j % 3 === 0 && before === 1 || (j + 1) % 3 === 0 && after === 1)) {
29353
+ acc = 0;
29354
+ }
28853
29355
  data[y * n + j] = (truncate ? Math.floor : Math.round)(255 * acc / (3 * S));
28854
29356
  }
28855
29357
  }
@@ -30168,22 +30670,27 @@ function penPolygon(width, height = width) {
30168
30670
  return pen;
30169
30671
  }
30170
30672
  var matrixPenCache = /* @__PURE__ */ new Map();
30673
+ function halfVectorComponent(v) {
30674
+ return Math.sign(v) * Math.floor(Math.abs(v) + 0.75);
30675
+ }
30171
30676
  function penPolygonMatrix(width, m) {
30172
30677
  const key = `${width},${m.join(",")}`;
30173
30678
  const cached = matrixPenCache.get(key);
30174
30679
  if (cached) {
30175
30680
  return cached;
30176
30681
  }
30177
- const r = Math.ceil(width / 2);
30682
+ const scale = Math.hypot(m[0], m[1]);
30683
+ if (Math.abs(Math.hypot(m[2], m[3]) - scale) < 1e-4 * scale && Math.abs(m[0] * m[2] + m[1] * m[3]) < 1e-4 * scale * scale && width * scale < HOBBY_LIMIT) {
30684
+ const digital = penPolygon(Math.round(width * scale));
30685
+ matrixPenCache.set(key, digital);
30686
+ return digital;
30687
+ }
30688
+ const h = width / 2;
30178
30689
  const mirror2 = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
30179
- const bez = ellipseBeziers(-r, -r, r, r);
30180
- const dev = [];
30181
- for (let i = 0; i < 14; i += 2) {
30182
- const x = bez[i];
30183
- const y = bez[i + 1] * mirror2;
30184
- dev.push(Math.round(m[0] * x + m[2] * y), Math.round(m[1] * x + m[3] * y));
30185
- }
30186
- const f = flattenBezierPath(dev);
30690
+ const hx = [halfVectorComponent(m[0] * h), halfVectorComponent(m[1] * h)];
30691
+ const hy = [mirror2 * halfVectorComponent(m[2] * h), mirror2 * halfVectorComponent(m[3] * h)];
30692
+ const box = ellipseBeziersBox({ ax: -hx[0] - hy[0], ay: -hx[1] - hy[1], exx: 2 * hx[0], exy: 2 * hx[1], eyx: 2 * hy[0], eyy: 2 * hy[1] });
30693
+ const f = flattenBezierPath(box.slice(0, 14));
30187
30694
  const half = [];
30188
30695
  for (let i = 0; i + 1 < f.length; i += 2) {
30189
30696
  half.push([f[i], f[i + 1]]);
@@ -30255,9 +30762,10 @@ function perpendicularVectors(width, dx0, dy0, height = width, matrixPen) {
30255
30762
  const den = 2 * (bh - hB + (bh - hS));
30256
30763
  const w = den === 0 ? 0 : (hB - hS) / den;
30257
30764
  const x = D[0] + (B[0] - D[0]) * w, y = D[1] + (B[1] - D[1]) * w;
30258
- const signs = [dx === 0 ? 0 : Math.sign(dy), Math.sign(dx)];
30259
- const firstEdge = best === 0 && hP >= hN;
30260
30765
  const num = hB - hS;
30766
+ const sign = (c) => Math.sign(den === 0 ? D[c] : D[c] * den + (B[c] - D[c]) * num);
30767
+ const signs = matrixPen ? [sign(0) !== 0 ? -sign(0) : dx === 0 ? 0 : Math.sign(dy), sign(1) !== 0 ? sign(1) : Math.sign(dx)] : [dx === 0 ? 0 : Math.sign(dy), Math.sign(dx)];
30768
+ const firstEdge = matrixPen ? best < n / 2 : best === 0 && hP >= hN;
30261
30769
  const rounded = [0, 1].map((c) => {
30262
30770
  const bias2 = signs[c] + 2 * oddEdgeAdjustment(Math.abs(B[c] - D[c]) % 2 === 1, firstEdge);
30263
30771
  if (den === 0) {
@@ -30284,7 +30792,8 @@ function squareExtension(width, dx, dy, scale = 1, height = width, matrix, whole
30284
30792
  if (l === 0) return [0, 0];
30285
30793
  }
30286
30794
  const q = width / 2 * scale / l;
30287
- return [Math.floor((matrix[0] * lx + matrix[2] * ly) * q + 0.5), Math.floor((matrix[1] * lx + matrix[3] * ly) * q + 0.5)];
30795
+ const round2 = symmetric ? (v) => Math.sign(v) * Math.floor(Math.abs(v) + 0.5) : (v) => Math.floor(v + 0.5);
30796
+ return [round2((matrix[0] * lx + matrix[2] * ly) * q), round2((matrix[1] * lx + matrix[3] * ly) * q)];
30288
30797
  }
30289
30798
  const [ax, ay] = typeof logicalScale === "number" ? [logicalScale, logicalScale] : logicalScale;
30290
30799
  const r = width / 2 * scale;
@@ -30338,7 +30847,8 @@ var Outliner = class {
30338
30847
  const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height, nibMatrix);
30339
30848
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
30340
30849
  const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height, nibMatrix ? this.pen : void 0);
30341
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.capWidth ?? this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height ?? this.opts.capWidth, nibMatrix, !!(this.opts.wholePixelDashVectors || this.opts.cutToLogicalUnits), void 0, this.opts.logicalScale), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, role: drawDir?.[2] ?? 3, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
30850
+ const reversed = !!drawDir && dx * drawDir[0] + dy * drawDir[1] < 0;
30851
+ return { dx, dy, tx: reversed ? drawDir[0] : dx, ty: reversed ? drawDir[1] : dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.capWidth ?? this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height ?? this.opts.capWidth, nibMatrix, !!(this.opts.wholePixelDashVectors || this.opts.cutToLogicalUnits), void 0, this.opts.logicalScale), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, role: drawDir?.[2] ?? 3, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
30342
30852
  }
30343
30853
  push(p, v) {
30344
30854
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -30451,7 +30961,7 @@ var Outliner = class {
30451
30961
  const sv = this.capSide(s, from);
30452
30962
  const ev = this.capSide(s, to);
30453
30963
  if (cap === "square") {
30454
- const e0 = scale === 1 || s.curveEnd ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0, false, !!this.opts.wholePixelDashVectors);
30964
+ const e0 = scale === 1 || s.curveEnd ? s.e : this.scaledExtension(s, scale);
30455
30965
  const e = start ? [-e0[0], -e0[1]] : e0;
30456
30966
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
30457
30967
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
@@ -30460,6 +30970,23 @@ var Outliner = class {
30460
30970
  this.push(p, ev);
30461
30971
  }
30462
30972
  }
30973
+ /**
30974
+ * The square-cap extension of a dash end that GDI scales by its real over whole-pixel length. At one logical unit per device pixel the
30975
+ * extension is the vector component times (half the width over the whole-pixel length), a float32 product of a float32 ratio, rounded
30976
+ * half away from zero; ties of the exact product (110.5, 3.5, 57.5, -62.5) fall where that single-precision value puts them.
30977
+ */
30978
+ scaledExtension(s, scale) {
30979
+ const o = this.opts;
30980
+ if (o.wholePixelDashVectors && !o.matrix && !o.dashMetric && (o.height === void 0 || o.height === o.width)) {
30981
+ const length = norm(Math.floor(s.pe[0] / 16), Math.floor(s.pe[1] / 16)) * 16;
30982
+ if (length > 0) {
30983
+ const ratio = Math.fround(o.width / 2 / length);
30984
+ const component = (v) => Math.sign(v) * Math.floor(Math.fround(Math.abs(v) * ratio) + 0.5);
30985
+ return [component(s.pe[0]), component(s.pe[1])];
30986
+ }
30987
+ }
30988
+ return squareExtension(o.width, s.pe[0], s.pe[1], scale, o.height, o.deviceNib ? o.matrix : void 0, false, !!o.wholePixelDashVectors);
30989
+ }
30463
30990
  /**
30464
30991
  * The join at `p` on `side`, coming along `a` and leaving along `b` in
30465
30992
  * outline order (for the left side, walked backwards, `a` is the later
@@ -30503,7 +31030,7 @@ var Outliner = class {
30503
31030
  }
30504
31031
  }
30505
31032
  } else if (join === "miter") {
30506
- const m = miterPoint(sa, [a.dx, a.dy], sb, [b.dx, b.dy], width, miterLimit, side, this.opts.height);
31033
+ const m = miterPoint(sa, [a.dx, a.dy], sb, [b.dx, b.dy], width, miterLimit, side, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0);
30507
31034
  if (m) {
30508
31035
  this.push(p, m);
30509
31036
  }
@@ -30577,7 +31104,7 @@ var Outliner = class {
30577
31104
  for (let i = 0; i + 1 < segs2.length; i++) {
30578
31105
  const s = segs2[i];
30579
31106
  const t = segs2[i + 1];
30580
- const tr = turnSign(s.dx, s.dy, t.dx, t.dy);
31107
+ const tr = turnSign(s.tx, s.ty, t.tx, t.ty);
30581
31108
  if (tr === 0) {
30582
31109
  this.push(P[i + 1], this.joinSide(s, "R"));
30583
31110
  } else {
@@ -30588,7 +31115,7 @@ var Outliner = class {
30588
31115
  for (let i = segs2.length - 1; i > 0; i--) {
30589
31116
  const s = segs2[i];
30590
31117
  const t = segs2[i - 1];
30591
- const tr = turnSign(t.dx, t.dy, s.dx, s.dy);
31118
+ const tr = turnSign(t.tx, t.ty, s.tx, s.ty);
30592
31119
  if (tr === 0) {
30593
31120
  this.push(P[i], this.joinSide(s, "L"));
30594
31121
  } else {
@@ -30608,7 +31135,7 @@ var Outliner = class {
30608
31135
  const i = j % m;
30609
31136
  const s = segs2[(i + m - 1) % m];
30610
31137
  const t = segs2[i];
30611
- const tr = turnSign(s.dx, s.dy, t.dx, t.dy);
31138
+ const tr = turnSign(s.tx, s.ty, t.tx, t.ty);
30612
31139
  if (tr === 0) {
30613
31140
  this.push(P[i], this.joinSide(s, "R"));
30614
31141
  } else {
@@ -30620,7 +31147,7 @@ var Outliner = class {
30620
31147
  const i = (m - j) % m;
30621
31148
  const s = segs2[i];
30622
31149
  const t = segs2[(i + m - 1) % m];
30623
- const tr = turnSign(t.dx, t.dy, s.dx, s.dy);
31150
+ const tr = turnSign(t.tx, t.ty, s.tx, s.ty);
30624
31151
  if (tr === 0) {
30625
31152
  this.push(P[i], this.joinSide(s, "L"));
30626
31153
  } else {
@@ -30640,6 +31167,14 @@ var Outliner = class {
30640
31167
  this.flush();
30641
31168
  }
30642
31169
  };
31170
+ function nearestUnit(v) {
31171
+ return Math.sign(v) * Math.floor((Math.abs(v) + 8) / 16) * 16;
31172
+ }
31173
+ function cutCoordinate(x0, d, t, len) {
31174
+ const offset = Math.abs(d) * (t / len);
31175
+ const v = Math.fround(x0 + (d < 0 ? -offset : offset));
31176
+ return d < 0 ? Math.ceil(v - 0.5) : Math.floor(v + 0.5);
31177
+ }
30643
31178
  function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric, matrix) {
30644
31179
  const out = [];
30645
31180
  const dashes = [];
@@ -30662,7 +31197,7 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
30662
31197
  const dir = [x1 - x0, y1 - y0];
30663
31198
  const det = matrix ? matrix[0] * matrix[3] - matrix[1] * matrix[2] : 1;
30664
31199
  const real = matrix ? Math.hypot((matrix[3] * dir[0] - matrix[2] * dir[1]) / det, (-matrix[1] * dir[0] + matrix[0] * dir[1]) / det) : metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : norm(dir[0], dir[1]);
30665
- const len = metric || matrix ? real : wholePixelVectors ? norm(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : norm(dir[0], dir[1]);
31200
+ const len = metric ? norm(nearestUnit(dir[0] / metric[0]), nearestUnit(dir[1] / metric[1])) : matrix ? norm(nearestUnit((matrix[3] * dir[0] - matrix[2] * dir[1]) / det), nearestUnit((-matrix[1] * dir[0] + matrix[0] * dir[1]) / det)) : wholePixelVectors ? norm(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : norm(dir[0], dir[1]);
30666
31201
  if (len === 0) {
30667
31202
  if (on && cur) {
30668
31203
  cur.pts.push(P[i + 1]);
@@ -30675,7 +31210,7 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
30675
31210
  let t = 0;
30676
31211
  while (len - t > left || left === 0 && on) {
30677
31212
  t += left;
30678
- const q = [Math.floor(x0 + dir[0] * t / len + 0.5), Math.floor(y0 + dir[1] * t / len + 0.5)];
31213
+ const q = [cutCoordinate(x0, dir[0], t, len), cutCoordinate(y0, dir[1], t, len)];
30679
31214
  if (on && cur) {
30680
31215
  cur.pts.push(q);
30681
31216
  cur.dirs.push(dir);
@@ -30732,7 +31267,7 @@ function widenInLogicalSpace(path, opts, m) {
30732
31267
  });
30733
31268
  }
30734
31269
  function widenPath(path, opts) {
30735
- if (opts.matrix && !(opts.deviceNib && opts.join === "round")) {
31270
+ if (opts.matrix && !opts.deviceNib) {
30736
31271
  return widenInLogicalSpace(path, opts, opts.matrix);
30737
31272
  }
30738
31273
  const out = [];
@@ -30786,7 +31321,7 @@ function widenPath(path, opts) {
30786
31321
  }
30787
31322
  return out;
30788
31323
  }
30789
- function miterPoint(sa, da, sb, db, width, limit, side, height = width) {
31324
+ function miterPoint(sa, da, sb, db, width, limit, side, height = width, matrix) {
30790
31325
  const den = da[0] * db[1] - da[1] * db[0];
30791
31326
  if (den === 0) {
30792
31327
  return null;
@@ -30799,6 +31334,12 @@ function miterPoint(sa, da, sb, db, width, limit, side, height = width) {
30799
31334
  const x = Math.sign(mx) * Math.floor(Math.abs(mx) + 0.5);
30800
31335
  const y = Math.sign(my) * Math.floor(Math.abs(my) + 0.5);
30801
31336
  const pixel = side === "L" ? Math.ceil : Math.floor;
31337
+ if (matrix) {
31338
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
31339
+ const lx = (matrix[3] * x - matrix[2] * y) / det;
31340
+ const ly = (-matrix[1] * x + matrix[0] * y) / det;
31341
+ return Math.hypot(Math.round(lx / 16), Math.round(ly / 16)) > limit * width / 32 ? null : [x, y];
31342
+ }
30802
31343
  const yDistance = height === width ? pixel(y / 16) : pixel(y / 16) * width / height;
30803
31344
  if (Math.hypot(pixel(x / 16), yDistance) > limit * width / 32) {
30804
31345
  return null;
@@ -30882,9 +31423,12 @@ function boxFrame(box) {
30882
31423
  const h = Math.round(Math.hypot(box.eyx, box.eyy));
30883
31424
  return { l: 0, t: 0, r: w, b: h };
30884
31425
  }
30885
- function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = false) {
31426
+ function roundRectDeviceBeziers(box, cw, ch, recordedClockwise = false, compatible = false) {
30886
31427
  const f = boxFrame(box);
30887
- const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible, clockwise);
31428
+ const mirrorX = isAxisBox(box) && box.exx < 0;
31429
+ const mirrorY = isAxisBox(box) && box.eyy < 0;
31430
+ const clockwise = recordedClockwise !== mirrorY;
31431
+ const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible, clockwise, mirrorX);
30888
31432
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
30889
31433
  const pts = [];
30890
31434
  for (let i = 0; i < q.length; i += 2) {
@@ -30936,6 +31480,11 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = fal
30936
31480
  set(15, null, f.b - hy);
30937
31481
  }
30938
31482
  }
31483
+ if (mirrorX) {
31484
+ for (let i = 0; i < pts.length; i += 2) {
31485
+ pts[i] = f.l + f.r - pts[i];
31486
+ }
31487
+ }
30939
31488
  return pts;
30940
31489
  }
30941
31490
  function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
@@ -30949,7 +31498,7 @@ function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false,
30949
31498
  path.closeFigure();
30950
31499
  return path;
30951
31500
  }
30952
- function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPath()) {
31501
+ function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPath(), mirror2) {
30953
31502
  const f = boxFrame(box);
30954
31503
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
30955
31504
  let sx = s[0];
@@ -30971,12 +31520,19 @@ function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPat
30971
31520
  if (det < 0) {
30972
31521
  cw = !cw;
30973
31522
  }
31523
+ } else if (mirror2) {
31524
+ cw = clockwise !== mirror2.y;
31525
+ if (mirror2.x) {
31526
+ sx = f.l + f.r - sx;
31527
+ ex = f.l + f.r - ex;
31528
+ }
30974
31529
  } else {
30975
31530
  if (box.exx < 0 !== box.eyy < 0) {
30976
31531
  cw = !cw;
30977
31532
  }
30978
31533
  }
30979
- const bz = arcBeziers(f.l, f.t, f.r, f.b, sx, sy, ex, ey, cw, !!box.halfX, !!box.framed);
31534
+ const mirrorX = !!mirror2?.x && isAxisBox(box);
31535
+ const bz = arcBeziers(f.l, f.t, f.r, f.b, sx, sy, ex, ey, cw, !!box.halfX, !!box.framed, mirrorX);
30980
31536
  const pts = [];
30981
31537
  for (let i = 0; i < bz.length; i += 2) {
30982
31538
  pts.push(...map(bz[i], bz[i + 1]));
@@ -30990,7 +31546,7 @@ function arcRasterPath(box, s, e, clockwise, kind, from, path = new GdiRasterPat
30990
31546
  if (kind === "pie") {
30991
31547
  const w = f.r - f.l;
30992
31548
  const h = f.b - f.t;
30993
- const [cx, cy] = map(f.l + Math.ceil(w / 2) + (box.halfX ? 1 : 0), f.t + Math.ceil(h / 2));
31549
+ const [cx, cy] = map(f.l + Math.ceil(w / 2) + (box.halfX && !mirrorX ? 1 : 0), f.t + Math.ceil(h / 2));
30994
31550
  path.lineTo(cx, cy);
30995
31551
  }
30996
31552
  if (kind === "pie" || kind === "chord") {
@@ -31031,8 +31587,10 @@ function penWidenOptions(rCtx, opts = {}) {
31031
31587
  const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
31032
31588
  const quarterTurn = Math.abs(matrix[0]) < 1e-9 && Math.abs(matrix[3]) < 1e-9;
31033
31589
  const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !quarterTurn && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
31034
- const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
31035
- const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
31590
+ const unrotated = Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6;
31591
+ const scaled2 = !rCtx.wholeDevicePixels && unrotated && (Math.abs(Math.abs(matrix[0]) - 1) > 1e-6 || Math.abs(Math.abs(matrix[3]) - 1) > 1e-6);
31592
+ const dashes = state.penExtended ? ellipse || general || scaled2 ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
31593
+ const dashMetric = (ellipse || scaled2) && !general && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
31036
31594
  if (general) {
31037
31595
  return {
31038
31596
  width: Math.round(state.penWidth * 16),
@@ -31047,8 +31605,6 @@ function penWidenOptions(rCtx, opts = {}) {
31047
31605
  cutToLogicalUnits: !dashes
31048
31606
  };
31049
31607
  }
31050
- const unrotated = Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6;
31051
- const scaled2 = !rCtx.wholeDevicePixels && unrotated && (Math.abs(Math.abs(matrix[0]) - 1) > 1e-6 || Math.abs(Math.abs(matrix[3]) - 1) > 1e-6);
31052
31608
  const uniform = scaled2 && !ellipse && state.penExtended && (flags & 15) !== 6;
31053
31609
  return {
31054
31610
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
@@ -31062,7 +31618,7 @@ function penWidenOptions(rCtx, opts = {}) {
31062
31618
  // One logical unit per device pixel, unrotated: GDI measures dash
31063
31619
  // segments in whole pixels.
31064
31620
  wholePixelDashVectors: Math.abs(matrix[0] - 1) < 1e-6 && Math.abs(matrix[3] - 1) < 1e-6 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6,
31065
- ...scaled2 && !dashes ? {
31621
+ ...scaled2 ? {
31066
31622
  cutToLogicalUnits: true,
31067
31623
  logicalScale: ellipse ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : Math.abs(matrix[0]),
31068
31624
  // A square cap extends by half the unrounded width in FIX.
@@ -31495,6 +32051,406 @@ function withoutOutline(spans, path) {
31495
32051
  return out;
31496
32052
  }
31497
32053
 
32054
+ // src/emf-plus-path-gradient-copies.ts
32055
+ var fix = (v) => Math.floor(v * 16 + 0.5) / 16;
32056
+ var TIE = 1e-6;
32057
+ var STRIP_TIE = 5e-3;
32058
+ var CONTAINMENT_TIE = 5e-4;
32059
+ var SLANTED_NEAR = 5e-6;
32060
+ var CEIL_EPSILON = 1e-9;
32061
+ function prepareCopies(shape, full, steps) {
32062
+ const n = shape.boundary.length;
32063
+ if (n < 3 || steps <= 0) return null;
32064
+ const isotropic = !shape.focus || Math.abs(shape.focus.x - shape.focus.y) <= 1e-9;
32065
+ const focus = shape.focus && isotropic ? Math.min(1, Math.max(0, shape.focus.x)) : 0;
32066
+ const vx = new Float64Array(n);
32067
+ const vy = new Float64Array(n);
32068
+ for (let i = 0; i < n; i++) {
32069
+ const p = shape.boundary[i];
32070
+ vx[i] = fix(full[0] * p.x + full[2] * p.y + full[4]);
32071
+ vy[i] = fix(full[1] * p.x + full[3] * p.y + full[5]);
32072
+ }
32073
+ const c = shape.center;
32074
+ const cx = fix(full[0] * c.x + full[2] * c.y + full[4]);
32075
+ const cy = fix(full[1] * c.x + full[3] * c.y + full[5]);
32076
+ const anisotropic = isotropic ? null : {
32077
+ ...shape,
32078
+ boundary: Array.from(vx, (x, i) => ({ x, y: vy[i] })),
32079
+ center: { x: cx, y: cy },
32080
+ boundaryArgb: shape.boundaryArgb,
32081
+ blend: null,
32082
+ preset: null,
32083
+ transform: null
32084
+ };
32085
+ let degenerate = false;
32086
+ for (let i = 0; i < n; i++) {
32087
+ const j = (i + 1) % n;
32088
+ if ((vx[i] - cx) * (vy[j] - cy) - (vy[i] - cy) * (vx[j] - cx) === 0) degenerate = true;
32089
+ }
32090
+ return { cx, cy, vx, vy, steps, focus, anisotropic, degenerate };
32091
+ }
32092
+ function floatCopyIndex(g, edge, dx, dy) {
32093
+ const n = g.vx.length;
32094
+ const ax = g.vx[edge] - g.cx;
32095
+ const ay = g.vy[edge] - g.cy;
32096
+ const ex = g.vx[(edge + 1) % n] - g.vx[edge];
32097
+ const ey = g.vy[(edge + 1) % n] - g.vy[edge];
32098
+ const denominator = down32(down32(ex * dy) - down32(ey * dx));
32099
+ if (denominator === 0) return null;
32100
+ const u = down32(down32(down32(ay * dx) - down32(ax * dy)) / denominator);
32101
+ const bx = down32(ax + down32(u * ex));
32102
+ const by = down32(ay + down32(u * ey));
32103
+ const useX = Math.abs(bx) >= Math.abs(by);
32104
+ const boundary = useX ? bx : by;
32105
+ if (boundary === 0) return null;
32106
+ const r = Math.abs(down32((useX ? dx : dy) / boundary));
32107
+ return Math.max(0, Math.floor(down32(down32(g.steps * r) + 0.5)));
32108
+ }
32109
+ function focusCopyIndex(g, edge, px, py) {
32110
+ const n = g.vx.length;
32111
+ const dx = px - g.cx;
32112
+ const dy = py - g.cy;
32113
+ const f = Math.fround(g.focus);
32114
+ const j = (edge + 1) % n;
32115
+ const ax = g.vx[edge] - g.cx;
32116
+ const ay = g.vy[edge] - g.cy;
32117
+ const ex = g.vx[j] - g.vx[edge];
32118
+ const ey = g.vy[j] - g.vy[edge];
32119
+ const denominator = down32(down32(ex * dy) - down32(ey * dx));
32120
+ if (denominator === 0) return null;
32121
+ const u = down32(down32(down32(ay * dx) - down32(ax * dy)) / denominator);
32122
+ const bx = down32(ax + down32(u * ex));
32123
+ const by = down32(ay + down32(u * ey));
32124
+ const useX = Math.abs(bx) >= Math.abs(by);
32125
+ const b = useX ? bx : by;
32126
+ if (b === 0) return null;
32127
+ const c = useX ? g.cx : g.cy;
32128
+ const p = useX ? px : py;
32129
+ const outer = down32(c + b);
32130
+ const scaled2 = (c0, v) => down32(c0 + down32(f * (v - c0)));
32131
+ const f0x = scaled2(g.cx, g.vx[edge]);
32132
+ const f0y = scaled2(g.cy, g.vy[edge]);
32133
+ const f1x = scaled2(g.cx, g.vx[j]);
32134
+ const f1y = scaled2(g.cy, g.vy[j]);
32135
+ const fax = down32(f0x - g.cx);
32136
+ const fay = down32(f0y - g.cy);
32137
+ const fex = down32(f1x - f0x);
32138
+ const fey = down32(f1y - f0y);
32139
+ const focusDenominator = down32(down32(fex * dy) - down32(fey * dx));
32140
+ if (focusDenominator === 0) return null;
32141
+ const fu = down32(down32(down32(fay * dx) - down32(fax * dy)) / focusDenominator);
32142
+ const inner = down32((useX ? f0x : f0y) + down32(fu * (useX ? fex : fey)));
32143
+ const span = Math.fround(outer - inner);
32144
+ if (span === 0) return null;
32145
+ const t = down32(Math.fround(p - inner) / span);
32146
+ const position = Math.fround(down32(g.steps * t) + 0.5);
32147
+ if (ex !== 0 && ey !== 0) {
32148
+ const ulp = (v) => 2 ** (Math.floor(Math.log2(Math.abs(v) || 1)) - 23);
32149
+ const slack = g.steps * (ulp(inner) + ulp(outer)) / Math.abs(span);
32150
+ const short = Math.ceil(position) - position;
32151
+ if (short > 0 && short <= slack) return null;
32152
+ }
32153
+ return Math.max(0, Math.floor(position));
32154
+ }
32155
+ function tieSide(g, edge, dx, dy, q, focus = 0) {
32156
+ const n = g.vx.length;
32157
+ const ex = g.vx[(edge + 1) % n] - g.vx[edge];
32158
+ const ey = g.vy[(edge + 1) % n] - g.vy[edge];
32159
+ if (ex === 0 && ey === 0) return null;
32160
+ const adx = Math.abs(dx);
32161
+ const ady = Math.abs(dy);
32162
+ let odd = g.steps;
32163
+ while (odd % 2 === 0) odd /= 2;
32164
+ const fractional = (2 * q + 1) % odd !== 0;
32165
+ const axisAligned = ex === 0 || ey === 0;
32166
+ const alike = axisAligned ? ex === 0 ? adx <= ady : ady <= adx : Math.abs(ex) === Math.abs(ey) || Math.abs(ex) > Math.abs(ey) === adx > ady;
32167
+ if (!alike) return axisAligned ? fractional : null;
32168
+ const forward = ex > 0 || ex === 0 && ey > 0;
32169
+ if (!forward) return focus > 0 && !axisAligned ? null : fractional;
32170
+ if (dx * ex + dy * ey < 0) return fractional || !edgeParameterIsBinary(g, edge, dx, dy, q);
32171
+ return fractional && adx === ady;
32172
+ }
32173
+ function gcd(a, b) {
32174
+ while (b) [a, b] = [b, a % b];
32175
+ return a;
32176
+ }
32177
+ function edgeParameterIsBinary(g, edge, dx, dy, q) {
32178
+ const n = g.vx.length;
32179
+ const k = 16;
32180
+ const ex = Math.round((g.vx[(edge + 1) % n] - g.vx[edge]) * k);
32181
+ const ey = Math.round((g.vy[(edge + 1) % n] - g.vy[edge]) * k);
32182
+ const ax = Math.round((g.vx[edge] - g.cx) * k);
32183
+ const ay = Math.round((g.vy[edge] - g.cy) * k);
32184
+ const S = 2 * q + 1;
32185
+ const D = 2 * g.steps;
32186
+ const P = Math.round(dx * k) * ex + Math.round(dy * k) * ey;
32187
+ const A = ax * ex + ay * ey;
32188
+ const numerator = P * D - A * S;
32189
+ const denominator = (ex * ex + ey * ey) * S;
32190
+ if (!Number.isSafeInteger(numerator) || !Number.isSafeInteger(denominator)) return false;
32191
+ if (numerator === 0) return true;
32192
+ let d = Math.abs(denominator / gcd(Math.abs(numerator), Math.abs(denominator)));
32193
+ while (d % 2 === 0) d /= 2;
32194
+ return d === 1;
32195
+ }
32196
+ function insideCopy(g, scale, px, py, scaleY = scale) {
32197
+ const n = g.vx.length;
32198
+ let xl = Infinity;
32199
+ let xr = -Infinity;
32200
+ let ax = g.cx + (g.vx[n - 1] - g.cx) * scale;
32201
+ let ay = g.cy + (g.vy[n - 1] - g.cy) * scaleY;
32202
+ for (let i = 0; i < n; i++) {
32203
+ const bx = g.cx + (g.vx[i] - g.cx) * scale;
32204
+ const by = g.cy + (g.vy[i] - g.cy) * scaleY;
32205
+ if (ay <= py && by > py || by <= py && ay > py) {
32206
+ const x = ax + (py - ay) / (by - ay) * (bx - ax);
32207
+ if (x < xl) xl = x;
32208
+ if (x > xr) xr = x;
32209
+ }
32210
+ ax = bx;
32211
+ ay = by;
32212
+ }
32213
+ return xl !== Infinity && px >= Math.ceil(xl - CEIL_EPSILON) && px < Math.ceil(xr - CEIL_EPSILON);
32214
+ }
32215
+ function edgeAt(g, scaleX, scaleY, px, py) {
32216
+ const n = g.vx.length;
32217
+ const near = 1e-6;
32218
+ let hit = null;
32219
+ let vertexRow = false;
32220
+ for (let i = 0; i < n; i++) {
32221
+ const j = (i + 1) % n;
32222
+ const ax = g.cx + (g.vx[i] - g.cx) * scaleX;
32223
+ const ay = g.cy + (g.vy[i] - g.cy) * scaleY;
32224
+ const bx = g.cx + (g.vx[j] - g.cx) * scaleX;
32225
+ const by = g.cy + (g.vy[j] - g.cy) * scaleY;
32226
+ if (Math.abs(ax - bx) < near && Math.abs(px - ax) < near && py >= Math.min(ay, by) - near && py <= Math.max(ay, by) + near) return { kind: "vertical", edge: i };
32227
+ if (Math.abs(ay - by) < near && Math.abs(py - ay) < near && px >= Math.min(ax, bx) - near && px <= Math.max(ax, bx) + near) return { kind: "horizontal", edge: i };
32228
+ if (Math.abs(ay - py) < near) vertexRow = true;
32229
+ const length = Math.hypot(bx - ax, by - ay);
32230
+ if (length < near) continue;
32231
+ const across = ((px - ax) * (by - ay) - (py - ay) * (bx - ax)) / length;
32232
+ const along = ((px - ax) * (bx - ax) + (py - ay) * (by - ay)) / (length * length);
32233
+ if (Math.abs(across) < SLANTED_NEAR && along >= -near && along <= 1 + near) hit = { kind: "slanted", edge: i };
32234
+ }
32235
+ return hit ?? (vertexRow ? { kind: "slanted", edge: -1 } : null);
32236
+ }
32237
+ function focusedEdgeStep(g, px, py) {
32238
+ const focus = g.anisotropic.focus;
32239
+ const full = 1 - 1e-9;
32240
+ if (focus.x < full && focus.y < full) return void 0;
32241
+ const n = g.vx.length;
32242
+ let onEdge = false;
32243
+ for (let i = 0; i < n && !onEdge; i++) {
32244
+ const j = (i + 1) % n;
32245
+ const near = 1e-6;
32246
+ if (focus.x >= full && Math.abs(g.vx[i] - g.vx[j]) < near && Math.abs(px - g.vx[i]) < near && py >= Math.min(g.vy[i], g.vy[j]) - near && py <= Math.max(g.vy[i], g.vy[j]) + near) onEdge = true;
32247
+ if (focus.y >= full && Math.abs(g.vy[i] - g.vy[j]) < near && Math.abs(py - g.vy[i]) < near && px >= Math.min(g.vx[i], g.vx[j]) - near && px <= Math.max(g.vx[i], g.vx[j]) + near) onEdge = true;
32248
+ }
32249
+ if (!onEdge) return void 0;
32250
+ const fx = Math.min(1, Math.max(0, focus.x));
32251
+ const fy = Math.min(1, Math.max(0, focus.y));
32252
+ for (let m = 0; m <= g.steps; m++) {
32253
+ const along = m === g.steps ? 1 : (m + 0.5) / g.steps;
32254
+ if (insideCopy(g, fx + (1 - fx) * along, px, py, fy + (1 - fy) * along)) return g.steps - m;
32255
+ }
32256
+ return null;
32257
+ }
32258
+ function anisotropicTieStep(g, q, tie, dx, dy, px, py) {
32259
+ const focus = g.anisotropic.focus;
32260
+ const along = (tie + 0.5) / g.steps;
32261
+ const fx = Math.min(1, Math.max(0, focus.x));
32262
+ const fy = Math.min(1, Math.max(0, focus.y));
32263
+ const scaleX = fx + (1 - fx) * along;
32264
+ const scaleY = fy + (1 - fy) * along;
32265
+ const hit = edgeAt(g, scaleX, scaleY, px, py);
32266
+ const half = g.steps - tie - 0.5;
32267
+ if (hit?.kind === "slanted") return half;
32268
+ if (hit === null && Math.abs(q - tie) >= CONTAINMENT_TIE) return half;
32269
+ if (hit === null) return g.steps - tie - (insideCopy(g, scaleX, px, py, scaleY) ? 0 : 1);
32270
+ let odd = g.steps;
32271
+ while (odd % 2 === 0) odd /= 2;
32272
+ const fractional = (2 * tie + 1) % odd !== 0;
32273
+ const vertical = hit.kind === "vertical";
32274
+ if (vertical ? Math.abs(dx) > Math.abs(dy) : Math.abs(dy) > Math.abs(dx)) return g.steps - tie - (fractional ? 0 : 1);
32275
+ const n = g.vx.length;
32276
+ const ex = g.vx[(hit.edge + 1) % n] - g.vx[hit.edge];
32277
+ const ey = g.vy[(hit.edge + 1) % n] - g.vy[hit.edge];
32278
+ if (!(ex > 0 || ex === 0 && ey > 0)) return g.steps - tie - (fractional ? 0 : 1);
32279
+ if (dx * ex + dy * ey >= 0) return g.steps - tie - (fractional && Math.abs(dx) === Math.abs(dy) ? 0 : 1);
32280
+ const ax = g.cx + (g.vx[hit.edge] - g.cx) * scaleX;
32281
+ const ay = g.cy + (g.vy[hit.edge] - g.cy) * scaleY;
32282
+ const u = vertical ? (py - ay) / (ey * scaleY) : (px - ax) / (ex * scaleX);
32283
+ const scaled2 = u * 2 ** 24;
32284
+ const binary = Math.abs(scaled2 - Math.round(scaled2)) < 1e-4;
32285
+ return g.steps - tie - (fractional || !binary ? 0 : 1);
32286
+ }
32287
+ function copiesStepAt(g, px, py, nudge = 0) {
32288
+ const n = g.vx.length;
32289
+ let s = -1;
32290
+ let edge = -1;
32291
+ const dx = px - g.cx;
32292
+ const dy = py - g.cy;
32293
+ for (let i = 0; i < n; i++) {
32294
+ const ax = g.vx[i] - g.cx;
32295
+ const ay = g.vy[i] - g.cy;
32296
+ const ex = g.vx[(i + 1) % n] - g.vx[i];
32297
+ const ey = g.vy[(i + 1) % n] - g.vy[i];
32298
+ const det = ax * ey - ay * ex;
32299
+ if (Math.abs(det) < 1e-12) continue;
32300
+ const alpha = (dx * ey - dy * ex) / det;
32301
+ const beta = (ax * dy - ay * dx) / det;
32302
+ if (alpha < -1e-9 || beta < -1e-9 || beta > alpha + 1e-9 || alpha > 1 + 1e-9) continue;
32303
+ s = alpha;
32304
+ edge = i;
32305
+ }
32306
+ if (g.anisotropic) {
32307
+ const edge2 = s > 1 - 1e-9;
32308
+ const column2 = focusedEdgeStep(g, px, py);
32309
+ if (column2 !== void 0) return column2;
32310
+ const ratio = pathGradientRatio(g.anisotropic, px + nudge, py, { x: px, y: py });
32311
+ if (ratio === null) return null;
32312
+ if (edge2) return Math.max(0, g.steps * (1 - ratio));
32313
+ s = ratio;
32314
+ }
32315
+ if (s < 0) return null;
32316
+ if (g.degenerate && !insideCopy(g, 1, px, py)) return null;
32317
+ if (!g.anisotropic && g.focus === 0 && edge >= 0) {
32318
+ const m2 = floatCopyIndex(g, edge, dx, dy);
32319
+ if (m2 !== null) {
32320
+ if (m2 >= g.steps && !insideCopy(g, 1, px, py)) return null;
32321
+ return g.steps - Math.min(m2, g.steps);
32322
+ }
32323
+ }
32324
+ if (!g.anisotropic && g.focus > 0 && g.focus < 1 && edge >= 0 && !(px === g.cx && py === g.cy)) {
32325
+ const m2 = focusCopyIndex(g, edge, px, py);
32326
+ if (m2 !== null) {
32327
+ if (m2 >= g.steps && !insideCopy(g, 1, px, py)) return null;
32328
+ return g.steps - Math.min(m2, g.steps);
32329
+ }
32330
+ }
32331
+ const f = g.focus;
32332
+ const q = s <= f ? 0 : (s - f) / (1 - f) * g.steps - 0.5;
32333
+ if (q > 0 && Math.abs(q - Math.round(q)) < (g.anisotropic ? STRIP_TIE : TIE)) {
32334
+ const tie = Math.round(q);
32335
+ if (g.anisotropic) return anisotropicTieStep(g, q, tie, dx, dy, px, py);
32336
+ const decided = edge >= 0 ? tieSide(g, edge, dx, dy, tie, f) : null;
32337
+ if (decided !== null) return g.steps - tie - (decided ? 0 : 1);
32338
+ return g.steps - tie - 0.5;
32339
+ }
32340
+ const m = Math.max(0, Math.ceil(q));
32341
+ if (m >= g.steps && !insideCopy(g, 1, px, py)) return null;
32342
+ return g.steps - Math.min(m, g.steps);
32343
+ }
32344
+
32345
+ // src/emf-plus-path-gradient-vertices.ts
32346
+ var FRACTION_BITS = 16;
32347
+ var ONE = 2 ** FRACTION_BITS;
32348
+ var CEIL_EPSILON2 = 1e-9;
32349
+ var snap = (v) => Math.ceil(v * 16 - 1e-9) / 16;
32350
+ function premultiplied2(argb) {
32351
+ const a = argb >>> 24;
32352
+ return [a, (argb >>> 16 & 255) * a / 255, (argb >>> 8 & 255) * a / 255, (argb & 255) * a / 255];
32353
+ }
32354
+ function prepareVertexGradient(shape, full) {
32355
+ const n = shape.boundary.length;
32356
+ if (n < 3 || shape.preset || shape.blend || shape.boundaryArgb.length < n) {
32357
+ return null;
32358
+ }
32359
+ if (shape.boundaryArgb.every((color) => color === shape.boundaryArgb[0])) {
32360
+ return null;
32361
+ }
32362
+ const vx = new Float64Array(n);
32363
+ const vy = new Float64Array(n);
32364
+ const vc = new Float64Array(n * 4);
32365
+ for (let i = 0; i < n; i++) {
32366
+ const p = shape.boundary[i];
32367
+ vx[i] = snap(full[0] * p.x + full[2] * p.y + full[4]);
32368
+ vy[i] = snap(full[1] * p.x + full[3] * p.y + full[5]);
32369
+ vc.set(premultiplied2(shape.boundaryArgb[i]), i * 4);
32370
+ }
32371
+ const c = shape.center;
32372
+ return {
32373
+ cx: snap(full[0] * c.x + full[2] * c.y + full[4]),
32374
+ cy: snap(full[1] * c.x + full[3] * c.y + full[5]),
32375
+ vx,
32376
+ vy,
32377
+ vc,
32378
+ cc: premultiplied2(shape.centerArgb)
32379
+ };
32380
+ }
32381
+ function edgeChannel(ax, ay, bx, by, ca, cb, x, y) {
32382
+ const dx = bx - ax;
32383
+ const dy = by - ay;
32384
+ let t = 0;
32385
+ if (Math.abs(dx) > Math.abs(dy)) {
32386
+ const steps = Math.trunc(Math.abs(dx));
32387
+ if (steps > 0) t = Math.abs(x - Math.floor(ax)) / steps;
32388
+ } else {
32389
+ const steps = Math.trunc(Math.abs(dy));
32390
+ if (steps > 0) t = Math.abs(y - Math.floor(ay)) / steps;
32391
+ }
32392
+ return Math.trunc((ca + (cb - ca) * t) * ONE);
32393
+ }
32394
+ function vertexGradientColorAt(g, px, py) {
32395
+ const n = g.vx.length;
32396
+ let result = null;
32397
+ const tx = [0, 0, 0];
32398
+ const ty = [0, 0, 0];
32399
+ const out = [0, 0, 0, 0];
32400
+ for (let f = 0; f < n; f++) {
32401
+ const f1 = (f + 1) % n;
32402
+ tx[0] = g.cx;
32403
+ tx[1] = g.vx[f];
32404
+ tx[2] = g.vx[f1];
32405
+ ty[0] = g.cy;
32406
+ ty[1] = g.vy[f];
32407
+ ty[2] = g.vy[f1];
32408
+ let left = -1;
32409
+ let right = -1;
32410
+ let xl = Infinity;
32411
+ let xr = -Infinity;
32412
+ for (let i = 0; i < 3; i++) {
32413
+ const j = (i + 1) % 3;
32414
+ const ay = ty[i];
32415
+ const by = ty[j];
32416
+ if (!(ay <= py && by > py || by <= py && ay > py)) continue;
32417
+ const x = tx[i] + (py - ay) / (by - ay) * (tx[j] - tx[i]);
32418
+ if (x < xl) {
32419
+ xl = x;
32420
+ left = i;
32421
+ }
32422
+ if (x > xr) {
32423
+ xr = x;
32424
+ right = i;
32425
+ }
32426
+ }
32427
+ if (left < 0 || right < 0 || left === right) continue;
32428
+ const xs = Math.ceil(xl - CEIL_EPSILON2);
32429
+ const xe = Math.ceil(xr - CEIL_EPSILON2);
32430
+ if (px < xs || px >= xe) continue;
32431
+ const li = left;
32432
+ const lj = (left + 1) % 3;
32433
+ const ri = right;
32434
+ const rj = (right + 1) % 3;
32435
+ for (let q = 0; q < 4; q++) {
32436
+ const colors = [g.cc[q], g.vc[f * 4 + q], g.vc[f1 * 4 + q]];
32437
+ const cL = edgeChannel(tx[li], ty[li], tx[lj], ty[lj], colors[li], colors[lj], xs, py);
32438
+ const cR = edgeChannel(tx[ri], ty[ri], tx[rj], ty[rj], colors[ri], colors[rj], xe, py);
32439
+ const step = Math.floor((cR - cL) / (xe - xs));
32440
+ const v = cL + step * (px - xs);
32441
+ out[q] = Math.max(0, Math.min(255, Math.floor((v + ONE / 2) / ONE)));
32442
+ }
32443
+ const alpha = out[0];
32444
+ if (alpha === 0) {
32445
+ result = 0;
32446
+ continue;
32447
+ }
32448
+ const ch = (premult) => Math.min(255, Math.round(premult * 255 / alpha));
32449
+ result = (alpha << 24 | ch(out[1]) << 16 | ch(out[2]) << 8 | ch(out[3])) >>> 0;
32450
+ }
32451
+ return result;
32452
+ }
32453
+
31498
32454
  // src/emf-plus-exact-fill.ts
31499
32455
  var IDENTITY4 = [1, 0, 0, 1, 0, 0];
31500
32456
  var MAX_EXACT_PIXELS = 16 * 1024 * 1024;
@@ -31573,17 +32529,110 @@ function pixelAligned(boundary, m) {
31573
32529
  }
31574
32530
  return [x0, y0, x1, y1].every((v) => Math.abs(v - Math.round(v)) < 1e-6);
31575
32531
  }
31576
- function pathGradientSampler(shape, wrap, device) {
32532
+ var TILE_WEIGHT_STEPS = 2048;
32533
+ function tileIndex(i, n, mirror2) {
32534
+ if (!mirror2) {
32535
+ return (i % n + n) % n;
32536
+ }
32537
+ const m = (i % (2 * n) + 2 * n) % (2 * n);
32538
+ return m < n ? m : 2 * n - 1 - m;
32539
+ }
32540
+ function fractionalTileSampler(shape, wrap, full) {
32541
+ if (Math.abs(full[1]) > 1e-9 || Math.abs(full[2]) > 1e-9 || full[0] <= 0 || full[3] <= 0) return null;
32542
+ if (!shape.boundaryArgb.every((color) => color === shape.boundaryArgb[0])) return null;
32543
+ let x0 = Infinity;
32544
+ let y0 = Infinity;
32545
+ let x1 = -Infinity;
32546
+ let y1 = -Infinity;
32547
+ for (const point of shape.boundary) {
32548
+ const x = full[0] * point.x + full[4];
32549
+ const y = full[3] * point.y + full[5];
32550
+ x0 = Math.min(x0, x);
32551
+ y0 = Math.min(y0, y);
32552
+ x1 = Math.max(x1, x);
32553
+ y1 = Math.max(y1, y);
32554
+ }
32555
+ const round = (v) => Math.floor(v + 0.5);
32556
+ const width = round(x1) - round(x0);
32557
+ const height = round(y1) - round(y0);
32558
+ if (!(x1 > x0) || !(y1 > y0) || width < 1 || height < 1 || width * height > 4 * 1024 * 1024) return null;
32559
+ const kx = width / (x1 - x0);
32560
+ const ky = height / (y1 - y0);
32561
+ const toTile = (point) => ({
32562
+ x: (full[0] * point.x + full[4] - x0) * kx,
32563
+ y: (full[3] * point.y + full[5] - y0) * ky
32564
+ });
32565
+ const inner = pathGradientSampler({
32566
+ ...shape,
32567
+ boundary: shape.boundary.map(toTile),
32568
+ center: toTile(shape.center),
32569
+ transform: null
32570
+ }, "clamp", IDENTITY4, false);
32571
+ if (!inner) return null;
32572
+ const mirrorX = wrap === "tile-flip-x" || wrap === "tile-flip-xy";
32573
+ const mirrorY = wrap === "tile-flip-y" || wrap === "tile-flip-xy";
32574
+ let texels = null;
32575
+ const texel = () => {
32576
+ if (texels) return texels;
32577
+ const rgba = new Uint8ClampedArray(width * height * 4);
32578
+ inner(0, 0, width, height, rgba);
32579
+ texels = new Float64Array(width * height * 4);
32580
+ for (let i = 0; i < width * height; i++) {
32581
+ const a = rgba[i * 4 + 3];
32582
+ texels[i * 4] = rgba[i * 4] * a / 255;
32583
+ texels[i * 4 + 1] = rgba[i * 4 + 1] * a / 255;
32584
+ texels[i * 4 + 2] = rgba[i * 4 + 2] * a / 255;
32585
+ texels[i * 4 + 3] = a;
32586
+ }
32587
+ return texels;
32588
+ };
32589
+ return (px, py, w, h, out) => {
32590
+ const t = texel();
32591
+ for (let j = 0; j < h; j++) {
32592
+ const v = ky * (py + j - y0);
32593
+ const iv = Math.floor(v);
32594
+ const wy = Math.floor((v - iv) * TILE_WEIGHT_STEPS + 0.5) / TILE_WEIGHT_STEPS;
32595
+ const r0 = tileIndex(iv, height, mirrorY) * width;
32596
+ const r1 = tileIndex(iv + 1, height, mirrorY) * width;
32597
+ for (let i = 0; i < w; i++) {
32598
+ const u = kx * (px + i - x0);
32599
+ const iu = Math.floor(u);
32600
+ const wx = Math.floor((u - iu) * TILE_WEIGHT_STEPS + 0.5) / TILE_WEIGHT_STEPS;
32601
+ const c0 = tileIndex(iu, width, mirrorX);
32602
+ const c1 = tileIndex(iu + 1, width, mirrorX);
32603
+ const o = (j * w + i) * 4;
32604
+ const sample2 = (k) => (1 - wx) * (1 - wy) * t[(r0 + c0) * 4 + k] + wx * (1 - wy) * t[(r0 + c1) * 4 + k] + (1 - wx) * wy * t[(r1 + c0) * 4 + k] + wx * wy * t[(r1 + c1) * 4 + k];
32605
+ const coverage = sample2(3);
32606
+ const alpha = Math.floor(coverage + 0.5);
32607
+ if (alpha <= 0) {
32608
+ out[o] = out[o + 1] = out[o + 2] = out[o + 3] = 0;
32609
+ continue;
32610
+ }
32611
+ const scale = coverage >= 255 ? 1 : 255 / coverage;
32612
+ out[o] = Math.min(255, Math.floor(sample2(0) * scale + 0.5));
32613
+ out[o + 1] = Math.min(255, Math.floor(sample2(1) * scale + 0.5));
32614
+ out[o + 2] = Math.min(255, Math.floor(sample2(2) * scale + 0.5));
32615
+ out[o + 3] = alpha;
32616
+ }
32617
+ }
32618
+ };
32619
+ }
32620
+ function pathGradientSampler(shape, wrap, device, strictOutside = true) {
31577
32621
  const box = boundaryBox2(shape.boundary);
31578
32622
  const full = mulMatrix(device, shape.transform ?? IDENTITY4);
31579
32623
  const inv2 = invertAffine(full);
31580
32624
  if (!box || !inv2) {
31581
32625
  return null;
31582
32626
  }
31583
- const anisotropicFocus = !!shape.focus && Math.abs(shape.focus.x - shape.focus.y) > 1e-9;
32627
+ if (wrap !== "clamp" && !pixelAligned(shape.boundary, full)) {
32628
+ const tiled = fractionalTileSampler(shape, wrap, full);
32629
+ if (tiled) return tiled;
32630
+ }
31584
32631
  const uniformSurround = shape.boundaryArgb.every((color) => color === shape.boundaryArgb[0]);
31585
- const smooth = !uniformSurround && !shape.preset || anisotropicFocus || wrap !== "clamp" && !pixelAligned(shape.boundary, full);
32632
+ const smooth = !uniformSurround && !shape.preset || wrap !== "clamp" && !pixelAligned(shape.boundary, full);
31586
32633
  const quantum = smooth ? 0 : pathGradientQuantum(shape.boundary, full);
32634
+ const vertexGradient = wrap === "clamp" || pixelAligned(shape.boundary, full) ? prepareVertexGradient(shape, full) : null;
32635
+ const copies = quantum > 0 ? prepareCopies(shape, full, quantum) : null;
31587
32636
  const pxX = Math.hypot(full[0], full[1]);
31588
32637
  const pxY = Math.hypot(full[2], full[3]);
31589
32638
  const lagX = pxX > 0 ? 1 / pxX : 0;
@@ -31604,7 +32653,25 @@ function pathGradientSampler(shape, wrap, device) {
31604
32653
  }
31605
32654
  if (wrap === "clamp" && by >= box.y + box.h) continue;
31606
32655
  const focusPoint = bias ? { x: bx - inv2[0] * bias, y: by - inv2[1] * bias } : void 0;
31607
- const c = pathGradientColorAt(shape, bx, by, focusPoint, quantum);
32656
+ let c = null;
32657
+ let decided = false;
32658
+ if (vertexGradient || copies) {
32659
+ const fx = wrap === "clamp" ? x0 + i : full[0] * bx + full[2] * by + full[4];
32660
+ const fy = wrap === "clamp" ? dy : full[1] * bx + full[3] * by + full[5];
32661
+ const rx = Math.round(fx);
32662
+ const ry = Math.round(fy);
32663
+ if (Math.abs(fx - rx) < 1e-6 && Math.abs(fy - ry) < 1e-6) {
32664
+ if (vertexGradient) {
32665
+ c = vertexGradientColorAt(vertexGradient, rx, ry);
32666
+ if (c === null && strictOutside) decided = true;
32667
+ } else if (copies) {
32668
+ const step = copiesStepAt(copies, rx, ry, bias);
32669
+ if (step !== null) c = pathGradientStepColor(shape, step, quantum);
32670
+ else if (strictOutside && !copies.anisotropic) decided = true;
32671
+ }
32672
+ }
32673
+ }
32674
+ if (c === null && !decided) c = pathGradientColorAt(shape, bx, by, focusPoint, quantum);
31608
32675
  if (c === null) {
31609
32676
  continue;
31610
32677
  }
@@ -32205,6 +33272,23 @@ function handleLineTo(rCtx, dataOff, recSize) {
32205
33272
  }
32206
33273
  return true;
32207
33274
  }
33275
+ function cosmeticRectangleBox(rCtx, box) {
33276
+ const { state } = rCtx;
33277
+ if (rCtx.inPath || state.penStyle === 5 || state.penStyle === 6 || box.exy !== 0 || box.eyx !== 0 || box.exx === 0 || box.eyy === 0 || !penIsCosmetic(rCtx)) {
33278
+ return box;
33279
+ }
33280
+ const ax = Math.ceil(box.ax / 16) * 16;
33281
+ const ay = Math.ceil(box.ay / 16) * 16;
33282
+ return { ...box, ax, ay, exx: Math.ceil((box.ax + box.exx) / 16) * 16 - ax, eyy: Math.ceil((box.ay + box.eyy) / 16) * 16 - ay };
33283
+ }
33284
+ function devicePositiveBox(box) {
33285
+ if (!isAxisBox(box) || box.exx >= 0 && box.eyy >= 0) {
33286
+ return box;
33287
+ }
33288
+ const ax = box.exx < 0 ? box.ax + box.exx : box.ax;
33289
+ const ay = box.eyy < 0 ? box.ay + box.eyy : box.ay;
33290
+ return { ...box, ax, ay, exx: Math.abs(box.exx), eyy: Math.abs(box.eyy) };
33291
+ }
32208
33292
  function handleRectangle(rCtx, dataOff, recSize) {
32209
33293
  const { ctx, view, state, inPath } = rCtx;
32210
33294
  if (recSize >= 24) {
@@ -32212,7 +33296,7 @@ function handleRectangle(rCtx, dataOff, recSize) {
32212
33296
  const t = view.getInt32(dataOff + 4, true);
32213
33297
  const r = view.getInt32(dataOff + 8, true);
32214
33298
  const b = view.getInt32(dataOff + 12, true);
32215
- const unframed = uprightFixBox(rCtx, l, t, r, b);
33299
+ const unframed = cosmeticRectangleBox(rCtx, uprightFixBox(rCtx, l, t, r, b));
32216
33300
  const inset = insideFrameInset(rCtx, unframed, true, rCtx.state.arcDirection === 2);
32217
33301
  const box = inset ? insetFixBox(unframed, inset) : unframed;
32218
33302
  const clockwise = rCtx.state.arcDirection === 2;
@@ -32267,7 +33351,7 @@ function handleRectangle(rCtx, dataOff, recSize) {
32267
33351
  c.beginPath();
32268
33352
  c.rect(x, y, w, h);
32269
33353
  },
32270
- raster: () => rectRasterPath(box, clockwise),
33354
+ raster: () => rectRasterPath(devicePositiveBox(box), clockwise),
32271
33355
  rectangle: true,
32272
33356
  fill: true,
32273
33357
  stroke: true,
@@ -32377,7 +33461,7 @@ function handleRoundRect(rCtx, dataOff, recSize) {
32377
33461
  const devM = gdiDeviceMatrix(rCtx);
32378
33462
  const cornerFixW = inset ? Math.abs(cornerW * devM[0]) * 16 : fixExtent(rCtx, cornerW, 0);
32379
33463
  const cornerFixH = inset ? Math.abs(cornerH * devM[3]) * 16 : fixExtent(rCtx, cornerH, 1);
32380
- const cornerOnFrame = (fix, size, framedSize) => inset && size !== 0 ? Math.floor(Math.min(fix, size) * framedSize / size) : fix;
33464
+ const cornerOnFrame = (fix2, size, framedSize) => inset && size !== 0 ? Math.floor(Math.min(fix2, size) * framedSize / size) : fix2;
32381
33465
  let cw = cornerOnFrame(cornerFixW, Math.abs((r - l) * devM[0]) * 16, Math.abs(framed.exx));
32382
33466
  let ch = cornerOnFrame(cornerFixH, Math.abs((b - t) * devM[3]) * 16, Math.abs(framed.eyy));
32383
33467
  const drawBox = inset ? framed : curvedFixBox(rCtx, l, t, r, b, true);
@@ -32441,18 +33525,21 @@ function curvedFixBox(rCtx, l, t, r, b, upright = false) {
32441
33525
  return box;
32442
33526
  }
32443
33527
  const m = gdiDeviceMatrix(rCtx);
32444
- if (Math.abs(m[0]) !== 1 || Math.abs(m[3]) !== 1 || m[1] !== 0 || m[2] !== 0) {
33528
+ if (m[1] !== 0 || m[2] !== 0) {
32445
33529
  return box;
32446
33530
  }
33531
+ const whole = box.ax % 16 === 0 && box.ay % 16 === 0 && box.exx % 16 === 0 && box.eyy % 16 === 0;
33532
+ const gx = whole ? 4 : 0;
33533
+ const gy = gx;
32447
33534
  const sx = box.exx < 0 ? -1 : 1;
32448
33535
  const sy = box.eyy < 0 ? -1 : 1;
32449
33536
  return {
32450
- ax: box.ax - 4 * sx,
32451
- ay: box.ay - 4 * sy,
32452
- exx: box.exx + 8 * sx,
33537
+ ax: box.ax - gx * sx,
33538
+ ay: box.ay - gy * sy,
33539
+ exx: box.exx + 2 * gx * sx,
32453
33540
  exy: 0,
32454
33541
  eyx: 0,
32455
- eyy: box.eyy + 8 * sy
33542
+ eyy: box.eyy + 2 * gy * sy
32456
33543
  };
32457
33544
  }
32458
33545
  function handleEllipse(rCtx, dataOff, recSize) {
@@ -32548,34 +33635,41 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
32548
33635
  }
32549
33636
  };
32550
33637
  const kind = isArcTo ? "arcto" : recType === EMR_PIE ? "pie" : recType === EMR_CHORD ? "chord" : "arc";
33638
+ const radialOnBox = (box, x, y) => {
33639
+ const wl = r - l;
33640
+ const hl = b - t;
33641
+ if (wl === 0 || hl === 0) {
33642
+ return fixPoint(rCtx, x, y);
33643
+ }
33644
+ const u = (x - l) / wl;
33645
+ const v = (y - t) / hl;
33646
+ return [box.ax + box.exx * u + box.eyx * v, box.ay + box.exy * u + box.eyy * v];
33647
+ };
32551
33648
  const devM = gdiDeviceMatrix(rCtx);
32552
- const rawFix = (x, y) => [(devM[0] * x + devM[2] * y + devM[4]) * 16, (devM[1] * x + devM[3] * y + devM[5]) * 16];
32553
- const radialOnBox = (p, raw) => {
32554
- if (!inset) {
32555
- return p;
32556
- }
32557
- const [rl, rt] = rawFix(l, t);
32558
- const [rr, rb] = rawFix(r, b);
32559
- const kx = rr !== rl ? framed.exx / (rr - rl) : 1;
32560
- const ky = rb !== rt ? framed.eyy / (rb - rt) : 1;
32561
- const snap = (v) => Math.abs(v) < 1e-6 ? 0 : v;
32562
- return [framed.ax + framed.exx / 2 + snap(raw[0] - (rl + rr) / 2) * kx, framed.ay + framed.eyy / 2 + snap(raw[1] - (rt + rb) / 2) * ky];
33649
+ const mapFlips = devM[0] * devM[3] - devM[1] * devM[2] < 0;
33650
+ const axisMap2 = devM[1] === 0 && devM[2] === 0;
33651
+ const rasterArgs = (immediate = false) => {
33652
+ const box = inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed;
33653
+ const boxFlips = box.exx * box.eyy - box.exy * box.eyx < 0;
33654
+ const mirror2 = axisMap2 && isAxisBox(box) ? { x: devM[0] < 0, y: devM[3] < 0 } : void 0;
33655
+ return {
33656
+ box,
33657
+ mirror: mirror2,
33658
+ clockwise: mirror2 ? clockwise : clockwise !== (mapFlips !== boxFlips),
33659
+ s: radialOnBox(box, startX, startY),
33660
+ // Device FIX rounding can separate distinct radial points on the
33661
+ // same logical ray. Preserve their proven endpoint identity.
33662
+ e: fullEllipse ? radialOnBox(box, startX, startY) : radialOnBox(box, endX, endY),
33663
+ from: currentFix(rCtx)
33664
+ };
32563
33665
  };
32564
- const rasterArgs = (immediate = false) => ({
32565
- box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
32566
- s: radialOnBox(fixPoint(rCtx, startX, startY), rawFix(startX, startY)),
32567
- // Device FIX rounding can separate distinct radial points on the
32568
- // same logical ray. Preserve their proven endpoint identity.
32569
- e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY), rawFix(startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY), rawFix(endX, endY)),
32570
- from: currentFix(rCtx)
32571
- });
32572
33666
  if (inPath) {
32573
33667
  if (isArcTo) {
32574
33668
  continueFigure(rCtx);
32575
33669
  }
32576
33670
  build(gdiPathRecorder(rCtx));
32577
33671
  const a = rasterArgs();
32578
- arcRasterPath(a.box, a.s, a.e, clockwise, kind, a.from, rasterPathOf(rCtx));
33672
+ arcRasterPath(a.box, a.s, a.e, a.clockwise, kind, a.from, rasterPathOf(rCtx), a.mirror);
32579
33673
  if (needsFill) {
32580
33674
  rasterPathOf(rCtx).closeFigure();
32581
33675
  }
@@ -32589,7 +33683,7 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
32589
33683
  },
32590
33684
  raster: () => {
32591
33685
  const a = rasterArgs(true);
32592
- return arcRasterPath(a.box, a.s, a.e, clockwise, kind, a.from).path;
33686
+ return arcRasterPath(a.box, a.s, a.e, a.clockwise, kind, a.from, void 0, a.mirror).path;
32593
33687
  },
32594
33688
  fill: needsFill,
32595
33689
  stroke: true
@@ -32597,7 +33691,7 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
32597
33691
  }
32598
33692
  if (isArcTo) {
32599
33693
  const a = rasterArgs();
32600
- const end = arcRasterPath(a.box, a.s, a.e, clockwise, "arc").end;
33694
+ const end = arcRasterPath(a.box, a.s, a.e, a.clockwise, "arc", void 0, void 0, a.mirror).end;
32601
33695
  const dx = Math.floor(end[0] / 16);
32602
33696
  const dy = Math.floor(end[1] / 16);
32603
33697
  const inv2 = invertAffine(gdiDeviceMatrix(rCtx));
@@ -32719,6 +33813,21 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
32719
33813
  }
32720
33814
  }
32721
33815
 
33816
+ // src/emf-gdi-chroma-tie-data.ts
33817
+ var CHROMA_TIE_FLIPS = {
33818
+ "40,0": [374, 506, 1076, 1078, 1142, 1526, 1910, 2294, 2678, 3446, 5750, 5806, 5818, 5830, 5842, 5854, 5866, 5902, 5938, 6324, 7256, 7484, 7868, 8636, 8792, 8996, 9020, 9404, 9788, 10556, 11904, 12112, 12136, 12160, 12172, 12184, 12208, 12220, 12244, 12256, 12268, 12666, 13190, 13598, 15338, 18246, 18540, 18750, 19940, 21272, 21476, 21680, 21759, 21884, 24100, 24882, 27364, 27614, 28022, 30442, 30534, 30900, 31062, 32478, 32482, 33673, 36394, 36984, 37242, 37404, 40380, 41256, 41541, 42688, 42736, 42784, 43188, 46651, 48193, 49126, 49530, 49668, 50268, 53877, 54849, 55404, 55476, 58319, 61818, 62257, 66538, 67026, 67236, 67398, 67716, 69373, 71370, 73392, 73872, 77949, 78325, 79054, 80143, 80400, 85086, 85632, 86184, 86370, 86394, 88496, 91974, 98682, 98820, 98868, 99054, 102841, 104262, 104628, 110970, 111628, 115656, 116574, 116916, 119216, 119334, 119968, 123396, 127812, 128579, 129366, 129493, 129738, 134784, 134878, 140880, 142861, 143671, 146590, 147484, 150855, 151211, 153414, 153922, 154543, 155567, 157776, 159826, 160168, 160910, 162313, 165787, 166068, 169642, 171408, 171882, 172510, 174117, 174926, 176025, 176170, 176928, 177636, 177718, 177990, 178356, 181268, 184330, 184354, 184390, 184402, 184414, 184426, 184438, 184462, 184498, 184514, 185282, 185666, 186434, 186818, 188354, 189491, 190278, 190672, 190696, 190732, 190756, 190768, 190804, 190840, 191624, 192776, 193160, 193952, 194615, 194782, 194948, 195080, 195464, 195848, 196010],
33819
+ "40,20": [1345, 13655, 16768, 19051, 22461, 23888, 29071, 34630, 40955, 41856, 43128, 47160, 47377, 47934, 47976, 48106, 48607, 49476, 59008, 59116, 59372, 65851, 69045, 69721, 71741, 74531, 85884, 89225, 89899, 91692, 93843, 94915, 95071, 95968, 97561, 100356, 101005, 102444, 109699, 116446, 117163, 118538, 119501, 133219, 136360, 137042, 137929, 138173, 143164, 145012, 145555, 146068, 156036, 158160, 160630, 161047, 174146, 175587, 176339, 177137],
33820
+ "50,20": [3435, 4690, 7934, 11527, 21838, 22211, 24980, 32745, 35495, 36570, 38851, 41578, 43128, 49195, 57142, 72649, 73084, 81747, 89022, 89826, 93145, 94307, 96679, 99174, 99185, 102486, 103896, 109861, 110110, 112698, 116081, 130842, 133613, 137784, 139643, 142939, 143358, 143734, 143834, 152125, 158072, 170378, 170422, 174146, 175547, 177966, 180424, 182339, 190180, 192424, 196256],
33821
+ "-40,0": [5816, 9911, 17137, 17332, 18078, 19903, 25108, 39517, 46996, 54208, 54890, 55254, 59753, 61616, 73287, 73927, 77843, 90139, 93011, 94263, 96552, 99873, 104370, 115822, 116256, 119156, 122178, 125065, 125455, 127853, 133264, 133614, 136585, 141275, 148914, 149785, 153213, 156483, 167561, 171079, 171826, 183498, 184714, 185541, 186397, 190359, 194533],
33822
+ "100,0": [458, 506, 543, 845, 1142, 1274, 1526, 2294, 5074, 5750, 5782, 5806, 5818, 5830, 5854, 5866, 5902, 5926, 5938, 6800, 7100, 7256, 7484, 7616, 7868, 8384, 8636, 8792, 8996, 9020, 9152, 9404, 10328, 10556, 11324, 11416, 11904, 12092, 12112, 12136, 12160, 12184, 12208, 12244, 12256, 12268, 12546, 13142, 13370, 13502, 13598, 14522, 15338, 16670, 17320, 18246, 19484, 19712, 19940, 20864, 21068, 21272, 21476, 21680, 21884, 23710, 24882, 25615, 25874, 26054, 26282, 27002, 27206, 27614, 28022, 30004, 30442, 30780, 30883, 31062, 31176, 31224, 31434, 33073, 36480, 36984, 37122, 37242, 37404, 37566, 37776, 39326, 39686, 40862, 42346, 42688, 42784, 43746, 43908, 45308, 45543, 45668, 46232, 46959, 48210, 48250, 48322, 48380, 49030, 49078, 49126, 49248, 49530, 49668, 50088, 52485, 54592, 54688, 55030, 55343, 55404, 55476, 55590, 56010, 58009, 59324, 59888, 60522, 60592, 60628, 60894, 60934, 60958, 61372, 61746, 61932, 62118, 62352, 62617, 66410, 66970, 67276, 67324, 67348, 67398, 67716, 67902, 68088, 68274, 68460, 73240, 73340, 73618, 73666, 73690, 73872, 74430, 75097, 77750, 79094, 79618, 79686, 80052, 80400, 80690, 81053, 84630, 85308, 85632, 86184, 86370, 86394, 86742, 86928, 89565, 91974, 92478, 92526, 92898, 93084, 97548, 97782, 98610, 98682, 98820, 98868, 99426, 99612, 100368, 103704, 104124, 104262, 104628, 104952, 105162, 105210, 105396, 105768, 106117, 107011, 110614, 110686, 110712, 110970, 111040, 111294, 111504, 111738, 111924, 112828, 113676, 114388, 115341, 115393, 116574, 116916, 116956, 116992, 117636, 117846, 122298, 122464, 122968, 123266, 123298, 123334, 123650, 123724, 123978, 124188, 125029, 125924, 128054, 128514, 129238, 129262, 129286, 129310, 129366, 129640, 129712, 130196, 134784, 136054, 136080, 136538, 137182, 141253, 141946, 142018, 142292, 142396, 143060, 143828, 145207, 145667, 145693, 146155, 147484, 147922, 148226, 148264, 148288, 148312, 148392, 148634, 148738, 149402, 152235, 153414, 153874, 153922, 154264, 154568, 155106, 155744, 156104, 156308, 156512, 156716, 156858, 158768, 159360, 159826, 160168, 160216, 160264, 160606, 160910, 161020, 162086, 162242, 162398, 162446, 162650, 165540, 166068, 166168, 166558, 167252, 168584, 171720, 171882, 172510, 172948, 174926, 175538, 176306, 177852, 177990, 178356, 181064, 181268, 181676, 181997, 182648, 183008, 183936, 184330, 184354, 184390, 184402, 184414, 184438, 184462, 184514, 185194, 185282, 185632, 185666, 186434, 188354, 189758, 189890, 190278, 190410, 190672, 190684, 190696, 190732, 190768, 190804, 190816, 190840, 191624, 191926, 192776, 193160, 193802, 193952, 195080, 195165, 195332, 195464, 195692, 195848],
33823
+ "-100,0": [8492, 8494, 18577, 69397, 74091, 76386, 76390, 120219, 122518, 127206, 127210, 173433, 182718, 188113, 188115, 188117],
33824
+ "20,0": [374, 758, 1142, 1526, 2294, 2678, 4598, 5782, 5806, 5818, 5830, 5842, 5878, 5926, 5938, 6857, 7100, 7256, 7484, 7868, 8144, 8636, 9020, 9404, 10556, 11324, 11904, 12092, 12112, 12136, 12160, 12184, 12208, 12232, 12244, 12256, 12268, 12408, 15256, 15338, 16012, 19736, 22402, 24192, 24490, 24720, 30900, 31062, 33949, 36540, 37242, 43461, 45209, 45343, 47763, 49530, 50829, 51159, 52932, 54027, 54376, 55056, 55110, 55476, 59280, 59784, 60294, 61056, 61170, 65557, 65771, 67398, 71574, 73872, 78008, 79686, 80052, 83615, 86184, 86370, 88236, 88957, 90159, 90896, 90972, 91188, 92340, 92657, 93560, 94764, 95047, 95257, 95760, 98682, 98796, 102636, 103746, 104262, 104628, 108240, 110418, 110970, 113753, 116916, 121939, 122283, 122285, 123481, 126166, 126786, 127848, 128811, 129546, 133194, 137205, 139249, 140100, 140104, 143450, 143585, 144257, 148826, 153414, 157182, 159486, 160495, 160975, 161749, 164341, 166068, 166168, 168189, 169944, 171030, 171630, 173895, 175302, 175860, 176838, 178356, 184104, 184330, 184342, 184354, 184366, 184390, 184402, 184414, 184426, 184438, 184462, 184474, 184486, 184514, 185282, 185666, 185765, 187202, 188354, 188776, 190038, 190672, 190696, 190732, 190768, 190792, 190804, 190816, 190840, 191302, 191624, 192392, 192776, 193160, 194369, 194696, 195003, 195464, 195848],
33825
+ "70,0": [254, 458, 1142, 1274, 1526, 2246, 2294, 2348, 2450, 2654, 2858, 3062, 4598, 5750, 5782, 5806, 5830, 5842, 5854, 5866, 5902, 5926, 5938, 6300, 7100, 7256, 7484, 7616, 7868, 8384, 8636, 8792, 8996, 9020, 9404, 9470, 9497, 9788, 10328, 10556, 11021, 11324, 11416, 11904, 12092, 12112, 12136, 12184, 12244, 12256, 12268, 12546, 13370, 13598, 15134, 15338, 16670, 18540, 19532, 19712, 19940, 21068, 21272, 21476, 21884, 24192, 24720, 24841, 26282, 27410, 27614, 28180, 29026, 30004, 30442, 30534, 30900, 31062, 31224, 31434, 34160, 35373, 36480, 36984, 37242, 37404, 37566, 39890, 42688, 42784, 46640, 48380, 49030, 49078, 49126, 49248, 49530, 49668, 50088, 50659, 54592, 54664, 54688, 55476, 55590, 56010, 60766, 60958, 60982, 61372, 61560, 61746, 61932, 62617, 65226, 67348, 67398, 67716, 68088, 68274, 69492, 69557, 70194, 73107, 73578, 73714, 74244, 75841, 76888, 79686, 80400, 83650, 84127, 84200, 86184, 86370, 86394, 86742, 86845, 86928, 88496, 90155, 90522, 90549, 91974, 92478, 92526, 92898, 93084, 94736, 95937, 96873, 97782, 98682, 98820, 98868, 103659, 104262, 104628, 104952, 105162, 105210, 105396, 107075, 108234, 110686, 110712, 110970, 111294, 111504, 111628, 111738, 116332, 116574, 116916, 116992, 117636, 121933, 122621, 122968, 123024, 123334, 123396, 127016, 127044, 129262, 129286, 129310, 129366, 129712, 134394, 134784, 136054, 136080, 140378, 142018, 142292, 144762, 145335, 145710, 147484, 147922, 148226, 148312, 148392, 150262, 153414, 153874, 153922, 154568, 155744, 159360, 159826, 160168, 160216, 160264, 160606, 160910, 161076, 162242, 162446, 162650, 163690, 164494, 166068, 166168, 166558, 166606, 167252, 167848, 168584, 170886, 171648, 171882, 172510, 172948, 174722, 174926, 176306, 177852, 177990, 178356, 181064, 181268, 183008, 184330, 184354, 184390, 184402, 184414, 184426, 184438, 184462, 184498, 184514, 185194, 185282, 185632, 185666, 185714, 186434, 187202, 189033, 189051, 189758, 189890, 190278, 190672, 190696, 190732, 190792, 190804, 190816, 190840, 191624, 192776, 193160, 193952, 195464, 195563, 195692, 195848],
33826
+ "0,30": [1721, 4912, 17621, 23134, 24625, 24929, 33960, 36358, 38321, 38379, 40933, 42823, 43299, 45130, 45943, 49299, 52890, 53885, 57288, 57436, 59699, 61699, 64420, 65176, 65236, 72099, 72211, 72381, 83500, 85501, 88189, 89169, 92103, 93701, 95610, 95681, 108288, 108606, 114622, 117231, 119626, 123617, 127534, 133819, 136508, 136984, 139544, 143792, 145778, 147469, 149239, 153446, 153562, 154152, 159126, 166024, 175800, 176759, 180377, 181528, 182453, 183108, 192812],
33827
+ "0,-50": [1993, 2566, 7118, 7355, 11339, 12468, 15355, 19766, 19939, 26761, 31589, 32405, 35291, 38652, 41997, 50880, 52335, 53022, 53093, 55240, 72257, 72491, 75259, 75267, 80408, 83070, 83658, 83938, 85802, 86633, 90942, 99179, 101706, 102357, 106183, 108569, 117985, 120676, 140059, 141222, 143338, 147505, 147553, 150898, 152640, 156175, 156373, 156839, 158346, 159040, 163988, 171036, 176002, 179175, 179438, 192876, 194345, 194768, 194848],
33828
+ "0,60": [2079, 10520, 24043, 34818, 38212, 39257, 41632, 41905, 48383, 50923, 58894, 59675, 61206, 64816, 65028, 66919, 71898, 77171, 77667, 82511, 82591, 90280, 94741, 98446, 99892, 99982, 103615, 105816, 111088, 115141, 115170, 126478, 127086, 129937, 130463, 131475, 133798, 134795, 134807, 136638, 138053, 139328, 140657, 143569, 145200, 146837, 147691, 147766, 149712, 151474, 168315, 171698, 173961, 177231, 182638, 184786, 185640, 188116, 192273, 196154]
33829
+ };
33830
+
32722
33831
  // src/emf-gdi-illuminant-data.ts
32723
33832
  var ILLUMINANT_CUBE_DATA = {
32724
33833
  1: "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",
@@ -32900,7 +34009,33 @@ function adjustChroma(r, g, b, scale, angle) {
32900
34009
  }
32901
34010
  return out;
32902
34011
  }
32903
- function colorAdjustmentMapper(ca) {
34012
+ var chromaTieTables = /* @__PURE__ */ new Map();
34013
+ function chromaTieTable(ca) {
34014
+ if (ca.illuminant !== 0 && ca.illuminant !== 6) return null;
34015
+ const key = `${ca.colorfulness},${ca.redGreenTint}`;
34016
+ let table2 = chromaTieTables.get(key);
34017
+ if (table2 === void 0) {
34018
+ const flips = CHROMA_TIE_FLIPS[key];
34019
+ table2 = null;
34020
+ if (flips) {
34021
+ table2 = new Int8Array(32768 * 3);
34022
+ for (const f of flips) table2[f >> 1] = f & 1 ? 1 : -1;
34023
+ }
34024
+ chromaTieTables.set(key, table2);
34025
+ }
34026
+ return table2;
34027
+ }
34028
+ function paletteEntry(v) {
34029
+ const n = Math.round(v * 31 / 255);
34030
+ return PALETTE[n] === v ? n : -1;
34031
+ }
34032
+ function tieIndex(c) {
34033
+ const r = paletteEntry(c[0]);
34034
+ const g = paletteEntry(c[1]);
34035
+ const b = paletteEntry(c[2]);
34036
+ return r < 0 || g < 0 || b < 0 ? -1 : (r * 32 + g) * 32 + b;
34037
+ }
34038
+ function colorAdjustmentMapper(ca, options2) {
32904
34039
  const illuminant = illuminantCube(ca.illuminant);
32905
34040
  const matrix = ILLUMINANT_MATRICES[ca.illuminant];
32906
34041
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
@@ -32913,6 +34048,7 @@ function colorAdjustmentMapper(ca) {
32913
34048
  const angle = TINT_RADIANS * ca.redGreenTint / 100;
32914
34049
  const log = (ca.flags & CA_LOG_FILTER) !== 0;
32915
34050
  const negative = (ca.flags & CA_NEGATIVE) !== 0;
34051
+ const ties = chroma && options2?.chromaTies !== false ? chromaTieTable(ca) : null;
32916
34052
  const curve = (value, channel) => {
32917
34053
  let v = 255 * (clamp255(value) / 255) ** gammas[channel];
32918
34054
  v = (v - black) / span * 255;
@@ -32932,6 +34068,7 @@ function colorAdjustmentMapper(ca) {
32932
34068
  return (rgb2) => {
32933
34069
  let c = [rgb2 >> 16 & 255, rgb2 >> 8 & 255, rgb2 & 255];
32934
34070
  if (chroma) {
34071
+ const tie = ties ? tieIndex(c) : -1;
32935
34072
  c = c.map(exactPaletteLevel);
32936
34073
  if (matrix) {
32937
34074
  const [r, g, b] = c;
@@ -32939,6 +34076,7 @@ function colorAdjustmentMapper(ca) {
32939
34076
  }
32940
34077
  c = adjustChroma(c[0], c[1], c[2], scale, angle);
32941
34078
  c = c.map(roundHalfUp);
34079
+ if (ties && tie >= 0) c = c.map((v, k) => v + ties[tie * 3 + k]);
32942
34080
  } else if (illuminant) {
32943
34081
  const mapped = lookupIlluminant(illuminant, c[0] / 255, c[1] / 255, c[2] / 255);
32944
34082
  c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
@@ -33022,6 +34160,50 @@ function ditherQuantize(v, threshold) {
33022
34160
  return paletteLevel(n < 0 ? 0 : n > 31 ? 31 : n);
33023
34161
  }
33024
34162
 
34163
+ // src/emf-gdi-halftone-branch.ts
34164
+ function halftoneColorKey(r, g, b) {
34165
+ return b === r ? 16777216 | b >> 2 << 8 | g >> 2 : b | g << 8 | r << 16;
34166
+ }
34167
+ function halftoneBranch(rgb2, w, h) {
34168
+ if (w <= 0 || h <= 0) return "replicate";
34169
+ const n = w * h;
34170
+ if (n <= 2304) return "replicate";
34171
+ const keyAt = (i) => halftoneColorKey(rgb2[i * 3], rgb2[i * 3 + 1], rgb2[i * 3 + 2]);
34172
+ const seen = /* @__PURE__ */ new Set();
34173
+ if (n > 16384) {
34174
+ for (let y = 0; y < h; y += 6) {
34175
+ for (let x = 0; x < w; x++) seen.add(keyAt(y * w + x));
34176
+ if (seen.size >= 20) return "filter";
34177
+ }
34178
+ return "replicate";
34179
+ }
34180
+ const rows = Math.floor(2304 / w) + 1;
34181
+ if (h < rows) return "replicate";
34182
+ const exact = h === rows;
34183
+ const limit = exact ? 289 + Math.floor((rows * w - 2304) / 8) : 145 + Math.floor((rows * w - 2304) / 16);
34184
+ let colors = 0;
34185
+ let duplicateRows = 0;
34186
+ let coloredPixels = 0;
34187
+ let gaveUp = false;
34188
+ for (let y = 0; y < h; y++) {
34189
+ let added = 0;
34190
+ for (let x = 0; x < w; x++) {
34191
+ const key = keyAt(y * w + x);
34192
+ if (!seen.has(key)) {
34193
+ seen.add(key);
34194
+ added++;
34195
+ }
34196
+ }
34197
+ colors += added;
34198
+ if (!gaveUp && colors >= limit) return "filter";
34199
+ if (added === 0) duplicateRows++;
34200
+ else coloredPixels += w;
34201
+ if (colors >= 20 && coloredPixels > 2304 && !(exact && gaveUp)) return "filter";
34202
+ if (exact ? colors + duplicateRows * w >= limit - 1 : colors + (duplicateRows + 1) * w >= n - 2305 + limit) gaveUp = true;
34203
+ }
34204
+ return "replicate";
34205
+ }
34206
+
33025
34207
  // src/emf-gdi-stretch.ts
33026
34208
  var BLACKONWHITE = 1;
33027
34209
  var WHITEONBLACK = 2;
@@ -33154,119 +34336,24 @@ function halftoneReduceTaps(srcLen, dstLen, reverse) {
33154
34336
  if (reverse) taps.reverse();
33155
34337
  return taps;
33156
34338
  }
33157
- var ENLARGE_INNER = [
33158
- 1e3,
33159
- 992.47,
33160
- 984.9399,
33161
- 977.4099,
33162
- 969.8798,
33163
- 962.3498,
33164
- 954.8198,
33165
- 947.2897,
33166
- 939.7597,
33167
- 932.2296,
33168
- 924.6996,
33169
- 917.1695,
33170
- 909.6395,
33171
- 902.1095,
33172
- 894.5665,
33173
- 886.8087,
33174
- 879.045,
33175
- 871.2813,
33176
- 863.4349,
33177
- 855.5885,
33178
- 847.7421,
33179
- 839.8269,
33180
- 831.9046,
33181
- 823.912,
33182
- 815.9193,
33183
- 807.9266,
33184
- 799.847,
33185
- 791.7283,
33186
- 783.6096,
33187
- 775.449,
33188
- 767.3204,
33189
- 758.9233,
33190
- 750.5263,
33191
- 742.4271,
33192
- 734.0547,
33193
- 725.6823,
33194
- 717.232,
33195
- 708.7675,
33196
- 700.2393,
33197
- 691.7111,
33198
- 683.0734,
33199
- 674.4357,
33200
- 665.7105,
33201
- 656.9854,
33202
- 648.2603,
33203
- 639.3747,
33204
- 630.4873,
33205
- 621.5157,
33206
- 612.5442
33207
- ];
33208
- var ENLARGE_OUTER = [
33209
- 375.1388,
33210
- 364.2093,
33211
- 353.2797,
33212
- 342.4714,
33213
- 331.7615,
33214
- 321.1462,
33215
- 310.6456,
33216
- 300.2252,
33217
- 289.9229,
33218
- 279.7227,
33219
- 269.6439,
33220
- 259.6535,
33221
- 249.7825,
33222
- 240.0362,
33223
- 230.3856,
33224
- 220.8799,
33225
- 211.4594,
33226
- 202.1844,
33227
- 192.9996,
33228
- 183.9679,
33229
- 175.1064,
33230
- 166.2864,
33231
- 157.6436,
33232
- 149.1447,
33233
- 140.7609,
33234
- 132.5474,
33235
- 124.4802,
33236
- 116.5636,
33237
- 108.778,
33238
- 101.1602,
33239
- 93.7098,
33240
- 86.4419,
33241
- 79.3251,
33242
- 72.4091,
33243
- 65.6853,
33244
- 59.1472,
33245
- 52.812,
33246
- 46.6978,
33247
- 40.8001,
33248
- 35.1449,
33249
- 29.7494,
33250
- 24.6096,
33251
- 19.7977,
33252
- 15.2801,
33253
- 11.1442,
33254
- 7.3916,
33255
- 4.1415,
33256
- 1.4039,
33257
- 0
33258
- ];
33259
- var ENLARGE_HALF = 500.0106;
33260
- var ENLARGE_KNOTS = 96;
33261
34339
  function enlargeKernel(u) {
33262
34340
  if (u >= 1) return 0;
33263
- if (Math.abs(u - 0.5) < 1e-9) return ENLARGE_HALF;
33264
- const table2 = u < 0.5 ? ENLARGE_INNER : ENLARGE_OUTER;
33265
- const edge = u * ENLARGE_KNOTS - (u < 0.5 ? 0 : ENLARGE_KNOTS / 2);
33266
- const i = Math.min(table2.length - 2, Math.floor(edge + 1e-9));
33267
- return table2[i] + (table2[i + 1] - table2[i]) * (edge - i);
34341
+ const x = 1 - u;
34342
+ if (Math.abs(u - 0.5) < 1e-9) return x;
34343
+ return Math.pow(x, u < 0.5 ? Math.SQRT1_2 : Math.SQRT2);
33268
34344
  }
33269
34345
  function halftoneEnlargeTaps(src, dst) {
34346
+ return halftoneEnlargeCumulative(src, dst).map((row2) => {
34347
+ let prev = 0;
34348
+ return row2.map(([j, cum], i) => {
34349
+ const c = i === row2.length - 1 ? 8192 : Math.ceil(cum - 1e-7);
34350
+ const share = c - prev;
34351
+ prev = c;
34352
+ return [j, share / 8192];
34353
+ });
34354
+ });
34355
+ }
34356
+ function halftoneEnlargeCumulative(src, dst) {
33270
34357
  const ratio = dst / src;
33271
34358
  const reach = Math.ceil(ratio) - 1;
33272
34359
  const fir = [];
@@ -33287,7 +34374,7 @@ function halftoneEnlargeTaps(src, dst) {
33287
34374
  }
33288
34375
  cover.push(run);
33289
34376
  }
33290
- const taps = [];
34377
+ const rows = [];
33291
34378
  for (let x = 0; x < dst; x++) {
33292
34379
  const weights = /* @__PURE__ */ new Map();
33293
34380
  for (let k = -reach; k <= reach; k++) {
@@ -33298,18 +34385,13 @@ function halftoneEnlargeTaps(src, dst) {
33298
34385
  }
33299
34386
  }
33300
34387
  const sorted = [...weights.entries()].sort((a, b) => a[0] - b[0]);
33301
- let prev = 0;
33302
34388
  let cum = 0;
33303
- const row2 = [];
33304
- for (let i = 0; i < sorted.length; i++) {
33305
- cum += sorted[i][1] * 8192;
33306
- const c = i === sorted.length - 1 ? 8192 : Math.ceil(cum - 1e-7);
33307
- row2.push([sorted[i][0], (c - prev) / 8192]);
33308
- prev = c;
33309
- }
33310
- taps.push(row2);
34389
+ rows.push(sorted.map(([j, v]) => {
34390
+ cum += v * 8192;
34391
+ return [j, cum];
34392
+ }));
33311
34393
  }
33312
- return taps;
34394
+ return rows;
33313
34395
  }
33314
34396
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
33315
34397
  for (let y = 0; y < h; y++) {
@@ -33386,6 +34468,20 @@ function halftoneDespeckle(px, w, h) {
33386
34468
  }
33387
34469
  }
33388
34470
  }
34471
+ function halftoneSharpen(px, w, h) {
34472
+ const src = px.slice();
34473
+ const at = (x, y, c) => src[(Math.max(0, Math.min(h - 1, y)) * w + Math.max(0, Math.min(w - 1, x))) * 3 + c];
34474
+ for (let y = 0; y < h; y++) {
34475
+ for (let x = 0; x < w; x++) {
34476
+ for (let c = 0; c < 3; c++) {
34477
+ const v = at(x, y, c);
34478
+ const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
34479
+ const out = v + Math.floor((4 * v - sum) / 8);
34480
+ px[(y * w + x) * 3 + c] = out < 0 ? 0 : out > 255 ? 255 : out;
34481
+ }
34482
+ }
34483
+ }
34484
+ }
33389
34485
  function halftonePairDespeckle(px, w, h, rows) {
33390
34486
  const n = rows ? w : h;
33391
34487
  const at = (k, side) => (rows ? side * w + k : k * w + side) * 3;
@@ -33448,6 +34544,239 @@ function halftoneReduceBoth(rect, sw, sh, dw, dh, flipX, flipY) {
33448
34544
  }
33449
34545
  return out;
33450
34546
  }
34547
+ function halftoneReduceOneAxis(rect, sw, sh, dw, dh, flipX, flipY) {
34548
+ const vertical = dh < sh;
34549
+ const taps = vertical ? halftoneReduceTaps(sh, dh, flipY) : halftoneReduceTaps(sw, dw, flipX);
34550
+ const reduced = new Float64Array(dw * dh * 3);
34551
+ for (let y = 0; y < dh; y++) {
34552
+ for (let x = 0; x < dw; x++) {
34553
+ const run = vertical ? taps[y] : taps[x];
34554
+ const keep = vertical ? flipX ? dw - 1 - x : x : flipY ? dh - 1 - y : y;
34555
+ let total = 0;
34556
+ for (const [, w] of run) total += w;
34557
+ for (let c = 0; c < 3; c++) {
34558
+ let sum = 0;
34559
+ for (const [k, w] of run) sum += rect[((vertical ? k : keep) * sw + (vertical ? keep : k)) * 3 + c] * w;
34560
+ reduced[(y * dw + x) * 3 + c] = sum / total;
34561
+ }
34562
+ }
34563
+ }
34564
+ const out = new Int32Array(dw * dh * 3);
34565
+ const at = (x, y, c) => reduced[(Math.max(0, Math.min(dh - 1, y)) * dw + Math.max(0, Math.min(dw - 1, x))) * 3 + c];
34566
+ for (let y = 0; y < dh; y++) {
34567
+ for (let x = 0; x < dw; x++) {
34568
+ for (let c = 0; c < 3; c++) {
34569
+ const v = at(x, y, c);
34570
+ const sum = vertical ? at(x, y - 1, c) + at(x, y + 1, c) : at(x - 1, y, c) + at(x + 1, y, c);
34571
+ out[(y * dw + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + (2 * v - sum) / 4)));
34572
+ }
34573
+ }
34574
+ }
34575
+ return out;
34576
+ }
34577
+ var FILTER_WEIGHTS = {
34578
+ 1: [[5, 22, 5, 32]],
34579
+ 2: [[4, 12, 0, 16], [0, 12, 4, 16]],
34580
+ 3: [[6, 10, 0, 16], [1, 14, 1, 16], [0, 10, 6, 16]],
34581
+ 4: [[6, 10, 0, 16], [3, 12, 1, 16], [1, 12, 3, 16], [0, 10, 6, 16]],
34582
+ 5: [[13, 19, 0, 32], [6, 25, 1, 32], [3, 26, 3, 32], [1, 25, 6, 32], [0, 19, 13, 32]]
34583
+ };
34584
+ function filterAxisTaps(src, dst) {
34585
+ const factor = dst / src;
34586
+ if (factor === 2) {
34587
+ const rows = FILTER_WEIGHTS[2].map(([a, b, c]) => [a * 512, b * 512, c * 512]);
34588
+ return Array.from({ length: dst }, (_, i) => {
34589
+ const k = Math.floor(i / 2);
34590
+ const [a, b, c] = rows[i % 2];
34591
+ return [[Math.max(0, k - 1), a], [k, b], [Math.min(src - 1, k + 1), c]];
34592
+ });
34593
+ }
34594
+ return halftoneEnlargeTaps(src, dst).map((row2) => row2.map(([j, v]) => [j, Math.round(v * 8192)]));
34595
+ }
34596
+ function halftoneFilterOneAxis(rgb2, w, h, W, H, below) {
34597
+ const horizontal = W > w;
34598
+ const n = horizontal ? w : h;
34599
+ const sharp = new Int32Array(rgb2.length);
34600
+ const at = (x, y, c) => y >= h && below ? below[Math.max(0, Math.min(w - 1, x)) * 3 + c] : rgb2[(Math.max(0, Math.min(h - 1, y)) * w + Math.max(0, Math.min(w - 1, x))) * 3 + c];
34601
+ for (let y = 0; y < h; y++) {
34602
+ for (let x = 0; x < w; x++) {
34603
+ for (let c = 0; c < 3; c++) {
34604
+ const v = at(x, y, c);
34605
+ const sum = horizontal ? at(x - 1, y, c) + at(x + 1, y, c) : at(x, y - 1, c) + at(x, y + 1, c);
34606
+ const out2 = v + Math.floor((2 * v - sum) / 4);
34607
+ sharp[(y * w + x) * 3 + c] = out2 < 0 ? 0 : out2 > 255 ? 255 : out2;
34608
+ }
34609
+ }
34610
+ }
34611
+ const taps = filterAxisTaps(n, horizontal ? W : H);
34612
+ const out = new Int32Array(W * H * 3);
34613
+ for (let y = 0; y < H; y++) {
34614
+ for (let x = 0; x < W; x++) {
34615
+ for (let c = 0; c < 3; c++) {
34616
+ let sum = 0;
34617
+ if (horizontal) for (const [j, weight] of taps[x]) sum += weight * sharp[(y * w + j) * 3 + c];
34618
+ else for (const [j, weight] of taps[y]) sum += weight * sharp[(j * w + x) * 3 + c];
34619
+ out[(y * W + x) * 3 + c] = Math.floor((sum + 4096) / 8192);
34620
+ }
34621
+ }
34622
+ }
34623
+ return out;
34624
+ }
34625
+ function filterRuns(src, dst) {
34626
+ const k = Array.from({ length: dst }, (_, i) => halftoneNearest(i, src, dst));
34627
+ const length = /* @__PURE__ */ new Map();
34628
+ for (const v of k) length.set(v, (length.get(v) ?? 0) + 1);
34629
+ const placed = /* @__PURE__ */ new Map();
34630
+ return k.map((v) => {
34631
+ const p = placed.get(v) ?? 0;
34632
+ placed.set(v, p + 1);
34633
+ return { k: v, weights: FILTER_WEIGHTS[length.get(v)][p] };
34634
+ });
34635
+ }
34636
+ function halftoneFilterSupported(w, h, W, H) {
34637
+ return w > 0 && h > 0 && W >= w && H >= h && (W > w || H > h);
34638
+ }
34639
+ function ditherFilteredSource(rect, SW, SH, W, H, dither, flipY) {
34640
+ if (W > 5 * SW || H > 5 * SH) {
34641
+ const further = new Int32Array((SH + 1) * SW * 3);
34642
+ further.set(rect);
34643
+ further.set(rect.subarray((SH - 1) * SW * 3), SH * SW * 3);
34644
+ ditherPixels(
34645
+ further,
34646
+ SW,
34647
+ SH + 1,
34648
+ dither,
34649
+ false,
34650
+ false,
34651
+ void 0,
34652
+ Int32Array.from({ length: SH + 1 }, (_, j) => flipY ? H - 1 - j : j)
34653
+ );
34654
+ return further;
34655
+ }
34656
+ const extended = new Int32Array((SH + 4) * SW * 3);
34657
+ extended.set(rect.subarray(0, SW * 3), 0);
34658
+ extended.set(rect.subarray(0, SW * 3), SW * 3);
34659
+ extended.set(rect, 2 * SW * 3);
34660
+ extended.set(rect.subarray((SH - 1) * SW * 3), (SH + 2) * SW * 3);
34661
+ extended.set(rect.subarray((SH - 1) * SW * 3), (SH + 3) * SW * 3);
34662
+ ditherPixels(
34663
+ extended,
34664
+ SW,
34665
+ SH + 4,
34666
+ { startX: dither.startX, startY: (dither.startY + (flipY ? 63 : 2)) % 65 },
34667
+ false,
34668
+ false,
34669
+ void 0,
34670
+ Int32Array.from({ length: SH + 4 }, (_, e) => flipY ? H - e + 1 : e - 2)
34671
+ );
34672
+ return extended;
34673
+ }
34674
+ function halftoneFilterEnlarge(rgb2, w, h, W, H, extended) {
34675
+ if (W === w || H === h) return halftoneFilterOneAxis(rgb2, w, h, W, H, extended && extended.length === (h + 1) * w * 3 ? extended.subarray(h * w * 3) : void 0);
34676
+ const clamp2 = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
34677
+ const general = W > 5 * w || H > 5 * h;
34678
+ const out = new Int32Array(W * H * 3);
34679
+ if (general) {
34680
+ const sharp2 = rgb2.slice();
34681
+ if (extended) {
34682
+ const at2 = (x, y, c) => extended[(Math.max(0, Math.min(h, y)) * w + Math.max(0, Math.min(w - 1, x))) * 3 + c];
34683
+ for (let y = 0; y < h; y++) {
34684
+ for (let x = 0; x < w; x++) {
34685
+ for (let c = 0; c < 3; c++) {
34686
+ const v = at2(x, y, c);
34687
+ const sum = at2(x - 1, y, c) + at2(x + 1, y, c) + at2(x, y - 1, c) + at2(x, y + 1, c);
34688
+ sharp2[(y * w + x) * 3 + c] = clamp2(v + Math.floor((4 * v - sum) / 8));
34689
+ }
34690
+ }
34691
+ }
34692
+ } else {
34693
+ halftoneSharpen(sharp2, w, h);
34694
+ }
34695
+ const xt = filterAxisTaps(w, W);
34696
+ const yt = filterAxisTaps(h, H);
34697
+ const middle2 = new Int32Array(W * h * 3);
34698
+ for (let y = 0; y < h; y++) {
34699
+ for (let x = 0; x < W; x++) {
34700
+ for (let c = 0; c < 3; c++) {
34701
+ let sum = 0;
34702
+ for (const [j, weight] of xt[x]) sum += weight * sharp2[(y * w + j) * 3 + c];
34703
+ middle2[(y * W + x) * 3 + c] = Math.floor((sum + 4096) / 8192);
34704
+ }
34705
+ }
34706
+ }
34707
+ for (let y = 0; y < H; y++) {
34708
+ for (let x = 0; x < W; x++) {
34709
+ for (let c = 0; c < 3; c++) {
34710
+ let sum = 0;
34711
+ for (const [j, weight] of yt[y]) sum += weight * middle2[(j * W + x) * 3 + c];
34712
+ out[(y * W + x) * 3 + c] = clamp2(Math.floor((sum + 4096) / 8192));
34713
+ }
34714
+ }
34715
+ }
34716
+ return out;
34717
+ }
34718
+ const rows = h + 2;
34719
+ const sharp = new Int32Array(w * rows * 3);
34720
+ let padded;
34721
+ if (extended && extended.length === (h + 4) * w * 3) padded = extended;
34722
+ else {
34723
+ padded = new Int32Array(w * (h + 4) * 3);
34724
+ if (extended && extended.length === rows * w * 3) {
34725
+ padded.set(extended.subarray(w * 3, 2 * w * 3), 0);
34726
+ padded.set(extended, w * 3);
34727
+ padded.set(extended.subarray(h * w * 3, (h + 1) * w * 3), (h + 3) * w * 3);
34728
+ } else {
34729
+ padded.set(rgb2.subarray(0, w * 3), 0);
34730
+ padded.set(rgb2.subarray(0, w * 3), w * 3);
34731
+ padded.set(rgb2, 2 * w * 3);
34732
+ padded.set(rgb2.subarray((h - 1) * w * 3), (h + 2) * w * 3);
34733
+ padded.set(rgb2.subarray((h - 1) * w * 3), (h + 3) * w * 3);
34734
+ }
34735
+ }
34736
+ const source = padded;
34737
+ const at = (x, y, c) => source[((y + 1) * w + Math.max(0, Math.min(w - 1, x))) * 3 + c];
34738
+ for (let y = 0; y < rows; y++) {
34739
+ for (let x = 0; x < w; x++) {
34740
+ for (let c = 0; c < 3; c++) {
34741
+ const v = at(x, y, c);
34742
+ const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
34743
+ sharp[(y * w + x) * 3 + c] = clamp2(v + Math.floor((4 * v - sum) / 8));
34744
+ }
34745
+ }
34746
+ }
34747
+ const xr = filterRuns(w, W);
34748
+ const yr = filterRuns(h, H);
34749
+ const middle = new Int32Array(w * 3);
34750
+ for (let y = 0; y < H; y++) {
34751
+ const near = yr[y].k + 1;
34752
+ const [a, b, c, total] = yr[y].weights;
34753
+ const before = (near - 1) * w * 3;
34754
+ const here = near * w * 3;
34755
+ const after = (near + 1) * w * 3;
34756
+ for (let i = 0; i < w * 3; i++) {
34757
+ middle[i] = Math.floor((a * sharp[before + i] + b * sharp[here + i] + c * sharp[after + i] + total / 2) / total);
34758
+ }
34759
+ for (let x = 0; x < W; x++) {
34760
+ const k = xr[x].k;
34761
+ const [a2, b2, c2, total2] = xr[x].weights;
34762
+ const left = Math.max(0, k - 1);
34763
+ const right = Math.min(w - 1, k + 1);
34764
+ for (let c3 = 0; c3 < 3; c3++) {
34765
+ out[(y * W + x) * 3 + c3] = Math.floor((a2 * middle[left * 3 + c3] + b2 * middle[k * 3 + c3] + c2 * middle[right * 3 + c3] + total2 / 2) / total2);
34766
+ }
34767
+ }
34768
+ }
34769
+ return out;
34770
+ }
34771
+ function halftoneMixedEngine(rect, SW, SH, W, H) {
34772
+ const halved = W > SW && H * 2 <= SH || H > SH && W * 2 <= SW;
34773
+ const cap = H < SH && 3 * H + 2 <= 2 * SH || W < SW && 3 * W + 2 <= 2 * SW;
34774
+ if (halved || cap) return "reduced";
34775
+ const small = SW * SH <= 2304;
34776
+ if (!small && halftoneBranch(rect, SW, SH) === "filter") return "reduced";
34777
+ if (W * H < SW * SH) return small ? "despeckled" : "reduced";
34778
+ return "nearest";
34779
+ }
33451
34780
  function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false, dither, curves) {
33452
34781
  const W = Math.max(0, Math.round(Math.abs(dw)));
33453
34782
  const H = Math.max(0, Math.round(Math.abs(dh)));
@@ -33492,14 +34821,76 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
33492
34821
  const reducing = W < SW && H < SH;
33493
34822
  const mixed = W > SW && H < SH || W < SW && H > SH;
33494
34823
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
33495
- const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
33496
- const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
33497
- if ((enlarging || nearestMixed) && !directDib && !pairRows && !pairColumns) {
34824
+ const mixedPlain = mixed && (!adjust || adjustAfterSampling || dithered);
34825
+ const engine = mixedPlain ? halftoneMixedEngine(rect, SW, SH, W, H) : "nearest";
34826
+ const nearestMixed = mixedPlain && engine === "nearest" && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
34827
+ const nativeMixed = mixedPlain && engine !== "nearest";
34828
+ const despeckles = SW * SH <= 2304 || SW * SH > 16384;
34829
+ const oneAxisReduce = W < SW && H === SH || H < SH && W === SW;
34830
+ const reduceDespeckle = (reducing || oneAxisReduce) && despeckles && !directDib && !(W < SW && 3 * W + 2 <= 2 * SW) && !(H < SH && 3 * H + 2 <= 2 * SH) && (SW * SH <= 2304 || halftoneBranch(rect, SW, SH) === "replicate");
34831
+ if (oneAxisReduce && (!adjust || adjustAfterSampling || dithered)) {
34832
+ if (reduceDespeckle) halftoneDespeckle(rect, SW, SH);
34833
+ const reduced = halftoneReduceOneAxis(rect, SW, SH, W, H, flipX, flipY);
34834
+ if (dithered) {
34835
+ ditherPixels(reduced, W, H, dither);
34836
+ adjust(reduced);
34837
+ if (curves) curves(reduced);
34838
+ } else if (adjust) adjust(reduced);
34839
+ for (let i = 0, o = 0; i < W * H; i++, o += 3) {
34840
+ data[i * 4] = reduced[o];
34841
+ data[i * 4 + 1] = reduced[o + 1];
34842
+ data[i * 4 + 2] = reduced[o + 2];
34843
+ data[i * 4 + 3] = 255;
34844
+ }
34845
+ return { width: W, height: H, data };
34846
+ }
34847
+ if (enlarging && halftoneFilterSupported(SW, SH, W, H) && (!adjust || adjustAfterSampling || dithered) && halftoneBranch(rect, SW, SH) === "filter") {
34848
+ let extended;
34849
+ let source = rect;
34850
+ if (dithered) {
34851
+ if (W === SW || H === SH) {
34852
+ if (H > SH) {
34853
+ extended = new Int32Array((SH + 1) * SW * 3);
34854
+ extended.set(rect);
34855
+ extended.set(rect.subarray((SH - 1) * SW * 3), SH * SW * 3);
34856
+ ditherPixels(extended, SW, SH + 1, dither, false, false, void 0, Int32Array.from({ length: SH + 1 }, (_, j) => flipY ? H - 1 - j : j));
34857
+ adjust(extended);
34858
+ source = extended.subarray(0, SW * SH * 3);
34859
+ } else {
34860
+ source = rect.slice();
34861
+ ditherPixels(source, SW, SH, dither, false, false, void 0, Int32Array.from({ length: SH }, (_, j) => flipY ? H - 1 - j : j));
34862
+ adjust(source);
34863
+ }
34864
+ } else {
34865
+ extended = ditherFilteredSource(rect, SW, SH, W, H, dither, flipY);
34866
+ adjust(extended);
34867
+ }
34868
+ }
34869
+ const filtered = halftoneFilterEnlarge(source, SW, SH, W, H, extended);
34870
+ if (flipX || flipY) {
34871
+ const mirror2 = filtered.slice();
34872
+ for (let y = 0; y < H; y++) {
34873
+ for (let x = 0; x < W; x++) {
34874
+ const from = ((flipY ? H - 1 - y : y) * W + (flipX ? W - 1 - x : x)) * 3;
34875
+ filtered.set(mirror2.subarray(from, from + 3), (y * W + x) * 3);
34876
+ }
34877
+ }
34878
+ }
34879
+ if (adjust && adjustAfterSampling) adjust(filtered);
34880
+ if (curves && dithered) curves(filtered);
34881
+ for (let i = 0, o = 0; i < W * H; i++, o += 3) {
34882
+ data[i * 4] = filtered[o];
34883
+ data[i * 4 + 1] = filtered[o + 1];
34884
+ data[i * 4 + 2] = filtered[o + 2];
34885
+ data[i * 4 + 3] = 255;
34886
+ }
34887
+ return { width: W, height: H, data };
34888
+ }
34889
+ if (((enlarging || nearestMixed || engine === "despeckled") && despeckles || reducing && reduceDespeckle) && !directDib && !pairRows && !pairColumns) {
33498
34890
  halftoneDespeckle(rect, SW, SH);
33499
34891
  }
33500
- const reducedEven = W < SW ? SW % 2 === 0 && H % SH === 0 : SH % 2 === 0 && W % SW === 0;
33501
- const ditherAtSource = dithered && (W >= SW && H >= SH || nativeMixed && reducedEven);
33502
- const extendRow = ditherAtSource && nativeMixed && W < SW && H > SH && !flipY;
34892
+ const ditherAtSource = dithered && (W >= SW && H >= SH || nativeMixed && W * H >= SW * SH);
34893
+ const extendRow = ditherAtSource && nativeMixed && W < SW && H > SH;
33503
34894
  if (extendRow) {
33504
34895
  const bigger = new Int32Array((SH + 1) * SW * 3);
33505
34896
  bigger.set(rect);
@@ -33515,7 +34906,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
33515
34906
  false,
33516
34907
  false,
33517
34908
  void 0,
33518
- flipY ? Int32Array.from({ length: SH }, (_, j) => H - 1 - j) : void 0
34909
+ flipY ? Int32Array.from({ length: extendRow ? SH + 1 : SH }, (_, j) => H - 1 - j) : void 0
33519
34910
  );
33520
34911
  }
33521
34912
  if (adjust && !adjustAfterSampling && (!dithered || ditherAtSource)) {
@@ -36620,9 +38011,9 @@ function handlePolyDraw(rCtx, offset, dataOff, recSize, pointSize) {
36620
38011
  ensureOpen();
36621
38012
  const pts = [0, 1, 2].map((k) => readPt(i + k));
36622
38013
  const dev = pts.map(([x, y]) => gmapPoint(rCtx, x, y));
36623
- const fix = pts.map(([x, y]) => fixPoint(rCtx, x, y));
38014
+ const fix2 = pts.map(([x, y]) => fixPoint(rCtx, x, y));
36624
38015
  canvas?.bezierCurveTo(dev[0].x, dev[0].y, dev[1].x, dev[1].y, dev[2].x, dev[2].y);
36625
- raster?.bezierTo(fix[0][0], fix[0][1], fix[1][0], fix[1][1], fix[2][0], fix[2][1]);
38016
+ raster?.bezierTo(fix2[0][0], fix2[0][1], fix2[1][0], fix2[1][1], fix2[2][0], fix2[2][1]);
36626
38017
  i += 2;
36627
38018
  } else {
36628
38019
  continue;
@@ -38021,22 +39412,22 @@ function strokeGdiplus(rCtx, pen, nib, sampler, buildPath, device, size, mode, c
38021
39412
  const m = frame2.toDevice;
38022
39413
  return poly.flatMap((p) => [toPlusFix(m[0] * p.x + m[2] * p.y + m[4]), toPlusFix(m[1] * p.x + m[3] * p.y + m[5])]);
38023
39414
  };
38024
- let fix;
39415
+ let fix2;
38025
39416
  if (hasCustomCap(pen)) {
38026
- fix = customCapOutline(figures, width, devicePen, pen).map(toFix);
39417
+ fix2 = customCapOutline(figures, width, devicePen, pen).map(toFix);
38027
39418
  } else if (width <= NOMINAL_PEN_MAX && !devicePen.dash && !(((pen.startCap ?? 0) | (pen.endCap ?? 0) | (pen.dashCap ?? 0)) & 240)) {
38028
39419
  return strokeNominal(rCtx, pen, sampler, buildPath, device, size, antialias, closedFigure);
38029
39420
  } else {
38030
- fix = widenFigures(figures, devicePen).map(toFix);
39421
+ fix2 = widenFigures(figures, devicePen).map(toFix);
38031
39422
  }
38032
- const box = figuresBox(fix, size);
39423
+ const box = figuresBox(fix2, size);
38033
39424
  if (!box) {
38034
39425
  return true;
38035
39426
  }
38036
39427
  if (box.w * box.h > 16e6) {
38037
39428
  return false;
38038
39429
  }
38039
- const coverage = rasterizePlusFill(fix, false, antialias, isHalfPixelOffset(rCtx.pixelOffsetMode ?? 0), box);
39430
+ const coverage = rasterizePlusFill(fix2, false, antialias, isHalfPixelOffset(rCtx.pixelOffsetMode ?? 0), box);
38040
39431
  return compositeBrushCoverage(rCtx, sampler, box, coverage, 1, true);
38041
39432
  }
38042
39433
  function strokeNominal(rCtx, pen, sampler, buildPath, device, size, antialias, closedFigure) {
@@ -38171,7 +39562,7 @@ function deviceQuad(wt, s, pts) {
38171
39562
  }
38172
39563
  return out;
38173
39564
  }
38174
- function imageResampleSpec(rCtx, dataOff, isMetafile, toWorld) {
39565
+ function imageResampleSpec(rCtx, dataOff, isMetafile, toWorld, points) {
38175
39566
  const { view } = rCtx;
38176
39567
  const kernel = resampleKernelFor(rCtx.interpolationMode ?? 0);
38177
39568
  if (isMetafile || view.getUint32(dataOff + 4, true) !== UNIT_PIXEL2) {
@@ -38192,10 +39583,11 @@ function imageResampleSpec(rCtx, dataOff, isMetafile, toWorld) {
38192
39583
  toDevice: mulMatrix(plusWorldMatrix(rCtx), toWorld(srcX, srcY, srcW, srcH)),
38193
39584
  kernel,
38194
39585
  halfPixelOffset: isHalfPixelOffset(rCtx.pixelOffsetMode ?? 0),
39586
+ ...points ? { pointsForm: true } : {},
38195
39587
  ...imageAttributesWrap(rCtx, view.getUint32(dataOff, true))
38196
39588
  };
38197
39589
  }
38198
- function drawOrDeferImage(rCtx, imgObj, dataOff, dx, dy, dw, dh, toWorld, effect = null) {
39590
+ function drawOrDeferImage(rCtx, imgObj, dataOff, dx, dy, dw, dh, toWorld, effect = null, points = false) {
38199
39591
  if (!imgObj.data) {
38200
39592
  return;
38201
39593
  }
@@ -38208,7 +39600,7 @@ function drawOrDeferImage(rCtx, imgObj, dataOff, dx, dy, dw, dh, toWorld, effect
38208
39600
  dh,
38209
39601
  transform: plusWorldMatrix(rCtx),
38210
39602
  isMetafile,
38211
- resample: imageResampleSpec(rCtx, dataOff, isMetafile, toWorld)
39603
+ resample: imageResampleSpec(rCtx, dataOff, isMetafile, toWorld, points)
38212
39604
  };
38213
39605
  const { view } = rCtx;
38214
39606
  const source = {
@@ -38677,7 +40069,7 @@ function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataS
38677
40069
  const c = (p3x - p1x) / sh;
38678
40070
  const d = (p3y - p1y) / sh;
38679
40071
  return [a, b, c, d, p1x - a * sx - c * sy, p1y - b * sx - d * sy];
38680
- }, effect);
40072
+ }, effect, true);
38681
40073
  } else {
38682
40074
  imgObj && imgObj.kind === "plus-image" && imgObj.data;
38683
40075
  }
@@ -40886,15 +42278,15 @@ function compatBox(p, l, t, r, b, opts = {}) {
40886
42278
  return box;
40887
42279
  }
40888
42280
  function fixBoxOf(box, cornerExact, keepInverted = false) {
40889
- const fix = keepInverted ? axisBox(box.x0, box.y0, box.x1, box.y1) : axisBox(box.x0, box.y0, Math.max(box.x0, box.x1), Math.max(box.y0, box.y1));
42281
+ const fix2 = keepInverted ? axisBox(box.x0, box.y0, box.x1, box.y1) : axisBox(box.x0, box.y0, Math.max(box.x0, box.x1), Math.max(box.y0, box.y1));
40890
42282
  if (box.halfX) {
40891
- fix.halfX = true;
40892
- fix.halfXCompat = true;
42283
+ fix2.halfX = true;
42284
+ fix2.halfXCompat = true;
40893
42285
  }
40894
42286
  if (cornerExact) {
40895
- fix.cornerExact = cornerExact;
42287
+ fix2.cornerExact = cornerExact;
40896
42288
  }
40897
- return fix;
42289
+ return fix2;
40898
42290
  }
40899
42291
  function canvasRect(box) {
40900
42292
  return { x: box.x0 / 16, y: box.y0 / 16, w: Math.max(0, box.x1 - box.x0) / 16, h: Math.max(0, box.y1 - box.y0) / 16 };