emf-converter 4.6.7 → 4.6.8

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
@@ -31460,28 +31460,92 @@ function halftoneAxis(start, srcLen, dstLen, reverse) {
31460
31460
  if (reverse) taps.reverse();
31461
31461
  return taps;
31462
31462
  }
31463
- var SOFT_TENT_SIGMA = 0.25;
31464
- var SOFT_TENT_STEPS = 31;
31465
- var SOFT_TENT_SPAN = 3;
31466
- var softTentCache = /* @__PURE__ */ new Map();
31467
- function softTent(d) {
31468
- const key = Math.round(d * 1024);
31469
- const cached = softTentCache.get(key);
31470
- if (cached !== void 0) {
31471
- return cached;
31463
+ function halftoneReduceTaps(srcLen, dstLen, reverse) {
31464
+ if (dstLen >= srcLen) return halftoneAxis(0, srcLen, dstLen, reverse);
31465
+ const taps = [];
31466
+ for (let i = 0; i < dstLen; i++) {
31467
+ const from = i * srcLen;
31468
+ const to = (i + 1) * srcLen;
31469
+ const run = [];
31470
+ let rest = 0;
31471
+ for (let k = Math.floor(from / dstLen); k * dstLen < to; k++) {
31472
+ const overlap = Math.min(to, (k + 1) * dstLen) - Math.max(from, k * dstLen);
31473
+ if (overlap <= 0) continue;
31474
+ const w = Math.ceil(overlap * FIX / srcLen);
31475
+ run.push([k, w]);
31476
+ if (run.length > 1) rest += w;
31477
+ }
31478
+ if (run.length > 1) run[0][1] = FIX - rest;
31479
+ taps.push(run);
31472
31480
  }
31473
- let sum = 0;
31481
+ if (reverse) taps.reverse();
31482
+ return taps;
31483
+ }
31484
+ var ENLARGE_KERNEL = [
31485
+ 0.7598,
31486
+ 0.7276,
31487
+ 0.6829,
31488
+ 0.6528,
31489
+ 0.6106,
31490
+ 0.5745,
31491
+ 0.5362,
31492
+ 0.4955,
31493
+ 0.457,
31494
+ 0.4121,
31495
+ 0.3762,
31496
+ 0.3233,
31497
+ 0.2741,
31498
+ 0.226,
31499
+ 0.1822,
31500
+ 0.1412,
31501
+ 0.1021,
31502
+ 0.0685,
31503
+ 0.0382,
31504
+ 0.0138,
31505
+ 0
31506
+ ];
31507
+ var ENLARGE_BOX = 0.2429;
31508
+ var ENLARGE_STEP = 0.05;
31509
+ function enlargeKernel(u) {
31510
+ const edge = u / ENLARGE_STEP;
31511
+ const i = Math.floor(edge);
31512
+ const smooth = i >= ENLARGE_KERNEL.length - 1 ? 0 : ENLARGE_KERNEL[i] + (ENLARGE_KERNEL[i + 1] - ENLARGE_KERNEL[i]) * (edge - i);
31513
+ return smooth + ENLARGE_BOX * (Math.abs(u - 0.5) < 1e-9 ? 0.5 : u < 0.5 ? 1 : 0);
31514
+ }
31515
+ function halftoneEnlargeTaps(src, dst) {
31516
+ const ratio = dst / src;
31517
+ const reach = Math.ceil((ENLARGE_KERNEL.length - 1) * ENLARGE_STEP * ratio);
31518
+ const fir = [];
31474
31519
  let total = 0;
31475
- const half = (SOFT_TENT_STEPS - 1) / 2;
31476
- for (let i = -half; i <= half; i++) {
31477
- const x = i / half * SOFT_TENT_SPAN * SOFT_TENT_SIGMA;
31478
- const g = Math.exp(-(x * x) / (2 * SOFT_TENT_SIGMA * SOFT_TENT_SIGMA));
31479
- total += g;
31480
- sum += g * Math.max(0, 1 - Math.abs(key / 1024 + x));
31520
+ for (let k = 0; k <= reach; k++) {
31521
+ const w = enlargeKernel(k / ratio);
31522
+ fir.push(w);
31523
+ total += k === 0 ? w : 2 * w;
31524
+ }
31525
+ const cover = [];
31526
+ for (let x = 0; x < dst; x++) {
31527
+ const lo = x / ratio;
31528
+ const hi = (x + 1) / ratio;
31529
+ const run = [];
31530
+ for (let j = Math.max(0, Math.floor(lo)); j < Math.min(src, hi); j++) {
31531
+ const overlap = Math.min(hi, j + 1) - Math.max(lo, j);
31532
+ if (overlap > 0) run.push([j, overlap * ratio]);
31533
+ }
31534
+ cover.push(run);
31481
31535
  }
31482
- const value = sum / total;
31483
- softTentCache.set(key, value);
31484
- return value;
31536
+ const taps = [];
31537
+ for (let x = 0; x < dst; x++) {
31538
+ const weights = /* @__PURE__ */ new Map();
31539
+ for (let k = -reach; k <= reach; k++) {
31540
+ const w = fir[Math.abs(k)] / total;
31541
+ if (w === 0) continue;
31542
+ for (const [j, v] of cover[Math.max(0, Math.min(dst - 1, x + k))]) {
31543
+ weights.set(j, (weights.get(j) ?? 0) + w * v);
31544
+ }
31545
+ }
31546
+ taps.push([...weights.entries()]);
31547
+ }
31548
+ return taps;
31485
31549
  }
31486
31550
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
31487
31551
  for (let y = 0; y < h; y++) {
@@ -31623,7 +31687,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31623
31687
  const mixed = W > SW && H < SH || W < SW && H > SH;
31624
31688
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
31625
31689
  const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
31626
- const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && Math.min(SW, W) >= 2 && Math.min(SH, H) >= 2 && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31690
+ const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31627
31691
  if ((enlarging || nearestMixed) && !directDib) {
31628
31692
  halftoneDespeckle(rect, SW, SH);
31629
31693
  }
@@ -31637,8 +31701,9 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31637
31701
  }
31638
31702
  const sampleW = nativeMixed ? Math.min(SW, W) : W;
31639
31703
  const sampleH = nativeMixed ? Math.min(SH, H) : H;
31640
- const cols = halftoneAxis(0, SW, sampleW, flipX);
31641
- const rows = halftoneAxis(0, SH, sampleH, flipY);
31704
+ const axis = nativeMixed ? (n, d, r) => halftoneReduceTaps(n, d, r) : (n, d, r) => halftoneAxis(0, n, d, r);
31705
+ const cols = axis(SW, sampleW, flipX);
31706
+ const rows = axis(SH, sampleH, flipY);
31642
31707
  if (nearestMixed) {
31643
31708
  const nearest = (taps, src2, dst, reverse) => {
31644
31709
  for (let i = 0; i < dst; i++) {
@@ -31710,29 +31775,15 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31710
31775
  const source = out;
31711
31776
  out = new Int32Array(W * H * 3);
31712
31777
  const axisTaps = (src2, dst) => {
31713
- const r = [];
31714
- for (let i = 0; i < dst; i++) {
31715
- if (src2 === dst) {
31716
- r.push([[i, 1]]);
31717
- continue;
31718
- }
31719
- const raw = (i + 0.5) * src2 / dst - 0.5;
31720
- const pos = Math.max(0, Math.min(src2 - 1, raw));
31721
- const i0 = Math.floor(pos);
31722
- if (dst === 2 * src2) {
31723
- r.push([[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]]);
31724
- continue;
31725
- }
31726
- const taps = [];
31727
- let total = 0;
31728
- for (let k = i0 - 2; k <= i0 + 3; k++) {
31729
- const w = softTent(raw - k);
31730
- taps.push([Math.max(0, Math.min(src2 - 1, k)), w]);
31731
- total += w;
31732
- }
31733
- r.push(taps.map(([k, w]) => [k, w / total]));
31778
+ if (src2 === dst) return Array.from({ length: dst }, (_, i) => [[i, 1]]);
31779
+ if (dst === 2 * src2) {
31780
+ return Array.from({ length: dst }, (_, i) => {
31781
+ const pos = Math.max(0, Math.min(src2 - 1, (i + 0.5) * src2 / dst - 0.5));
31782
+ const i0 = Math.floor(pos);
31783
+ return [[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]];
31784
+ });
31734
31785
  }
31735
- return r;
31786
+ return halftoneEnlargeTaps(src2, dst);
31736
31787
  };
31737
31788
  const xt = axisTaps(sampleW, W), yt = axisTaps(sampleH, H);
31738
31789
  for (let y = 0; y < H; y++) {
@@ -31740,7 +31791,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31740
31791
  for (let c = 0; c < 3; c++) {
31741
31792
  let v = 0;
31742
31793
  for (const [yy, wy] of yt[y]) for (const [xx, wx] of xt[x]) v += source[(yy * sampleW + xx) * 3 + c] * wy * wx;
31743
- out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5)));
31794
+ out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5 + 1e-7)));
31744
31795
  }
31745
31796
  }
31746
31797
  }
