emf-converter 4.8.1 → 4.8.3

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.mjs CHANGED
@@ -17037,13 +17037,17 @@ function expandedBlur(rgba, width, height, radius, x0, y0, x1, y1, cropped) {
17037
17037
  const blurred = blurReduction(radius) > 1 ? effectBlur(buf, bw, bh, radius, cropped ? { x: r, y: r, w: x1 - x0, h: y1 - y0 } : void 0, true) : gdipBlur(buf, bw, bh, radius, cropped ? r : 0, cropped, Math.ceil((y1 - y0) / (x1 - x0)));
17038
17038
  const w = x1 - x0;
17039
17039
  const out = new Uint8ClampedArray(w * (y1 - y0) * 4);
17040
+ const halo = new Uint8ClampedArray((y1 - y0) * 4);
17040
17041
  for (let y = 0; y < y1 - y0; y++) {
17041
17042
  const from = ((y + r) * bw + r) * 4;
17042
17043
  for (let i = 0; i < w * 4; i++) {
17043
17044
  out[y * w * 4 + i] = Math.round(blurred[from + i]);
17044
17045
  }
17046
+ for (let i = 0; i < 4; i++) {
17047
+ halo[y * 4 + i] = Math.round(blurred[from + w * 4 + i]);
17048
+ }
17045
17049
  }
17046
- return out;
17050
+ return { out, halo };
17047
17051
  }
