emf-converter 4.8.0 → 4.8.2

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
@@ -16401,8 +16401,8 @@ function midtoneGamma(t) {
16401
16401
  low = high;
16402
16402
  high = (high + 100) / 2;
16403
16403
  }
16404
- gamma = Math.abs(t) === 100 ? 10 : Math.min(10, gamma + (Math.abs(t) - low) / (high - low));
16405
- return Math.fround(t < 0 ? gamma : 1 / gamma);
16404
+ gamma = Math.abs(t) === 100 ? 10 : Math.min(10, truncF32(gamma + truncF32(truncF32(Math.abs(t) - low) / truncF32(high - low))));
16405
+ return t < 0 ? truncF32(gamma) : truncF32(1 / truncF32(gamma));
16406
16406
  }
16407
16407
  function brightnessContrastLut(brightness, contrast) {
16408
16408
  const gain = contrast >= 100 ? 1e6 : contrast >= 0 ? 100 / (100 - contrast) : (100 + contrast) / 100;
@@ -16419,6 +16419,23 @@ function curveAdjustmentLut(adjustment, intensity) {
16419
16419
  return nativeCurveLookup(adjustment, clamp(Math.trunc(intensity), min, max)).slice();
16420
16420
  }
16421
16421
  function levelsLut(highlight, midtone, shadow) {
16422
+ if (highlight !== shadow) {
16423
+ const forward = highlight > shadow;
16424
+ const lo = truncF32((forward ? shadow : highlight) * 255 / 100);
16425
+ const hi = truncF32((forward ? highlight : shadow) * 255 / 100);
16426
+ const scale = truncF32(1 / truncF32(hi - lo));
16427
+ const exponent2 = midtoneGamma(midtone);
16428
+ const lut = new Uint8Array(256);
16429
+ for (let v = 0; v < 256; v++) {
16430
+ let level = clamp(truncF32(truncF32(v - lo) * scale), 0, 1);
16431
+ if (midtone !== 0) {
16432
+ level = truncF32(level ** exponent2);
16433
+ }
16434
+ const out = forward ? truncF32(255 * level) : truncF32(255 - truncF32(255 * level));
16435
+ lut[v] = clamp(Math.floor(out + 0.5), 0, 255);
16436
+ }
16437
+ return lut;
16438
+ }
16422
16439
  const base = shadow * 255 / 100 - (highlight === shadow && shadow < 50 ? 1 : 0);
16423
16440
  const span = highlight === shadow ? 1 : (highlight - shadow) * 255 / 100;
16424
16441
  const exponent = midtoneGamma(midtone);
@@ -16451,14 +16468,6 @@ function applyColorMatrix(src, m) {
16451
16468
  }
16452
16469
  return out;
16453
16470
  }
16454
- function hslToRgb(h, s, l) {
16455
- const c = (1 - Math.abs(2 * l - 1)) * s;
16456
- const hp = (h % 360 + 360) % 360 / 60;
16457
- const x = c * (1 - Math.abs(hp % 2 - 1));
16458
- const m = l - c / 2;
16459
- const [r, g, b] = hp < 1 ? [c, x, 0] : hp < 2 ? [x, c, 0] : hp < 3 ? [0, c, x] : hp < 4 ? [0, x, c] : hp < 5 ? [x, 0, c] : [c, 0, x];
16460
- return [r + m, g + m, b + m];
16461
- }
16462
16471
  var HUE_SEXTANT = 43;
16463
16472
  var HUE_CIRCLE = 255;
16464
16473
  function gdipHue(r, g, b) {
@@ -16481,29 +16490,30 @@ function gdipHue(r, g, b) {
16481
16490
  function applyHueSaturationLightness(src, hue, saturation, lightness) {
16482
16491
  const out = new Uint8ClampedArray(src);
16483
16492
  const shift = Math.round(hue * HUE_CIRCLE / 360);
16484
- const sMul = 1 + saturation / 100;
16493
+ const satScale = 65536 + Math.floor(saturation * 65536 / 100);
16494
+ const lightOffset = Math.round(255 * Math.floor(lightness * 65536 / 100) / 65536);
16485
16495
  for (let i = 0; i < src.length; i += 4) {
16486
16496
  const r = src[i];
16487
16497
  const g = src[i + 1];
16488
16498
  const b = src[i + 2];
16489
16499
  const max = Math.max(r, g, b);
16490
16500
  const min = Math.min(r, g, b);
16491
- const l = clamp(Math.round(((max + min >> 1) * 100 + 255 * lightness) / 100), 0, 255);
16501
+ const l = clamp((max + min >> 1) + lightOffset, 0, 255);
16492
16502
  if (max === min) {
16493
16503
  out[i] = out[i + 1] = out[i + 2] = l;
16494
16504
  continue;
16495
16505
  }
16496
16506
  const sum = max + min;
16497
- const s = Math.fround(clamp((max - min) / (sum <= 255 ? sum : 510 - sum) * sMul, 0, 1));
16498
- const hi = l <= 127 ? l * (1 + s) : l + s * (255 - l);
16499
- const m1 = l <= 127 ? 2 * l - Math.trunc(hi) : Math.round(2 * l - hi);
16500
- const m2 = 2 * l - m1;
16507
+ const sat2 = clamp(Math.round(Math.floor((max - min) * 255 / (sum <= 255 ? sum : 510 - sum)) * satScale / 65536), 0, 255);
16508
+ const hi = l <= 127 ? Math.floor(l * (255 + sat2) / 255) : l + sat2 - Math.floor(l * sat2 / 255);
16509
+ const m1 = 2 * l - hi;
16510
+ const m2 = hi;
16501
16511
  const index = ((gdipHue(r, g, b) + shift) % HUE_CIRCLE + HUE_CIRCLE) % HUE_CIRCLE;
16502
16512
  const q = index + Math.floor((index + 41) / 85);
16503
16513
  const sextant = Math.min(5, Math.floor(q / HUE_SEXTANT));
16504
- const f = (q - sextant * HUE_SEXTANT) / HUE_SEXTANT;
16505
- const up = Math.trunc(m1 + (m2 - m1) * f);
16506
- const down = Math.trunc(m1 + (m2 - m1) * (1 - f));
16514
+ const position = q - sextant * HUE_SEXTANT;
16515
+ const up = m1 + Math.floor((m2 - m1) * position / HUE_SEXTANT);
16516
+ const down = m1 + Math.floor((m2 - m1) * (HUE_SEXTANT - position) / HUE_SEXTANT);
16507
16517
  const [nr, ng, nb] = [
16508
16518
  [m2, up, m1],
16509
16519
  [down, m2, m1],
@@ -16518,28 +16528,40 @@ function applyHueSaturationLightness(src, hue, saturation, lightness) {
16518
16528
  }
16519
16529
  return out;
16520
16530
  }
16521
- var LUMA_709 = [0.2126, 0.7152, 0.0722];
16522
- var TINT_CHROMA_SCALE = 0.985;
16523
16531
  function applyTint(src, hue, amount) {
16524
16532
  const index = (Math.round(hue * 255 / 360) + 256) % 256;
16525
16533
  const q = (index + Math.floor((index + 41) / 85)) % 258;
16526
- const tint = hslToRgb(q * 60 / 43, 1, 0.5);
16527
- const ty = tint[0] * LUMA_709[0] + tint[1] * LUMA_709[1] + tint[2] * LUMA_709[2];
16528
- const chroma = tint.map((c) => (c - ty) * TINT_CHROMA_SCALE);
16529
- const a = amount / 100;
16534
+ const sextant = Math.min(5, Math.floor(q / HUE_SEXTANT));
16535
+ const position = q - sextant * HUE_SEXTANT;
16536
+ const up = Math.floor(TINT_FULL * position / HUE_SEXTANT);
16537
+ const down = Math.floor(TINT_FULL * (HUE_SEXTANT - position) / HUE_SEXTANT);
16538
+ const [tr, tg, tb] = [
16539
+ [TINT_FULL, up, 0],
16540
+ [down, TINT_FULL, 0],
16541
+ [0, TINT_FULL, up],
16542
+ [0, down, TINT_FULL],
16543
+ [up, 0, TINT_FULL],
16544
+ [TINT_FULL, 0, down]
16545
+ ][sextant];
16546
+ const weight = Math.sign(amount) * Math.floor((255 * Math.abs(amount) + 49) / 100);
16547
+ const original = 255 - weight;
16530
16548
  const out = new Uint8ClampedArray(src);
16531
16549
  for (let i = 0; i < src.length; i += 4) {
16532
16550
  const r = src[i];
16533
16551
  const g = src[i + 1];
16534
16552
  const b = src[i + 2];
16535
- const y = r * LUMA_709[0] + g * LUMA_709[1] + b * LUMA_709[2];
16536
- const v = Math.max(r, g, b);
16537
- out[i] = Math.round((1 - a) * r + a * (y + v * chroma[0]));
16538
- out[i + 1] = Math.round((1 - a) * g + a * (y + v * chroma[1]));
16539
- out[i + 2] = Math.round((1 - a) * b + a * (y + v * chroma[2]));
16553
+ const u = weight * Math.max(r, g, b) >> 8;
16554
+ const x0 = original * r + tr * u;
16555
+ const x1 = original * g + tg * u;
16556
+ const x2 = original * b + tb * u;
16557
+ const base = 54 * r + 183 * g + 19 * b - (54 * (x0 >> 8) + 183 * (x1 >> 8) + 19 * (x2 >> 8));
16558
+ out[i] = base + x0 >> 8;
16559
+ out[i + 1] = base + x1 >> 8;
16560
+ out[i + 2] = base + x2 >> 8;
16540
16561
  }
16541
16562
  return out;
16542
16563
  }
16564
+ var TINT_FULL = 254;
16543
16565
  function applyRedEyeCorrection(src, width, height, areas) {
16544
16566
  const out = new Uint8ClampedArray(src);
16545
16567
  for (const a of areas) {
@@ -20539,8 +20561,7 @@ function resampleImage(rgba, width, height, spec, surface) {
20539
20561
  const axisAligned = m[1] === 0 && m[2] === 0;
20540
20562
  if (hq && axisAligned) {
20541
20563
  const ox = m[0] * spec.srcX + m[4];
20542
- const oy = m[3] * spec.srcY + m[5];
20543
- m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5] + mirroredOrigin(oy) - oy];
20564
+ m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5]];
20544
20565
  }
20545
20566
  const inv2 = invert2(m);
20546
20567
  if (!inv2) {
@@ -23353,6 +23374,21 @@ var nestedReplayer = null;
23353
23374
  function registerNestedMetafileReplayer(fn) {
23354
23375
  nestedReplayer = fn;
23355
23376
  }
23377
+ function inclusiveNestedMapping(toDevice, srcX, srcY, srcW, srcH) {
23378
+ const [a, b, c, d, e, f] = toDevice;
23379
+ const lengthU = Math.hypot(a, b) * srcW;
23380
+ const lengthV = Math.hypot(c, d) * srcH;
23381
+ if (!(srcW > 1 && srcH > 1 && lengthU > 1 && lengthV > 1)) {
23382
+ return toDevice;
23383
+ }
23384
+ const ku = (lengthU - 1) / lengthU * (srcW / (srcW - 1));
23385
+ const kv = (lengthV - 1) / lengthV * (srcH / (srcH - 1));
23386
+ const na = a * ku;
23387
+ const nb = b * ku;
23388
+ const nc = c * kv;
23389
+ const nd = d * kv;
23390
+ return [na, nb, nc, nd, e + (a - na) * srcX + (c - nc) * srcY, f + (b - nb) * srcX + (d - nd) * srcY];
23391
+ }
23356
23392
  function drawNestedMetafile(rCtx, img, cached, source) {
23357
23393
  const depth = rCtx.nestingDepth ?? 0;
23358
23394
  if (!nestedReplayer || !source || !img.data || source.unit !== UNIT_PIXEL || depth >= MAX_NESTED_METAFILE_DEPTH) {
@@ -23366,9 +23402,12 @@ function drawNestedMetafile(rCtx, img, cached, source) {
23366
23402
  if (!size) {
23367
23403
  return false;
23368
23404
  }
23369
- const toCanvas = mulMatrix(
23370
- [1, 0, 0, 1, -0.5, -0.5],
23371
- mulMatrix(mulMatrix(plusWorldMatrix(rCtx), source.toWorld(srcX, srcY, srcW, srcH)), [1, 0, 0, 1, 0.5, 0.5])
23405
+ const toCanvas = inclusiveNestedMapping(
23406
+ mulMatrix(plusWorldMatrix(rCtx), source.toWorld(srcX, srcY, srcW, srcH)),
23407
+ srcX,
23408
+ srcY,
23409
+ srcW,
23410
+ srcH
23372
23411
  );
23373
23412
  const bytes = img.data.slice(0);
23374
23413
  const caches = cached && cached.kind === "metafile" ? cached.caches : void 0;
@@ -29187,9 +29226,9 @@ function perpendicularVectors(width, dx0, dy0) {
29187
29226
  const vx = rounded[0], vy = rounded[1];
29188
29227
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29189
29228
  }
29190
- function squareExtension(width, dx, dy) {
29229
+ function squareExtension(width, dx, dy, scale = 1) {
29191
29230
  const len = Math.hypot(dx, dy);
29192
- const r = width / 2;
29231
+ const r = width / 2 * scale;
29193
29232
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
29194
29233
  }
29195
29234
  function turnSign(ax, ay, bx, by) {
@@ -29228,7 +29267,7 @@ var Outliner = class {
29228
29267
  const [L, R] = drawVertices(this.pen, d[0], d[1]);
29229
29268
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29230
29269
  const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1]);
29231
- 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 };
29270
+ 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 };
29232
29271
  }
29233
29272
  push(p, v) {
29234
29273
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29323,7 +29362,7 @@ var Outliner = class {
29323
29362
  return side === "R" ? s.v : [-s.v[0], -s.v[1]];
29324
29363
  }
29325
29364
  /** A cap at `p` from the `from` side of `s` round to the other side (`start`: around the back). */
29326
- cap(p, s, start) {
29365
+ cap(p, s, start, scale = 1) {
29327
29366
  const from = start ? "L" : "R";
29328
29367
  const to = start ? "R" : "L";
29329
29368
  const { cap } = this.opts;
@@ -29341,7 +29380,8 @@ var Outliner = class {
29341
29380
  const sv = this.capSide(s, from);
29342
29381
  const ev = this.capSide(s, to);
29343
29382
  if (cap === "square") {
29344
- const e = start ? [-s.e[0], -s.e[1]] : s.e;
29383
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale);
29384
+ const e = start ? [-e0[0], -e0[1]] : e0;
29345
29385
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29346
29386
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
29347
29387
  } else {
@@ -29437,7 +29477,7 @@ var Outliner = class {
29437
29477
  * lets a single point stand for a zero-length dash along `dirs[0]`;
29438
29478
  * `draws` (curve end tangents) picks draw vertices only.
29439
29479
  */
29440
- open(P, dirs, draws, curves) {
29480
+ open(P, dirs, draws, curves, startScale = 1, endScale = 1) {
29441
29481
  if (P.length < 2 && !dirs?.[0]) {
29442
29482
  this.dot(P[0]);
29443
29483
  return;
@@ -29448,12 +29488,12 @@ var Outliner = class {
29448
29488
  }
29449
29489
  if (segs2.length === 0) {
29450
29490
  const s = this.seg(P[0], P[0], dirs?.[0], draws?.[0], curves?.[0]);
29451
- this.cap(P[0], s, true);
29452
- this.cap(P[0], s, false);
29491
+ this.cap(P[0], s, true, startScale);
29492
+ this.cap(P[0], s, false, endScale);
29453
29493
  this.flush();
29454
29494
  return;
29455
29495
  }
29456
- this.cap(P[0], segs2[0], true);
29496
+ this.cap(P[0], segs2[0], true, startScale);
29457
29497
  for (let i = 0; i + 1 < segs2.length; i++) {
29458
29498
  const s = segs2[i];
29459
29499
  const t = segs2[i + 1];
@@ -29464,7 +29504,7 @@ var Outliner = class {
29464
29504
  this.join(P[i + 1], s, t, "R", tr < 0);
29465
29505
  }
29466
29506
  }
29467
- this.cap(P[P.length - 1], segs2[segs2.length - 1], false);
29507
+ this.cap(P[P.length - 1], segs2[segs2.length - 1], false, endScale);
29468
29508
  for (let i = segs2.length - 1; i > 0; i--) {
29469
29509
  const s = segs2[i];
29470
29510
  const t = segs2[i - 1];
@@ -29520,7 +29560,7 @@ var Outliner = class {
29520
29560
  this.flush();
29521
29561
  }
29522
29562
  };
29523
- function dashPieces(P, tangents, pattern, shorten) {
29563
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29524
29564
  const out = [];
29525
29565
  const dashes = [];
29526
29566
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29535,12 +29575,22 @@ function dashPieces(P, tangents, pattern, shorten) {
29535
29575
  let idx = 0;
29536
29576
  let left = dashes[0];
29537
29577
  let on = true;
29538
- let cur = { pts: [P[0]], dirs: [], draws: [] };
29578
+ let cur = { pts: [P[0]], dirs: [], draws: [], curves: [], startScale: 1, endScale: 1 };
29539
29579
  for (let i = 0; i + 1 < P.length; i++) {
29540
29580
  const [x0, y0] = P[i];
29541
29581
  const [x1, y1] = P[i + 1];
29542
29582
  const dir = [x1 - x0, y1 - y0];
29543
- const len = Math.hypot(dir[0], dir[1]);
29583
+ const real = Math.hypot(dir[0], dir[1]);
29584
+ const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29585
+ if (len === 0) {
29586
+ if (on && cur) {
29587
+ cur.pts.push(P[i + 1]);
29588
+ cur.dirs.push(dir);
29589
+ cur.draws.push(tangents[i]);
29590
+ cur.curves.push(curveFlags[i]);
29591
+ }
29592
+ continue;
29593
+ }
29544
29594
  let t = 0;
29545
29595
  while (len - t > left || left === 0 && on) {
29546
29596
  t += left;
@@ -29549,10 +29599,12 @@ function dashPieces(P, tangents, pattern, shorten) {
29549
29599
  cur.pts.push(q);
29550
29600
  cur.dirs.push(dir);
29551
29601
  cur.draws.push(tangents[i]);
29602
+ cur.curves.push(curveFlags[i]);
29603
+ cur.endScale = cur.pts[0] === P[0] && q[0] === P[0][0] && q[1] === P[0][1] ? 1 : real / len;
29552
29604
  out.push(cur);
29553
29605
  cur = null;
29554
29606
  } else {
29555
- cur = { pts: [q], dirs: [], draws: [] };
29607
+ cur = { pts: [q], dirs: [], draws: [], curves: [], startScale: real / len, endScale: 1 };
29556
29608
  }
29557
29609
  on = !on;
29558
29610
  idx = (idx + 1) % dashes.length;
@@ -29563,9 +29615,12 @@ function dashPieces(P, tangents, pattern, shorten) {
29563
29615
  cur.pts.push(P[i + 1]);
29564
29616
  cur.dirs.push(dir);
29565
29617
  cur.draws.push(tangents[i]);
29618
+ cur.curves.push(curveFlags[i]);
29619
+ cur.endScale = real / len;
29566
29620
  }
29567
29621
  }
29568
29622
  if (on && cur && cur.dirs.length > 0) {
29623
+ cur.endScale = 1;
29569
29624
  out.push(cur);
29570
29625
  }
29571
29626
  return out;
@@ -29600,10 +29655,13 @@ function widenPath(path, opts) {
29600
29655
  if (dashed) {
29601
29656
  const run = closed ? [...P, P[0]] : P;
29602
29657
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29603
- for (const piece of dashPieces(run, closed ? [...dirs, void 0] : dirs, opts.dashes, shorten)) {
29658
+ const runTangents = closed ? [...dirs, void 0] : dirs;
29659
+ const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29660
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29604
29661
  const pts = [piece.pts[0]];
29605
29662
  const pdirs = [];
29606
29663
  const pdraws = [];
29664
+ const pcurves = [];
29607
29665
  for (let i = 1; i < piece.pts.length; i++) {
29608
29666
  const q = piece.pts[i];
29609
29667
  const last = pts[pts.length - 1];
@@ -29611,9 +29669,10 @@ function widenPath(path, opts) {
29611
29669
  pts.push(q);
29612
29670
  pdirs.push(piece.dirs[i - 1]);
29613
29671
  pdraws.push(piece.draws[i - 1]);
29672
+ pcurves.push(piece.curves[i - 1]);
29614
29673
  }
29615
29674
  }
29616
- outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]], pts.map(() => !!fig.roundWiden));
29675
+ 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);
29617
29676
  }
29618
29677
  } else if (closed && P.length >= 3) {
29619
29678
  outliner.closed(P, dirs, curves);
@@ -29821,7 +29880,10 @@ function penWidenOptions(rCtx, opts = {}) {
29821
29880
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
29822
29881
  miterLimit: state.miterLimit ?? 10,
29823
29882
  dashes: dashes ? dashes.map((v) => v * 16) : null,
29824
- shortenDashes: (flags & 15) !== 7
29883
+ shortenDashes: (flags & 15) !== 7,
29884
+ // One logical unit per device pixel, unrotated: GDI measures dash
29885
+ // segments in whole pixels.
29886
+ 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
29825
29887
  };
29826
29888
  }
29827
29889
  function hatchBackgroundMask(hatch) {