package/dist/browser.mjs CHANGED
@@ -31458,28 +31458,92 @@ function halftoneAxis(start, srcLen, dstLen, reverse) {
31458
31458
  if (reverse) taps.reverse();
31459
31459
  return taps;
31460
31460
  }
31461
- var SOFT_TENT_SIGMA = 0.25;
31462
- var SOFT_TENT_STEPS = 31;
31463
- var SOFT_TENT_SPAN = 3;
31464
- var softTentCache = /* @__PURE__ */ new Map();
31465
- function softTent(d) {
31466
- const key = Math.round(d * 1024);
31467
- const cached = softTentCache.get(key);
31468
- if (cached !== void 0) {
31469
- return cached;
31461
+ function halftoneReduceTaps(srcLen, dstLen, reverse) {
31462
+ if (dstLen >= srcLen) return halftoneAxis(0, srcLen, dstLen, reverse);
31463
+ const taps = [];
31464
+ for (let i = 0; i < dstLen; i++) {
31465
+ const from = i * srcLen;
31466
+ const to = (i + 1) * srcLen;
31467
+ const run = [];
31468
+ let rest = 0;
31469
+ for (let k = Math.floor(from / dstLen); k * dstLen < to; k++) {
31470
+ const overlap = Math.min(to, (k + 1) * dstLen) - Math.max(from, k * dstLen);
31471
+ if (overlap <= 0) continue;
31472
+ const w = Math.ceil(overlap * FIX / srcLen);
31473
+ run.push([k, w]);
31474
+ if (run.length > 1) rest += w;
31475
+ }
31476
+ if (run.length > 1) run[0][1] = FIX - rest;
31477
+ taps.push(run);
31470
31478
  }
31471
- let sum = 0;
31479
+ if (reverse) taps.reverse();
31480
+ return taps;
31481
+ }
31482
+ var ENLARGE_KERNEL = [
31483
+ 0.7598,
31484
+ 0.7276,
31485
+ 0.6829,
31486
+ 0.6528,
31487
+ 0.6106,
31488
+ 0.5745,
31489
+ 0.5362,
31490
+ 0.4955,
31491
+ 0.457,
31492
+ 0.4121,
31493
+ 0.3762,
31494
+ 0.3233,
31495
+ 0.2741,
31496
+ 0.226,
31497
+ 0.1822,
31498
+ 0.1412,
31499
+ 0.1021,
31500
+ 0.0685,
31501
+ 0.0382,
31502
+ 0.0138,
31503
+ 0
31504
+ ];
31505
+ var ENLARGE_BOX = 0.2429;
31506
+ var ENLARGE_STEP = 0.05;
31507
+ function enlargeKernel(u) {
31508
+ const edge = u / ENLARGE_STEP;
31509
+ const i = Math.floor(edge);
31510
+ const smooth = i >= ENLARGE_KERNEL.length - 1 ? 0 : ENLARGE_KERNEL[i] + (ENLARGE_KERNEL[i + 1] - ENLARGE_KERNEL[i]) * (edge - i);
31511
+ return smooth + ENLARGE_BOX * (Math.abs(u - 0.5) < 1e-9 ? 0.5 : u < 0.5 ? 1 : 0);
31512
+ }
31513
+ function halftoneEnlargeTaps(src, dst) {
31514
+ const ratio = dst / src;
31515
+ const reach = Math.ceil((ENLARGE_KERNEL.length - 1) * ENLARGE_STEP * ratio);
31516
+ const fir = [];
31472
31517
  let total = 0;
31473
- const half = (SOFT_TENT_STEPS - 1) / 2;
31474
- for (let i = -half; i <= half; i++) {
31475
- const x = i / half * SOFT_TENT_SPAN * SOFT_TENT_SIGMA;
31476
- const g = Math.exp(-(x * x) / (2 * SOFT_TENT_SIGMA * SOFT_TENT_SIGMA));
31477
- total += g;
31478
- sum += g * Math.max(0, 1 - Math.abs(key / 1024 + x));
31518
+ for (let k = 0; k <= reach; k++) {
31519
+ const w = enlargeKernel(k / ratio);
31520
+ fir.push(w);
31521
+ total += k === 0 ? w : 2 * w;
31522
+ }
31523
+ const cover = [];
31524
+ for (let x = 0; x < dst; x++) {
31525
+ const lo = x / ratio;
31526
+ const hi = (x + 1) / ratio;
31527
+ const run = [];
31528
+ for (let j = Math.max(0, Math.floor(lo)); j < Math.min(src, hi); j++) {
31529
+ const overlap = Math.min(hi, j + 1) - Math.max(lo, j);
31530
+ if (overlap > 0) run.push([j, overlap * ratio]);
31531
+ }
31532
+ cover.push(run);
31479
31533
  }
31480
- const value = sum / total;
31481
- softTentCache.set(key, value);
31482
- return value;
31534
+ const taps = [];
31535
+ for (let x = 0; x < dst; x++) {
31536
+ const weights = /* @__PURE__ */ new Map();
31537
+ for (let k = -reach; k <= reach; k++) {
31538
+ const w = fir[Math.abs(k)] / total;
31539
+ if (w === 0) continue;
31540
+ for (const [j, v] of cover[Math.max(0, Math.min(dst - 1, x + k))]) {
31541
+ weights.set(j, (weights.get(j) ?? 0) + w * v);
31542
+ }
31543
+ }
31544
+ taps.push([...weights.entries()]);
31545
+ }
31546
+ return taps;
31483
31547
  }
31484
31548
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
31485
31549
  for (let y = 0; y < h; y++) {
@@ -31621,7 +31685,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31621
31685
  const mixed = W > SW && H < SH || W < SW && H > SH;
31622
31686
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
31623
31687
  const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
31624
- const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && Math.min(SW, W) >= 2 && Math.min(SH, H) >= 2 && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31688
+ const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31625
31689
  if ((enlarging || nearestMixed) && !directDib) {
31626
31690
  halftoneDespeckle(rect, SW, SH);
31627
31691
  }
@@ -31635,8 +31699,9 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31635
31699
  }
31636
31700
  const sampleW = nativeMixed ? Math.min(SW, W) : W;
31637
31701
  const sampleH = nativeMixed ? Math.min(SH, H) : H;
31638
- const cols = halftoneAxis(0, SW, sampleW, flipX);
31639
- const rows = halftoneAxis(0, SH, sampleH, flipY);
31702
+ const axis = nativeMixed ? (n, d, r) => halftoneReduceTaps(n, d, r) : (n, d, r) => halftoneAxis(0, n, d, r);
31703
+ const cols = axis(SW, sampleW, flipX);
31704
+ const rows = axis(SH, sampleH, flipY);
31640
31705
  if (nearestMixed) {
31641
31706
  const nearest = (taps, src2, dst, reverse) => {
31642
31707
  for (let i = 0; i < dst; i++) {
@@ -31708,29 +31773,15 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31708
31773
  const source = out;
31709
31774
  out = new Int32Array(W * H * 3);
31710
31775
  const axisTaps = (src2, dst) => {
31711
- const r = [];
31712
- for (let i = 0; i < dst; i++) {
31713
- if (src2 === dst) {
31714
- r.push([[i, 1]]);
31715
- continue;
31716
- }
31717
- const raw = (i + 0.5) * src2 / dst - 0.5;
31718
- const pos = Math.max(0, Math.min(src2 - 1, raw));
31719
- const i0 = Math.floor(pos);
31720
- if (dst === 2 * src2) {
31721
- r.push([[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]]);
31722
- continue;
31723
- }
31724
- const taps = [];
31725
- let total = 0;
31726
- for (let k = i0 - 2; k <= i0 + 3; k++) {
31727
- const w = softTent(raw - k);
31728
- taps.push([Math.max(0, Math.min(src2 - 1, k)), w]);
31729
- total += w;
31730
- }
31731
- r.push(taps.map(([k, w]) => [k, w / total]));
31776
+ if (src2 === dst) return Array.from({ length: dst }, (_, i) => [[i, 1]]);
31777
+ if (dst === 2 * src2) {
31778
+ return Array.from({ length: dst }, (_, i) => {
31779
+ const pos = Math.max(0, Math.min(src2 - 1, (i + 0.5) * src2 / dst - 0.5));
31780
+ const i0 = Math.floor(pos);
31781
+ return [[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]];
31782
+ });
31732
31783
  }
31733
- return r;
31784
+ return halftoneEnlargeTaps(src2, dst);
31734
31785
  };
31735
31786
  const xt = axisTaps(sampleW, W), yt = axisTaps(sampleH, H);
31736
31787
  for (let y = 0; y < H; y++) {
@@ -31738,7 +31789,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31738
31789
  for (let c = 0; c < 3; c++) {
31739
31790
  let v = 0;
31740
31791
  for (const [yy, wy] of yt[y]) for (const [xx, wx] of xt[x]) v += source[(yy * sampleW + xx) * 3 + c] * wy * wx;
31741
- out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5)));
31792
+ out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5 + 1e-7)));
31742
31793
  }
31743
31794
  }
31744
31795
  }