17048
17052
  function applyImageEffectToRect(rgba, width, height, effect, src) {
17049
17053
  if (width <= 0 || height <= 0 || rgba.length !== width * height * 4) {
@@ -17076,7 +17080,12 @@ function applyImageEffectToRect(rgba, width, height, effect, src) {
17076
17080
  };
17077
17081
  if (src && effect.kind === "blur" && effect.expandEdge) {
17078
17082
  const cropped = Math.ceil(src.x + src.w) < width && Math.ceil(src.y + src.h) < height;
17079
- return result(expandedBlur(rgba, width, height, effect.radius, x0, y0, x1, y1, cropped));
17083
+ const { out: out2, halo } = expandedBlur(rgba, width, height, effect.radius, x0, y0, x1, y1, cropped);
17084
+ const region2 = result(out2);
17085
+ if (shownWidth === w && shownHeight === h) {
17086
+ region2.haloRight = halo;
17087
+ }
17088
+ return region2;
17080
17089
  }
17081
17090
  let region = rgba;
17082
17091
  if (w !== width || h !== height) {
@@ -20448,6 +20457,22 @@ function cubicIntegral(t, a) {
20448
20457
  }
20449
20458
  return Math.sign(t) * v;
20450
20459
  }
20460
+ 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];
20461
+ function fadeAt(d, bilinear) {
20462
+ if (d >= 1) {
20463
+ return 0;
20464
+ }
20465
+ if (bilinear) {
20466
+ return 1 - Math.max(0, d);
20467
+ }
20468
+ const x = Math.max(0, d) * 20;
20469
+ const i = Math.floor(x);
20470
+ return FAR_FADE[i] + (FAR_FADE[i + 1] - FAR_FADE[i]) * (x - i);
20471
+ }
20472
+ function nearSourceExtent(deviceLen, srcLen) {
20473
+ const d = Math.ceil(deviceLen - 1e-6) - srcLen;
20474
+ return d >= -1 && d <= 1;
20475
+ }
20451
20476
  var BICUBIC_A = -0.5;
20452
20477
  var HQ_BICUBIC_A = -1;
20453
20478
  function axisFilter(kernel, scale, copy) {
@@ -20552,13 +20577,39 @@ function mirroredOrigin(o) {
20552
20577
  return f === 0 ? o : Math.floor(o) + 1 - f;
20553
20578
  }
20554
20579
  function resampleImage(rgba, width, height, spec, surface) {
20580
+ if (spec.rightHalo && spec.rightHalo.length === height * 4) {
20581
+ const grown = new Uint8ClampedArray((width + 1) * height * 4);
20582
+ for (let y = 0; y < height; y++) {
20583
+ grown.set(rgba.subarray(y * width * 4, (y + 1) * width * 4), y * (width + 1) * 4);
20584
+ grown.set(spec.rightHalo.subarray(y * 4, y * 4 + 4), (y * (width + 1) + width) * 4);
20585
+ }
20586
+ return resampleImage(grown, width + 1, height, { ...spec, rightHalo: void 0 }, surface);
20587
+ }
20555
20588
  if (spec.kernel === "nearest" && !spec.wrap) {
20556
20589
  return resampleNearest(rgba, width, height, spec, surface);
20557
20590
  }
20558
20591
  let m = snapToDeviceGrid(spec);
20559
- const kernel = spec.kernel;
20592
+ let kernel = spec.kernel;
20560
20593
  const hq = kernel === "hq-bilinear" || kernel === "hq-bicubic";
20561
20594
  const axisAligned = m[1] === 0 && m[2] === 0;
20595
+ let farFade = false;
20596
+ let shiftX = 0;
20597
+ let shiftY = 0;
20598
+ if (hq && !axisAligned) {
20599
+ const extentU = Math.hypot(m[0], m[1]) * spec.srcW;
20600
+ const extentV = Math.hypot(m[2], m[3]) * spec.srcH;
20601
+ if (nearSourceExtent(extentU, spec.srcW) || nearSourceExtent(extentV, spec.srcH)) {
20602
+ kernel = kernel === "hq-bicubic" ? "bicubic" : "bilinear";
20603
+ } else {
20604
+ farFade = true;
20605
+ if (spec.halfPixelOffset) {
20606
+ const lu = Math.hypot(m[0], m[1]);
20607
+ const lv = Math.hypot(m[2], m[3]);
20608
+ shiftX = 0.5 * m[0] / lu + 0.5 * m[2] / lv;
20609
+ shiftY = 0.5 * m[1] / lu + 0.5 * m[3] / lv;
20610
+ }
20611
+ }
20612
+ }
20562
20613
  if (hq && axisAligned) {
20563
20614
  const ox = m[0] * spec.srcX + m[4];
20564
20615
  m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5]];
@@ -20613,6 +20664,8 @@ function resampleImage(rgba, width, height, spec, surface) {
20613
20664
  const vMax = spec.srcY + spec.srcH;
20614
20665
  const wu = [];
20615
20666
  const wv = [];
20667
+ const gradU = Math.hypot(inv2[0], inv2[2]);
20668
+ const gradV = Math.hypot(inv2[1], inv2[3]);
20616
20669
  const c = spec.clampArgb ?? 0;
20617
20670
  const edge = {
20618
20671
  wrap: spec.wrap,
@@ -20624,8 +20677,8 @@ function resampleImage(rgba, width, height, spec, surface) {
20624
20677
  const py = by0 + j + o;
20625
20678
  for (let i = 0; i < w; i++) {
20626
20679
  const px = bx0 + i + o;
20627
- const u = inv2[0] * px + inv2[2] * py + inv2[4];
20628
- const v = inv2[1] * px + inv2[3] * py + inv2[5];
20680
+ const u = inv2[0] * (px - shiftX) + inv2[2] * (py - shiftY) + inv2[4];
20681
+ const v = inv2[1] * (px - shiftX) + inv2[3] * (py - shiftY) + inv2[5];
20629
20682
  const cx = px + COVERAGE_NUDGE_X;
20630
20683
  const cy = py + COVERAGE_NUDGE_Y;
20631
20684
  const eu = inv2[0] * cx + inv2[2] * cy + inv2[4];
@@ -20633,31 +20686,35 @@ function resampleImage(rgba, width, height, spec, surface) {
20633
20686
  if (eu < spec.srcX || ev < spec.srcY || eu >= uMax || ev >= vMax) {
20634
20687
  continue;
20635
20688
  }
20636
- const cu = u;
20637
- const cv = v;
20638
- const iu0 = Math.ceil(cu - fu.radius);
20639
- const iu1 = Math.floor(cu + fu.radius);
20640
- const iv0 = Math.ceil(cv - fv.radius);
20641
- const iv1 = Math.floor(cv + fv.radius);
20642
- wu.length = 0;
20643
- wv.length = 0;
20644
- for (let t = iu0; t <= iu1; t++) {
20645
- wu.push(fu.weight(t, cu));
20646
- }
20647
- for (let t = iv0; t <= iv1; t++) {
20648
- wv.push(fv.weight(t, cv));
20649
- }
20650
- const [r, g, b, a] = blendSeparable(
20651
- rgba,
20652
- width,
20653
- spec.wrap ? { x0: 0, y0: 0, x1: width, y1: height } : { x0: sx0, y0: sy0, x1: sx1, y1: sy1 },
20654
- iu0,
20655
- wu,
20656
- iv0,
20657
- wv,
20658
- kernel === "bicubic",
20659
- edge
20660
- );
20689
+ const box = { x0: 0, y0: 0, x1: width, y1: height };
20690
+ const sampleAt = (cu, cv) => {
20691
+ const iu0 = Math.ceil(cu - fu.radius);
20692
+ const iu1 = Math.floor(cu + fu.radius);
20693
+ const iv0 = Math.ceil(cv - fv.radius);
20694
+ const iv1 = Math.floor(cv + fv.radius);
20695
+ wu.length = 0;
20696
+ wv.length = 0;
20697
+ for (let t = iu0; t <= iu1; t++) {
20698
+ wu.push(fu.weight(t, cu));
20699
+ }
20700
+ for (let t = iv0; t <= iv1; t++) {
20701
+ wv.push(fv.weight(t, cv));
20702
+ }
20703
+ return blendSeparable(rgba, width, box, iu0, wu, iv0, wv, kernel === "bicubic", edge);
20704
+ };
20705
+ let [r, g, b, a] = sampleAt(u, v);
20706
+ if (farFade && !spec.wrap && a > 0) {
20707
+ const du = (uMax - u) / gradU;
20708
+ const dv = (vMax - v) / gradV;
20709
+ 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);
20710
+ if (k < 1) {
20711
+ const f = Math.max(0, k);
20712
+ r *= f;
20713
+ g *= f;
20714
+ b *= f;
20715
+ a *= f;
20716
+ }
20717
+ }
20661
20718
  if (a <= 0) {
20662
20719
  continue;
20663
20720
  }
@@ -23484,7 +23541,8 @@ function effectedDraw(img, bitmap, effect, draw, source) {
23484
23541
  srcY,
23485
23542
  srcW,
23486
23543
  srcH,
23487
- toDevice: mulMatrix(draw.resample.toDevice, shift)
23544
+ toDevice: mulMatrix(draw.resample.toDevice, shift),
23545
+ rightHalo: region.haloRight
23488
23546
  }
23489
23547
  }
23490
23548
  };
@@ -29226,9 +29284,9 @@ function perpendicularVectors(width, dx0, dy0) {
29226
29284
  const vx = rounded[0], vy = rounded[1];
29227
29285
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29228
29286
  }
29229
- function squareExtension(width, dx, dy) {
29287
+ function squareExtension(width, dx, dy, scale = 1) {
29230
29288
  const len = Math.hypot(dx, dy);
29231
- const r = width / 2;
29289
+ const r = width / 2 * scale;
29232
29290
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
29233
29291
  }
29234
29292
  function turnSign(ax, ay, bx, by) {
@@ -29267,7 +29325,7 @@ var Outliner = class {
29267
29325
  const [L, R] = drawVertices(this.pen, d[0], d[1]);
29268
29326
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29269
29327
  const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1]);
29270
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1]), curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29328
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1]), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29271
29329
  }
