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