package/dist/index.js CHANGED
@@ -31461,28 +31461,92 @@ function halftoneAxis(start, srcLen, dstLen, reverse) {
31461
31461
  if (reverse) taps.reverse();
31462
31462
  return taps;
31463
31463
  }
31464
- var SOFT_TENT_SIGMA = 0.25;
31465
- var SOFT_TENT_STEPS = 31;
31466
- var SOFT_TENT_SPAN = 3;
31467
- var softTentCache = /* @__PURE__ */ new Map();
31468
- function softTent(d) {
31469
- const key = Math.round(d * 1024);
31470
- const cached = softTentCache.get(key);
31471
- if (cached !== void 0) {
31472
- return cached;
31464
+ function halftoneReduceTaps(srcLen, dstLen, reverse) {
31465
+ if (dstLen >= srcLen) return halftoneAxis(0, srcLen, dstLen, reverse);
31466
+ const taps = [];
31467
+ for (let i = 0; i < dstLen; i++) {
31468
+ const from = i * srcLen;
31469
+ const to = (i + 1) * srcLen;
31470
+ const run = [];
31471
+ let rest = 0;
31472
+ for (let k = Math.floor(from / dstLen); k * dstLen < to; k++) {
31473
+ const overlap = Math.min(to, (k + 1) * dstLen) - Math.max(from, k * dstLen);
31474
+ if (overlap <= 0) continue;
31475
+ const w = Math.ceil(overlap * FIX / srcLen);
31476
+ run.push([k, w]);
31477
+ if (run.length > 1) rest += w;
31478
+ }
31479
+ if (run.length > 1) run[0][1] = FIX - rest;
31480
+ taps.push(run);
31473
31481
  }
31474
- let sum = 0;
31482
+ if (reverse) taps.reverse();
31483
+ return taps;
31484
+ }
31485
+ var ENLARGE_KERNEL = [
31486
+ 0.7598,
31487
+ 0.7276,
31488
+ 0.6829,
31489
+ 0.6528,
31490
+ 0.6106,
31491
+ 0.5745,
31492
+ 0.5362,
31493
+ 0.4955,
31494
+ 0.457,
31495
+ 0.4121,
31496
+ 0.3762,
31497
+ 0.3233,
31498
+ 0.2741,
31499
+ 0.226,
31500
+ 0.1822,
31501
+ 0.1412,
31502
+ 0.1021,
31503
+ 0.0685,
31504
+ 0.0382,
31505
+ 0.0138,
31506
+ 0
31507
+ ];
31508
+ var ENLARGE_BOX = 0.2429;
31509
+ var ENLARGE_STEP = 0.05;
31510
+ function enlargeKernel(u) {
31511
+ const edge = u / ENLARGE_STEP;
31512
+ const i = Math.floor(edge);
31513
+ const smooth = i >= ENLARGE_KERNEL.length - 1 ? 0 : ENLARGE_KERNEL[i] + (ENLARGE_KERNEL[i + 1] - ENLARGE_KERNEL[i]) * (edge - i);
31514
+ return smooth + ENLARGE_BOX * (Math.abs(u - 0.5) < 1e-9 ? 0.5 : u < 0.5 ? 1 : 0);
31515
+ }
31516
+ function halftoneEnlargeTaps(src, dst) {
31517
+ const ratio = dst / src;
31518
+ const reach = Math.ceil((ENLARGE_KERNEL.length - 1) * ENLARGE_STEP * ratio);
31519
+ const fir = [];
31475
31520
  let total = 0;
31476
- const half = (SOFT_TENT_STEPS - 1) / 2;
31477
- for (let i = -half; i <= half; i++) {
31478
- const x = i / half * SOFT_TENT_SPAN * SOFT_TENT_SIGMA;
31479
- const g = Math.exp(-(x * x) / (2 * SOFT_TENT_SIGMA * SOFT_TENT_SIGMA));
31480
- total += g;
31481
- sum += g * Math.max(0, 1 - Math.abs(key / 1024 + x));
31521
+ for (let k = 0; k <= reach; k++) {
31522
+ const w = enlargeKernel(k / ratio);
31523
+ fir.push(w);
31524
+ total += k === 0 ? w : 2 * w;
31525
+ }
31526
+ const cover = [];
31527
+ for (let x = 0; x < dst; x++) {
31528
+ const lo = x / ratio;
31529
+ const hi = (x + 1) / ratio;
31530
+ const run = [];
31531
+ for (let j = Math.max(0, Math.floor(lo)); j < Math.min(src, hi); j++) {
31532
+ const overlap = Math.min(hi, j + 1) - Math.max(lo, j);
31533
+ if (overlap > 0) run.push([j, overlap * ratio]);
31534
+ }
31535
+ cover.push(run);
31482
31536
  }
31483
- const value = sum / total;
31484
- softTentCache.set(key, value);
31485
- return value;
31537
+ const taps = [];
31538
+ for (let x = 0; x < dst; x++) {
31539
+ const weights = /* @__PURE__ */ new Map();
31540
+ for (let k = -reach; k <= reach; k++) {
31541
+ const w = fir[Math.abs(k)] / total;
31542
+ if (w === 0) continue;
31543
+ for (const [j, v] of cover[Math.max(0, Math.min(dst - 1, x + k))]) {
31544
+ weights.set(j, (weights.get(j) ?? 0) + w * v);
31545
+ }
31546
+ }
31547
+ taps.push([...weights.entries()]);
31548
+ }
31549
+ return taps;
31486
31550
  }
31487
31551
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
31488
31552
  for (let y = 0; y < h; y++) {
@@ -31624,7 +31688,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31624
31688
  const mixed = W > SW && H < SH || W < SW && H > SH;
31625
31689
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
31626
31690
  const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
31627
- const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && Math.min(SW, W) >= 2 && Math.min(SH, H) >= 2 && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31691
+ const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31628
31692
  if ((enlarging || nearestMixed) && !directDib) {
31629
31693
  halftoneDespeckle(rect, SW, SH);
31630
31694
  }
@@ -31638,8 +31702,9 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31638
31702
  }
31639
31703
  const sampleW = nativeMixed ? Math.min(SW, W) : W;
31640
31704
  const sampleH = nativeMixed ? Math.min(SH, H) : H;
31641
- const cols = halftoneAxis(0, SW, sampleW, flipX);
31642
- const rows = halftoneAxis(0, SH, sampleH, flipY);
31705
+ const axis = nativeMixed ? (n, d, r) => halftoneReduceTaps(n, d, r) : (n, d, r) => halftoneAxis(0, n, d, r);
31706
+ const cols = axis(SW, sampleW, flipX);
31707
+ const rows = axis(SH, sampleH, flipY);
31643
31708
  if (nearestMixed) {
31644
31709
  const nearest = (taps, src2, dst, reverse) => {
31645
31710
  for (let i = 0; i < dst; i++) {
@@ -31711,29 +31776,15 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31711
31776
  const source = out;
31712
31777
  out = new Int32Array(W * H * 3);
31713
31778
  const axisTaps = (src2, dst) => {
31714
- const r = [];
31715
- for (let i = 0; i < dst; i++) {
31716
- if (src2 === dst) {
31717
- r.push([[i, 1]]);
31718
- continue;
31719
- }
31720
- const raw = (i + 0.5) * src2 / dst - 0.5;
31721
- const pos = Math.max(0, Math.min(src2 - 1, raw));
31722
- const i0 = Math.floor(pos);
31723
- if (dst === 2 * src2) {
31724
- r.push([[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]]);
31725
- continue;
31726
- }
31727
- const taps = [];
31728
- let total = 0;
31729
- for (let k = i0 - 2; k <= i0 + 3; k++) {
31730
- const w = softTent(raw - k);
31731
- taps.push([Math.max(0, Math.min(src2 - 1, k)), w]);
31732
- total += w;
31733
- }
31734
- r.push(taps.map(([k, w]) => [k, w / total]));
31779
+ if (src2 === dst) return Array.from({ length: dst }, (_, i) => [[i, 1]]);
31780
+ if (dst === 2 * src2) {
31781
+ return Array.from({ length: dst }, (_, i) => {
31782
+ const pos = Math.max(0, Math.min(src2 - 1, (i + 0.5) * src2 / dst - 0.5));
31783
+ const i0 = Math.floor(pos);
31784
+ return [[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]];
31785
+ });
31735
31786
  }
31736
- return r;
31787
+ return halftoneEnlargeTaps(src2, dst);
31737
31788
  };
31738
31789
  const xt = axisTaps(sampleW, W), yt = axisTaps(sampleH, H);
31739
31790
  for (let y = 0; y < H; y++) {
@@ -31741,7 +31792,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31741
31792
  for (let c = 0; c < 3; c++) {
31742
31793
  let v = 0;
31743
31794
  for (const [yy, wy] of yt[y]) for (const [xx, wx] of xt[x]) v += source[(yy * sampleW + xx) * 3 + c] * wy * wx;
31744
- out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5)));
31795
+ out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5 + 1e-7)));
31745
31796
  }
31746
31797
  }
31747
31798
  }