29272
29330
  push(p, v) {
29273
29331
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29362,7 +29420,7 @@ var Outliner = class {
29362
29420
  return side === "R" ? s.v : [-s.v[0], -s.v[1]];
29363
29421
  }
29364
29422
  /** A cap at `p` from the `from` side of `s` round to the other side (`start`: around the back). */
29365
- cap(p, s, start) {
29423
+ cap(p, s, start, scale = 1) {
29366
29424
  const from = start ? "L" : "R";
29367
29425
  const to = start ? "R" : "L";
29368
29426
  const { cap } = this.opts;
@@ -29380,7 +29438,8 @@ var Outliner = class {
29380
29438
  const sv = this.capSide(s, from);
29381
29439
  const ev = this.capSide(s, to);
29382
29440
  if (cap === "square") {
29383
- const e = start ? [-s.e[0], -s.e[1]] : s.e;
29441
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale);
29442
+ const e = start ? [-e0[0], -e0[1]] : e0;
29384
29443
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29385
29444
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
29386
29445
  } else {
@@ -29476,7 +29535,7 @@ var Outliner = class {
29476
29535
  * lets a single point stand for a zero-length dash along `dirs[0]`;
29477
29536
  * `draws` (curve end tangents) picks draw vertices only.
29478
29537
  */
29479
- open(P, dirs, draws, curves) {
29538
+ open(P, dirs, draws, curves, startScale = 1, endScale = 1) {
29480
29539
  if (P.length < 2 && !dirs?.[0]) {
29481
29540
  this.dot(P[0]);
29482
29541
  return;
@@ -29487,12 +29546,12 @@ var Outliner = class {
29487
29546
  }
29488
29547
  if (segs2.length === 0) {
29489
29548
  const s = this.seg(P[0], P[0], dirs?.[0], draws?.[0], curves?.[0]);
29490
- this.cap(P[0], s, true);
29491
- this.cap(P[0], s, false);
29549
+ this.cap(P[0], s, true, startScale);
29550
+ this.cap(P[0], s, false, endScale);
29492
29551
  this.flush();
29493
29552
  return;
29494
29553
  }
29495
- this.cap(P[0], segs2[0], true);
29554
+ this.cap(P[0], segs2[0], true, startScale);
29496
29555
  for (let i = 0; i + 1 < segs2.length; i++) {
29497
29556
  const s = segs2[i];
29498
29557
  const t = segs2[i + 1];
@@ -29503,7 +29562,7 @@ var Outliner = class {
29503
29562
  this.join(P[i + 1], s, t, "R", tr < 0);
29504
29563
  }
29505
29564
  }
29506
- this.cap(P[P.length - 1], segs2[segs2.length - 1], false);
29565
+ this.cap(P[P.length - 1], segs2[segs2.length - 1], false, endScale);
29507
29566
  for (let i = segs2.length - 1; i > 0; i--) {
29508
29567
  const s = segs2[i];
29509
29568
  const t = segs2[i - 1];
@@ -29559,7 +29618,7 @@ var Outliner = class {
29559
29618
  this.flush();
29560
29619
  }
29561
29620
  };
29562
- function dashPieces(P, tangents, pattern, shorten) {
29621
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29563
29622
  const out = [];
29564
29623
  const dashes = [];
29565
29624
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29574,12 +29633,22 @@ function dashPieces(P, tangents, pattern, shorten) {
29574
29633
  let idx = 0;
29575
29634
  let left = dashes[0];
29576
29635
  let on = true;
29577
- let cur = { pts: [P[0]], dirs: [], draws: [] };
29636
+ let cur = { pts: [P[0]], dirs: [], draws: [], curves: [], startScale: 1, endScale: 1 };
29578
29637
  for (let i = 0; i + 1 < P.length; i++) {
29579
29638
  const [x0, y0] = P[i];
29580
29639
  const [x1, y1] = P[i + 1];
29581
29640
  const dir = [x1 - x0, y1 - y0];
29582
- const len = Math.hypot(dir[0], dir[1]);
29641
+ const real = Math.hypot(dir[0], dir[1]);
29642
+ const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29643
+ if (len === 0) {
29644
+ if (on && cur) {
29645
+ cur.pts.push(P[i + 1]);
29646
+ cur.dirs.push(dir);
29647
+ cur.draws.push(tangents[i]);
29648
+ cur.curves.push(curveFlags[i]);
29649
+ }
29650
+ continue;
29651
+ }
29583
29652
  let t = 0;
29584
29653
  while (len - t > left || left === 0 && on) {
29585
29654
  t += left;
@@ -29588,10 +29657,12 @@ function dashPieces(P, tangents, pattern, shorten) {
29588
29657
  cur.pts.push(q);
29589
29658
  cur.dirs.push(dir);
29590
29659
  cur.draws.push(tangents[i]);
29660
+ cur.curves.push(curveFlags[i]);
29661
+ cur.endScale = cur.pts[0] === P[0] && q[0] === P[0][0] && q[1] === P[0][1] ? 1 : real / len;
29591
29662
  out.push(cur);
29592
29663
  cur = null;
29593
29664
  } else {
29594
- cur = { pts: [q], dirs: [], draws: [] };
29665
+ cur = { pts: [q], dirs: [], draws: [], curves: [], startScale: real / len, endScale: 1 };
29595
29666
  }
29596
29667
  on = !on;
29597
29668
  idx = (idx + 1) % dashes.length;
@@ -29602,9 +29673,12 @@ function dashPieces(P, tangents, pattern, shorten) {
29602
29673
  cur.pts.push(P[i + 1]);
29603
29674
  cur.dirs.push(dir);
29604
29675
  cur.draws.push(tangents[i]);
29676
+ cur.curves.push(curveFlags[i]);
29677
+ cur.endScale = real / len;
29605
29678
  }
29606
29679
  }
29607
29680
  if (on && cur && cur.dirs.length > 0) {
29681
+ cur.endScale = 1;
29608
29682
  out.push(cur);
29609
29683
  }
29610
29684
  return out;
@@ -29639,10 +29713,13 @@ function widenPath(path, opts) {
29639
29713
  if (dashed) {
29640
29714
  const run = closed ? [...P, P[0]] : P;
29641
29715
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29642
- for (const piece of dashPieces(run, closed ? [...dirs, void 0] : dirs, opts.dashes, shorten)) {
29716
+ const runTangents = closed ? [...dirs, void 0] : dirs;
29717
+ const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29718
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29643
29719
  const pts = [piece.pts[0]];
29644
29720
  const pdirs = [];
29645
29721
  const pdraws = [];
29722
+ const pcurves = [];
29646
29723
  for (let i = 1; i < piece.pts.length; i++) {
29647
29724
  const q = piece.pts[i];
29648
29725
  const last = pts[pts.length - 1];
@@ -29650,9 +29727,10 @@ function widenPath(path, opts) {
29650
29727
  pts.push(q);
29651
29728
  pdirs.push(piece.dirs[i - 1]);
29652
29729
  pdraws.push(piece.draws[i - 1]);
29730
+ pcurves.push(piece.curves[i - 1]);
29653
29731
  }
29654
29732
  }
29655
- outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]], pts.map(() => !!fig.roundWiden));
29733
+ outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]], pdirs.length > 0 ? pcurves : [piece.curves[0]], piece.startScale, piece.endScale);
29656
29734
  }
29657
29735
  } else if (closed && P.length >= 3) {
29658
29736
  outliner.closed(P, dirs, curves);
@@ -29860,7 +29938,10 @@ function penWidenOptions(rCtx, opts = {}) {
29860
29938
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
29861
29939
  miterLimit: state.miterLimit ?? 10,
29862
29940
  dashes: dashes ? dashes.map((v) => v * 16) : null,
29863
- shortenDashes: (flags & 15) !== 7
29941
+ shortenDashes: (flags & 15) !== 7,
29942
+ // One logical unit per device pixel, unrotated: GDI measures dash
29943
+ // segments in whole pixels.
29944
+ 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
29864
29945
  };
29865
29946
  }
29866
29947
  function hatchBackgroundMask(hatch) {
@@ -31400,6 +31481,15 @@ function illuminantCube(index) {
31400
31481
  }
31401
31482
  return cube;
31402
31483
  }
31484
+ var ILLUMINANT_MATRICES = {
31485
+ 1: [[1.64737, -0.59174, -0.05494], [0.02963, 0.96126, 881e-5], [0.2911, 0.40189, 0.30769]],
31486
+ 2: [[1.22319, -0.17765, -0.04515], [275e-5, 0.99054, 645e-5], [0.05514, 0.12795, 0.81816]],
31487
+ 3: [[1.02833, -0.01775, -0.01086], [861e-5, 0.98431, 728e-5], [-0.01616, -0.0448, 1.05995]],
31488
+ 4: [[1.17271, -0.14059, -0.03174], [-474e-5, 1.00266, 183e-5], [0.05783, 0.14663, 0.79683]],
31489
+ 5: [[1.10431, -0.08327, -0.02067], [-336e-5, 1.0025, 67e-5], [0.03344, 0.09072, 0.87702]],
31490
+ 7: [[0.92515, 0.05628, 0.01822], [318e-5, 0.9967, 34e-5], [-0.02086, -0.06817, 1.08783]],
31491
+ 8: [[1.31275, -0.26259, -0.04977], [-244e-5, 0.99695, 524e-5], [0.10854, 0.23443, 0.65827]]
31492
+ };
31403
31493
  function hasIlluminant(ca) {
31404
31494
  return illuminantCube(ca.illuminant) !== null;
31405
31495
  }
@@ -31470,9 +31560,9 @@ var BRIGHTNESS_STEP = 0.95625;
31470
31560
  var COLORFULNESS_SCALE = 1 / 100;
31471
31561
  var TINT_RADIANS = -Math.PI / 3;
31472
31562
  var RGB_TO_XYZ = [
31473
- [0.4124, 0.3576, 0.1805],
31474
- [0.2126, 0.7152, 0.0722],
31475
- [0.0193, 0.1192, 0.9505]
31563
+ [0.4123908, 0.3575843, 0.1804808],
31564
+ [0.212639, 0.7151687, 0.0721923],
31565
+ [0.0193308, 0.1191948, 0.9505322]
31476
31566
  ];
31477
31567
  var XYZ_TO_RGB = invert3(RGB_TO_XYZ);
31478
31568
  var WHITE = RGB_TO_XYZ.map((row2) => row2[0] + row2[1] + row2[2]);
@@ -31500,13 +31590,13 @@ function adjustChroma(r, g, b, scale, angle) {
31500
31590
  const z = RGB_TO_XYZ[2][0] * r + RGB_TO_XYZ[2][1] * g + RGB_TO_XYZ[2][2] * b;
31501
31591
  const d = x + 15 * y + 3 * z;
31502
31592
  if (d <= 1e-9 || y <= 1e-9) {
31503
- return [r, g, b];
31593
+ return [clamp255(r), clamp255(g), clamp255(b)];
31504
31594
  }
31505
31595
  const du = 4 * x / d - WHITE_U;
31506
31596
  const dv = 9 * y / d - WHITE_V;
31507
31597
  const cos = Math.cos(angle) * scale;
31508
31598
  const sin = Math.sin(angle) * scale;
31509
- const u = WHITE_U + du * cos - dv * sin;
31599
+ const u = Math.max(0, WHITE_U + du * cos - dv * sin);
31510
31600
  const v = Math.max(1e-6, WHITE_V + du * sin + dv * cos);
31511
31601
  const x2 = y * 9 * u / (4 * v);
31512
31602
  const z2 = y * (12 - 3 * u - 20 * v) / (4 * v);
@@ -31525,6 +31615,7 @@ function adjustChroma(r, g, b, scale, angle) {
31525
31615
  }
31526
31616
  function colorAdjustmentMapper(ca) {
31527
31617
  const illuminant = illuminantCube(ca.illuminant);
31618
+ const matrix = ILLUMINANT_MATRICES[ca.illuminant];
31528
31619
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
31529
31620
  const black = ca.referenceBlack / 1e4 * 255;
31530
31621
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 * 255 - black);
@@ -31553,16 +31644,17 @@ function colorAdjustmentMapper(ca) {
31553
31644
  }
31554
31645
  return (rgb2) => {
31555
31646
  let c = [rgb2 >> 16 & 255, rgb2 >> 8 & 255, rgb2 & 255];
31556
- if (illuminant) {
31557
- const mapped = lookupIlluminant(illuminant, c[0] / 255, c[1] / 255, c[2] / 255);
31558
- c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
31559
- }
31560
31647
  if (chroma) {
31561
- if (!illuminant) {
31562
- c = c.map(exactPaletteLevel);
31648
+ c = c.map(exactPaletteLevel);
31649
+ if (matrix) {
31650
+ const [r, g, b] = c;
31651
+ c = matrix.map((row2) => row2[0] * r + row2[1] * g + row2[2] * b);
31563
31652
  }
31564
- c = adjustChroma(clamp255(c[0]), clamp255(c[1]), clamp255(c[2]), scale, angle);
31653
+ c = adjustChroma(c[0], c[1], c[2], scale, angle);
31565
31654
  c = c.map(roundHalfUp);
31655
+ } else if (illuminant) {
31656
+ const mapped = lookupIlluminant(illuminant, c[0] / 255, c[1] / 255, c[2] / 255);
31657
+ c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
31566
31658
  }
31567
31659
  return curve(c[0], 0) << 16 | curve(c[1], 1) << 8 | curve(c[2], 2);
31568
31660
  };
@@ -31916,20 +32008,6 @@ function halftoneDespeckle(px, w, h) {
31916
32008
  }
31917
32009
  }
31918
32010
  }
31919
- function halftoneSharpen(px, w, h) {
31920
- const src = px.slice();
31921
- 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];
31922
- for (let y = 0; y < h; y++) {
31923
- for (let x = 0; x < w; x++) {
31924
- for (let c = 0; c < 3; c++) {
31925
- const v = at(x, y, c);
31926
- const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
31927
- const out = v + Math.floor((4 * v - sum) / 8);
31928
- px[(y * w + x) * 3 + c] = out < 0 ? 0 : out > 255 ? 255 : out;
31929
- }
31930
- }
31931
- }
31932
- }
31933
32011
  function halftonePairDespeckle(px, w, h, rows) {
31934
32012
  const n = rows ? w : h;
31935
32013
  const at = (k, side) => (rows ? side * w + k : k * w + side) * 3;
@@ -31952,6 +32030,46 @@ function halftoneKeepLast(px, w, h, rows) {
31952
32030
  }
31953
32031
  return out;
31954
32032
  }
32033
+ function halftoneReduceBoth(rect, sw, sh, dw, dh, flipX, flipY) {
32034
+ const cols = halftoneReduceTaps(sw, dw, flipX);
32035
+ const rows = halftoneReduceTaps(sh, dh, flipY);
32036
+ const wide = new Int32Array(dw * sh * 3);
32037
+ for (let y = 0; y < sh; y++) {
32038
+ for (let x = 0; x < dw; x++) {
32039
+ let total = 0;
32040
+ for (const [, w] of cols[x]) total += w;
32041
+ for (let c = 0; c < 3; c++) {
32042
+ let sum = 0;
32043
+ for (const [xx, w] of cols[x]) sum += rect[(y * sw + xx) * 3 + c] * w;
32044
+ wide[(y * dw + x) * 3 + c] = Math.floor((2 * sum + total) / (2 * total));
32045
+ }
32046
+ }
32047
+ }
32048
+ const avg = new Float64Array(dw * dh * 3);
32049
+ for (let y = 0; y < dh; y++) {
32050
+ let total = 0;
32051
+ for (const [, w] of rows[y]) total += w;
32052
+ for (let x = 0; x < dw; x++) {
32053
+ for (let c = 0; c < 3; c++) {
32054
+ let sum = 0;
32055
+ for (const [yy, w] of rows[y]) sum += wide[(yy * dw + x) * 3 + c] * w;
32056
+ avg[(y * dw + x) * 3 + c] = sum / total;
32057
+ }
32058
+ }
32059
+ }
32060
+ const at = (x, y, c) => avg[(Math.max(0, Math.min(dh - 1, y)) * dw + Math.max(0, Math.min(dw - 1, x))) * 3 + c];
32061
+ const out = new Int32Array(dw * dh * 3);
32062
+ for (let y = 0; y < dh; y++) {
32063
+ for (let x = 0; x < dw; x++) {
32064
+ for (let c = 0; c < 3; c++) {
32065
+ const v = at(x, y, c);
32066
+ const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
32067
+ out[(y * dw + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + (4 * v - sum) / 8)));
32068
+ }
32069
+ }
32070
+ }
32071
+ return out;
32072
+ }
31955
32073
  function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false, dither, curves) {
31956
32074
  const W = Math.max(0, Math.round(Math.abs(dw)));
31957
32075
  const H = Math.max(0, Math.round(Math.abs(dh)));
@@ -32003,11 +32121,18 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32003
32121
  }
32004
32122
  const reducedEven = W < SW ? SW % 2 === 0 && H % SH === 0 : SH % 2 === 0 && W % SW === 0;
32005
32123
  const ditherAtSource = dithered && (W >= SW && H >= SH || nativeMixed && reducedEven);
32124
+ const extendRow = ditherAtSource && nativeMixed && W < SW && H > SH && !flipY;
32125
+ if (extendRow) {
32126
+ const bigger = new Int32Array((SH + 1) * SW * 3);
32127
+ bigger.set(rect);
32128
+ bigger.copyWithin(SH * SW * 3, (SH - 1) * SW * 3, SH * SW * 3);
32129
+ rect = bigger;
32130
+ }
32006
32131
  if (ditherAtSource) {
32007
32132
  ditherPixels(
32008
32133
  rect,
32009
32134
  SW,
32010
- SH,
32135
+ extendRow ? SH + 1 : SH,
32011
32136
  dither,
32012
32137
  false,
32013
32138
  false,
@@ -32047,7 +32172,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32047
32172
  linear(rows, SH, H, flipY);
32048
32173
  }
32049
32174
  let out = nativeMixed ? new Float64Array(sampleW * sampleH * 3) : new Int32Array(W * H * 3);
32050
- for (let y = 0; y < sampleH; y++) {
32175
+ if (reducing) {
32176
+ out = halftoneReduceBoth(rect, SW, SH, W, H, flipX, flipY);
32177
+ }
32178
+ for (let y = 0; !reducing && y < sampleH; y++) {
32051
32179
  const ys = rows[y];
32052
32180
  for (let x = 0; x < sampleW; x++) {
32053
32181
  const xs = cols[x];
@@ -32072,15 +32200,38 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32072
32200
  out[o + 2] = round(b);
32073
32201
  }
32074
32202
  }
32075
- if (reducing) {
32076
- halftoneSharpen(out, W, H);
32077
- }
32078
32203
  if (nativeMixed) {
32079
32204
  const reduceHorizontal = W < SW;
32205
+ let extension;
32206
+ if (extendRow) {
32207
+ const reduced = new Float64Array(sampleW * 3);
32208
+ for (let x = 0; x < sampleW; x++) {
32209
+ let total = 0;
32210
+ const sums = [0, 0, 0];
32211
+ for (const [xx, wx] of cols[x]) {
32212
+ total += wx;
32213
+ for (let c = 0; c < 3; c++) sums[c] += rect[(SH * SW + xx) * 3 + c] * wx;
32214
+ }
32215
+ for (let c = 0; c < 3; c++) reduced[x * 3 + c] = sums[c] / total;
32216
+ }
32217
+ extension = reduced;
32218
+ }
32080
32219
  for (const horizontal of [reduceHorizontal, !reduceHorizontal]) {
32081
32220
  const source2 = out;
32082
32221
  out = new Int32Array(source2.length);
32083
- const at = (x, y, c) => source2[(Math.max(0, Math.min(sampleH - 1, y)) * sampleW + Math.max(0, Math.min(sampleW - 1, x))) * 3 + c];
32222
+ const ext = extension;
32223
+ const at = (x, y, c) => y >= sampleH && ext ? ext[Math.max(0, Math.min(sampleW - 1, x)) * 3 + c] : source2[(Math.max(0, Math.min(sampleH - 1, y)) * sampleW + Math.max(0, Math.min(sampleW - 1, x))) * 3 + c];
32224
+ if (horizontal && ext) {
32225
+ const next = new Int32Array(sampleW * 3);
32226
+ for (let x = 0; x < sampleW; x++) {
32227
+ for (let c = 0; c < 3; c++) {
32228
+ const v = ext[x * 3 + c];
32229
+ const sum = at(x - 1, sampleH, c) + at(x + 1, sampleH, c);
32230
+ next[x * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + (2 * v - sum) / 4)));
32231
+ }
32232
+ }
32233
+ extension = next;
32234
+ }
32084
32235
  for (let y = 0; y < sampleH; y++) {
32085
32236
  for (let x = 0; x < sampleW; x++) {
32086
32237
  for (let c = 0; c < 3; c++) {