package/dist/index.mjs CHANGED
@@ -31459,28 +31459,92 @@ function halftoneAxis(start, srcLen, dstLen, reverse) {
31459
31459
  if (reverse) taps.reverse();
31460
31460
  return taps;
31461
31461
  }
31462
- var SOFT_TENT_SIGMA = 0.25;
31463
- var SOFT_TENT_STEPS = 31;
31464
- var SOFT_TENT_SPAN = 3;
31465
- var softTentCache = /* @__PURE__ */ new Map();
31466
- function softTent(d) {
31467
- const key = Math.round(d * 1024);
31468
- const cached = softTentCache.get(key);
31469
- if (cached !== void 0) {
31470
- return cached;
31462
+ function halftoneReduceTaps(srcLen, dstLen, reverse) {
31463
+ if (dstLen >= srcLen) return halftoneAxis(0, srcLen, dstLen, reverse);
31464
+ const taps = [];
31465
+ for (let i = 0; i < dstLen; i++) {
31466
+ const from = i * srcLen;
31467
+ const to = (i + 1) * srcLen;
31468
+ const run = [];
31469
+ let rest = 0;
31470
+ for (let k = Math.floor(from / dstLen); k * dstLen < to; k++) {
31471
+ const overlap = Math.min(to, (k + 1) * dstLen) - Math.max(from, k * dstLen);
31472
+ if (overlap <= 0) continue;
31473
+ const w = Math.ceil(overlap * FIX / srcLen);
31474
+ run.push([k, w]);
31475
+ if (run.length > 1) rest += w;
31476
+ }
31477
+ if (run.length > 1) run[0][1] = FIX - rest;
31478
+ taps.push(run);
31471
31479
  }
31472
- let sum = 0;
31480
+ if (reverse) taps.reverse();
31481
+ return taps;
31482
+ }
31483
+ var ENLARGE_KERNEL = [
31484
+ 0.7598,
31485
+ 0.7276,
31486
+ 0.6829,
31487
+ 0.6528,
31488
+ 0.6106,
31489
+ 0.5745,
31490
+ 0.5362,
31491
+ 0.4955,
31492
+ 0.457,
31493
+ 0.4121,
31494
+ 0.3762,
31495
+ 0.3233,
31496
+ 0.2741,
31497
+ 0.226,
31498
+ 0.1822,
31499
+ 0.1412,
31500
+ 0.1021,
31501
+ 0.0685,
31502
+ 0.0382,
31503
+ 0.0138,
31504
+ 0
31505
+ ];
31506
+ var ENLARGE_BOX = 0.2429;
31507
+ var ENLARGE_STEP = 0.05;
31508
+ function enlargeKernel(u) {
31509
+ const edge = u / ENLARGE_STEP;
31510
+ const i = Math.floor(edge);
31511
+ const smooth = i >= ENLARGE_KERNEL.length - 1 ? 0 : ENLARGE_KERNEL[i] + (ENLARGE_KERNEL[i + 1] - ENLARGE_KERNEL[i]) * (edge - i);
31512
+ return smooth + ENLARGE_BOX * (Math.abs(u - 0.5) < 1e-9 ? 0.5 : u < 0.5 ? 1 : 0);
31513
+ }
31514
+ function halftoneEnlargeTaps(src, dst) {
31515
+ const ratio = dst / src;
31516
+ const reach = Math.ceil((ENLARGE_KERNEL.length - 1) * ENLARGE_STEP * ratio);
31517
+ const fir = [];
31473
31518
  let total = 0;
31474
- const half = (SOFT_TENT_STEPS - 1) / 2;
31475
- for (let i = -half; i <= half; i++) {
31476
- const x = i / half * SOFT_TENT_SPAN * SOFT_TENT_SIGMA;
31477
- const g = Math.exp(-(x * x) / (2 * SOFT_TENT_SIGMA * SOFT_TENT_SIGMA));
31478
- total += g;
31479
- sum += g * Math.max(0, 1 - Math.abs(key / 1024 + x));
31519
+ for (let k = 0; k <= reach; k++) {
31520
+ const w = enlargeKernel(k / ratio);
31521
+ fir.push(w);
31522
+ total += k === 0 ? w : 2 * w;
31523
+ }
31524
+ const cover = [];
31525
+ for (let x = 0; x < dst; x++) {
31526
+ const lo = x / ratio;
31527
+ const hi = (x + 1) / ratio;
31528
+ const run = [];
31529
+ for (let j = Math.max(0, Math.floor(lo)); j < Math.min(src, hi); j++) {
31530
+ const overlap = Math.min(hi, j + 1) - Math.max(lo, j);
31531
+ if (overlap > 0) run.push([j, overlap * ratio]);
31532
+ }
31533
+ cover.push(run);
31480
31534
  }
31481
- const value = sum / total;
31482
- softTentCache.set(key, value);
31483
- return value;
31535
+ const taps = [];
31536
+ for (let x = 0; x < dst; x++) {
31537
+ const weights = /* @__PURE__ */ new Map();
31538
+ for (let k = -reach; k <= reach; k++) {
31539
+ const w = fir[Math.abs(k)] / total;
31540
+ if (w === 0) continue;
31541
+ for (const [j, v] of cover[Math.max(0, Math.min(dst - 1, x + k))]) {
31542
+ weights.set(j, (weights.get(j) ?? 0) + w * v);
31543
+ }
31544
+ }
31545
+ taps.push([...weights.entries()]);
31546
+ }
31547
+ return taps;
31484
31548
  }
31485
31549
  function ditherPixels(px, w, h, dither, flipX, flipY, phaseX, phaseY) {
31486
31550
  for (let y = 0; y < h; y++) {
@@ -31622,7 +31686,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31622
31686
  const mixed = W > SW && H < SH || W < SW && H > SH;
31623
31687
  const dithered = !!dither && !!adjust && !adjustAfterSampling;
31624
31688
  const nearestMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W < SW && W * 2 > SW || H < SH && H * 2 > SH);
31625
- const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && Math.min(SW, W) >= 2 && Math.min(SH, H) >= 2 && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31689
+ const nativeMixed = mixed && (!adjust || adjustAfterSampling || dithered) && (W > SW && H * 2 <= SH || H > SH && W * 2 <= SW);
31626
31690
  if ((enlarging || nearestMixed) && !directDib) {
31627
31691
  halftoneDespeckle(rect, SW, SH);
31628
31692
  }
@@ -31636,8 +31700,9 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31636
31700
  }
31637
31701
  const sampleW = nativeMixed ? Math.min(SW, W) : W;
31638
31702
  const sampleH = nativeMixed ? Math.min(SH, H) : H;
31639
- const cols = halftoneAxis(0, SW, sampleW, flipX);
31640
- const rows = halftoneAxis(0, SH, sampleH, flipY);
31703
+ const axis = nativeMixed ? (n, d, r) => halftoneReduceTaps(n, d, r) : (n, d, r) => halftoneAxis(0, n, d, r);
31704
+ const cols = axis(SW, sampleW, flipX);
31705
+ const rows = axis(SH, sampleH, flipY);
31641
31706
  if (nearestMixed) {
31642
31707
  const nearest = (taps, src2, dst, reverse) => {
31643
31708
  for (let i = 0; i < dst; i++) {
@@ -31709,29 +31774,15 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31709
31774
  const source = out;
31710
31775
  out = new Int32Array(W * H * 3);
31711
31776
  const axisTaps = (src2, dst) => {
31712
- const r = [];
31713
- for (let i = 0; i < dst; i++) {
31714
- if (src2 === dst) {
31715
- r.push([[i, 1]]);
31716
- continue;
31717
- }
31718
- const raw = (i + 0.5) * src2 / dst - 0.5;
31719
- const pos = Math.max(0, Math.min(src2 - 1, raw));
31720
- const i0 = Math.floor(pos);
31721
- if (dst === 2 * src2) {
31722
- r.push([[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]]);
31723
- continue;
31724
- }
31725
- const taps = [];
31726
- let total = 0;
31727
- for (let k = i0 - 2; k <= i0 + 3; k++) {
31728
- const w = softTent(raw - k);
31729
- taps.push([Math.max(0, Math.min(src2 - 1, k)), w]);
31730
- total += w;
31731
- }
31732
- r.push(taps.map(([k, w]) => [k, w / total]));
31777
+ if (src2 === dst) return Array.from({ length: dst }, (_, i) => [[i, 1]]);
31778
+ if (dst === 2 * src2) {
31779
+ return Array.from({ length: dst }, (_, i) => {
31780
+ const pos = Math.max(0, Math.min(src2 - 1, (i + 0.5) * src2 / dst - 0.5));
31781
+ const i0 = Math.floor(pos);
31782
+ return [[i0, 1 - (pos - i0)], [Math.min(src2 - 1, i0 + 1), pos - i0]];
31783
+ });
31733
31784
  }
31734
- return r;
31785
+ return halftoneEnlargeTaps(src2, dst);
31735
31786
  };
31736
31787
  const xt = axisTaps(sampleW, W), yt = axisTaps(sampleH, H);
31737
31788
  for (let y = 0; y < H; y++) {
@@ -31739,7 +31790,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
31739
31790
  for (let c = 0; c < 3; c++) {
31740
31791
  let v = 0;
31741
31792
  for (const [yy, wy] of yt[y]) for (const [xx, wx] of xt[x]) v += source[(yy * sampleW + xx) * 3 + c] * wy * wx;
31742
- out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5)));
31793
+ out[(y * W + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + 0.5 + 1e-7)));
31743
31794
  }
31744
31795
  }
31745
31796
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emf-converter",
3
- "version": "4.6.7",
3
+ "version": "4.6.8",
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",