emf-converter 4.8.6 → 4.8.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.mjs CHANGED
@@ -27796,10 +27796,10 @@ function parseEmfHeader(view) {
27796
27796
  };
27797
27797
  }
27798
27798
  function getRenderableEmfBounds(header) {
27799
- const boundsW = header.bounds.right - header.bounds.left;
27800
- const boundsH = header.bounds.bottom - header.bounds.top;
27799
+ const boundsW = header.bounds.right - header.bounds.left + 1;
27800
+ const boundsH = header.bounds.bottom - header.bounds.top + 1;
27801
27801
  if (boundsW > 0 && boundsH > 0) {
27802
- return header.bounds;
27802
+ return { ...header.bounds, right: header.bounds.right + 1, bottom: header.bounds.bottom + 1 };
27803
27803
  }
27804
27804
  if (header.frameW > 0 && header.frameH > 0) {
27805
27805
  emfLog(
@@ -30831,6 +30831,13 @@ function insetFixBox(box, inset) {
30831
30831
  }
30832
30832
  return framed;
30833
30833
  }
30834
+ function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
30835
+ const ax = BigInt(2 * sx - l - r);
30836
+ const ay = BigInt(2 * sy - t - b);
30837
+ const bx = BigInt(2 * ex - l - r);
30838
+ const by = BigInt(2 * ey - t - b);
30839
+ return ax * by === ay * bx && ax * bx + ay * by > 0n;
30840
+ }
30834
30841
  function handleSetPixelV(rCtx, dataOff, recSize) {
30835
30842
  const { ctx, view } = rCtx;
30836
30843
  if (recSize >= 20) {
@@ -31188,7 +31195,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
31188
31195
  const rx = Math.abs(r - l) / 2;
31189
31196
  const ry = Math.abs(b - t) / 2;
31190
31197
  const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
31191
- const endAngle = Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
31198
+ const clockwise = state.arcDirection === 2;
31199
+ const fullEllipse = recType !== EMR_PIE && rx > 0 && ry > 0 && sameEllipseRay(l, t, r, b, startX, startY, endX, endY);
31200
+ const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
31192
31201
  const rotated = hasWorldRotation(rCtx);
31193
31202
  const unframed = fixBox(rCtx, l, t, r, b);
31194
31203
  const inset = insideFrameInset(rCtx, unframed);
@@ -31202,13 +31211,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
31202
31211
  };
31203
31212
  const isArcTo = recType === EMR_ARCTO;
31204
31213
  const needsFill = recType === EMR_PIE || recType === EMR_CHORD;
31205
- const clockwise = state.arcDirection === 2;
31206
31214
  const startPoint = rotated ? gmapPoint(rCtx, cxA + rx * Math.cos(startAngle), cyA + ry * Math.sin(startAngle)) : { x: params.cx + params.rx * Math.cos(startAngle), y: params.cy + params.ry * Math.sin(startAngle) };
31207
31215
  const build = (c) => {
31208
31216
  if (recType === EMR_PIE) {
31209
31217
  c.moveTo(params.cx, params.cy);
31218
+ } else if (!isArcTo && inPath) {
31219
+ c.moveTo(startPoint.x, startPoint.y);
31210
31220
  }
31211
31221
  if (isArcTo) {
31222
+ if (!inPath) {
31223
+ const from = currentFix(rCtx);
31224
+ c.moveTo(from[0] / 16, from[1] / 16);
31225
+ }
31212
31226
  c.lineTo(startPoint.x, startPoint.y);
31213
31227
  }
31214
31228
  c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, startAngle, endAngle, !clockwise);
@@ -31228,7 +31242,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
31228
31242
  const rasterArgs = (immediate = false) => ({
31229
31243
  box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
31230
31244
  s: radialOnBox(fixPoint(rCtx, startX, startY)),
31231
- e: radialOnBox(fixPoint(rCtx, endX, endY)),
31245
+ // Device FIX rounding can separate distinct radial points on the
31246
+ // same logical ray. Preserve their proven endpoint identity.
31247
+ e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
31232
31248
  from: currentFix(rCtx)
31233
31249
  });
31234
31250
  if (inPath) {
@@ -31816,40 +31832,121 @@ function halftoneReduceTaps(srcLen, dstLen, reverse) {
31816
31832
  if (reverse) taps.reverse();
31817
31833
  return taps;
31818
31834
  }
31819
- var ENLARGE_KERNEL = [
31820
- 0.7598,
31821
- 0.7276,
31822
- 0.6829,
31823
- 0.6528,
31824
- 0.6106,
31825
- 0.5745,
31826
- 0.5362,
31827
- 0.4955,
31828
- 0.457,
31829
- 0.4121,
31830
- 0.3762,
31831
- 0.3233,
31832
- 0.2741,
31833
- 0.226,
31834
- 0.1822,
31835
- 0.1412,
31836
- 0.1021,
31837
- 0.0685,
31838
- 0.0382,
31839
- 0.0138,
31835
+ var ENLARGE_INNER = [
31836
+ 1e3,
31837
+ 992.47,
31838
+ 984.9399,
31839
+ 977.4099,
31840
+ 969.8798,
31841
+ 962.3498,
31842
+ 954.8198,
31843
+ 947.2897,
31844
+ 939.7597,
31845
+ 932.2296,
31846
+ 924.6996,
31847
+ 917.1695,
31848
+ 909.6395,
31849
+ 902.1095,
31850
+ 894.5665,
31851
+ 886.8087,
31852
+ 879.045,
31853
+ 871.2813,
31854
+ 863.4349,
31855
+ 855.5885,
31856
+ 847.7421,
31857
+ 839.8269,
31858
+ 831.9046,
31859
+ 823.912,
31860
+ 815.9193,
31861
+ 807.9266,
31862
+ 799.847,
31863
+ 791.7283,
31864
+ 783.6096,
31865
+ 775.449,
31866
+ 767.3204,
31867
+ 758.9233,
31868
+ 750.5263,
31869
+ 742.4271,
31870
+ 734.0547,
31871
+ 725.6823,
31872
+ 717.232,
31873
+ 708.7675,
31874
+ 700.2393,
31875
+ 691.7111,
31876
+ 683.0734,
31877
+ 674.4357,
31878
+ 665.7105,
31879
+ 656.9854,
31880
+ 648.2603,
31881
+ 639.3747,
31882
+ 630.4873,
31883
+ 621.5157,
31884
+ 612.5442
31885
+ ];
31886
+ var ENLARGE_OUTER = [
31887
+ 375.1388,
31888
+ 364.2093,
31889
+ 353.2797,
31890
+ 342.4714,
31891
+ 331.7615,
31892
+ 321.1462,
31893
+ 310.6456,
31894
+ 300.2252,
31895
+ 289.9229,
31896
+ 279.7227,
31897
+ 269.6439,
31898
+ 259.6535,
31899
+ 249.7825,
31900
+ 240.0362,
31901
+ 230.3856,
31902
+ 220.8799,
31903
+ 211.4594,
31904
+ 202.1844,
31905
+ 192.9996,
31906
+ 183.9679,
31907
+ 175.1064,
31908
+ 166.2864,
31909
+ 157.6436,
31910
+ 149.1447,
31911
+ 140.7609,
31912
+ 132.5474,
31913
+ 124.4802,
31914
+ 116.5636,
31915
+ 108.778,
31916
+ 101.1602,
31917
+ 93.7098,
31918
+ 86.4419,
31919
+ 79.3251,
31920
+ 72.4091,
31921
+ 65.6853,
31922
+ 59.1472,
31923
+ 52.812,
31924
+ 46.6978,
31925
+ 40.8001,
31926
+ 35.1449,
31927
+ 29.7494,
31928
+ 24.6096,
31929
+ 19.7977,
31930
+ 15.2801,
31931
+ 11.1442,
31932
+ 7.3916,
31933
+ 4.1415,
31934
+ 1.4039,
31840
31935
  0
31841
31936
  ];
31842
- var ENLARGE_BOX = 0.2429;
31843
- var ENLARGE_STEP = 0.05;
31937
+ var ENLARGE_HALF = 500.0106;
31938
+ var ENLARGE_KNOTS = 96;
31844
31939
  function enlargeKernel(u) {
31845
- const edge = u / ENLARGE_STEP;
31846
- const i = Math.floor(edge);
31847
- const smooth = i >= ENLARGE_KERNEL.length - 1 ? 0 : ENLARGE_KERNEL[i] + (ENLARGE_KERNEL[i + 1] - ENLARGE_KERNEL[i]) * (edge - i);
31848
- return smooth + ENLARGE_BOX * (Math.abs(u - 0.5) < 1e-9 ? 0.5 : u < 0.5 ? 1 : 0);
31940
+ if (u >= 1) return 0;
31941
+ if (Math.abs(u - 0.5) < 1e-9) return ENLARGE_HALF;
31942
+ const table = u < 0.5 ? ENLARGE_INNER : ENLARGE_OUTER;
31943
+ const edge = u * ENLARGE_KNOTS - (u < 0.5 ? 0 : ENLARGE_KNOTS / 2);
31944
+ const i = Math.min(table.length - 2, Math.floor(edge + 1e-9));
31945
+ return table[i] + (table[i + 1] - table[i]) * (edge - i);
31849
31946
  }
31850
31947
  function halftoneEnlargeTaps(src, dst) {
31851
31948
  const ratio = dst / src;
31852
- const reach = Math.ceil((ENLARGE_KERNEL.length - 1) * ENLARGE_STEP * ratio);
31949
+ const reach = Math.ceil(ratio) - 1;
31853
31950
  const fir = [];
31854
31951
  let total = 0;
31855
31952
  for (let k = 0; k <= reach; k++) {
@@ -31878,7 +31975,17 @@ function halftoneEnlargeTaps(src, dst) {
31878
31975
  weights.set(j, (weights.get(j) ?? 0) + w * v);
31879
31976
  }
31880
31977
  }
31881
- taps.push([...weights.entries()]);
31978
+ const sorted = [...weights.entries()].sort((a, b) => a[0] - b[0]);
31979
+ let prev = 0;
31980
+ let cum = 0;
31981
+ const row2 = [];
31982
+ for (let i = 0; i < sorted.length; i++) {
31983
+ cum += sorted[i][1] * 8192;
31984
+ const c = i === sorted.length - 1 ? 8192 : Math.ceil(cum - 1e-7);
31985
+ row2.push([sorted[i][0], (c - prev) / 8192]);
31986
+ prev = c;
31987
+ }
31988
+ taps.push(row2);
31882
31989
  }
31883
31990
  return taps;
31884
31991
  }
@@ -32095,8 +32202,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32095
32202
  const sampleW = nativeMixed ? Math.min(SW, W) : W;
32096
32203
  const sampleH = nativeMixed ? Math.min(SH, H) : H;
32097
32204
  const axis = nativeMixed ? (n, d, r) => halftoneReduceTaps(n, d, r) : (n, d, r) => halftoneAxis(0, n, d, r);
32098
- const cols = axis(SW, sampleW, flipX);
32099
- const rows = axis(SH, sampleH, flipY);
32205
+ const enlargeX = nativeMixed && W > SW;
32206
+ const enlargeY = nativeMixed && H > SH;
32207
+ const cols = axis(SW, sampleW, flipX && !enlargeX);
32208
+ const rows = axis(SH, sampleH, flipY && !enlargeY);
32100
32209
  if (nearestMixed) {
32101
32210
  const nearest = (taps, src2, dst, reverse) => {
32102
32211
  for (let i = 0; i < dst; i++) {
@@ -32205,6 +32314,8 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32205
32314
  return halftoneEnlargeTaps(src2, dst);
32206
32315
  };
32207
32316
  const xt = axisTaps(sampleW, W), yt = axisTaps(sampleH, H);
32317
+ if (enlargeX && flipX) xt.reverse();
32318
+ if (enlargeY && flipY) yt.reverse();
32208
32319
  for (let y = 0; y < H; y++) {
32209
32320
  for (let x = 0; x < W; x++) {
32210
32321
  for (let c = 0; c < 3; c++) {
@@ -35599,14 +35710,20 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
35599
35710
  }
35600
35711
 
35601
35712
  // src/emf-gdi-transform-handlers.ts
35713
+ function extentsSettable(rCtx) {
35714
+ return rCtx.mapMode === 7 || rCtx.mapMode === 8;
35715
+ }
35602
35716
  function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35603
35717
  const { view } = rCtx;
35604
35718
  switch (recType) {
35605
35719
  case EMR_SETWINDOWEXTEX: {
35606
- if (recSize >= 16) {
35607
- rCtx.windowExt.cx = view.getInt32(dataOff, true);
35608
- rCtx.windowExt.cy = view.getInt32(dataOff + 4, true);
35609
- activateGdiMappingMode(rCtx);
35720
+ if (recSize >= 16 && extentsSettable(rCtx)) {
35721
+ const cx = view.getInt32(dataOff, true);
35722
+ const cy = view.getInt32(dataOff + 4, true);
35723
+ if (cx !== 0 && cy !== 0) {
35724
+ rCtx.windowExt = { cx, cy };
35725
+ activateGdiMappingMode(rCtx);
35726
+ }
35610
35727
  }
35611
35728
  return true;
35612
35729
  }
@@ -35619,10 +35736,13 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35619
35736
  return true;
35620
35737
  }
35621
35738
  case EMR_SETVIEWPORTEXTEX: {
35622
- if (recSize >= 16) {
35623
- rCtx.viewportExt.cx = view.getInt32(dataOff, true);
35624
- rCtx.viewportExt.cy = view.getInt32(dataOff + 4, true);
35625
- activateGdiMappingMode(rCtx);
35739
+ if (recSize >= 16 && extentsSettable(rCtx)) {
35740
+ const cx = view.getInt32(dataOff, true);
35741
+ const cy = view.getInt32(dataOff + 4, true);
35742
+ if (cx !== 0 && cy !== 0) {
35743
+ rCtx.viewportExt = { cx, cy };
35744
+ activateGdiMappingMode(rCtx);
35745
+ }
35626
35746
  }
35627
35747
  return true;
35628
35748
  }
@@ -35637,14 +35757,21 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35637
35757
  case EMR_SETMAPMODE: {
35638
35758
  if (recSize >= 12) {
35639
35759
  const mode = view.getUint32(dataOff, true);
35640
- if (mode === 8 || mode === 7) {
35641
- activateGdiMappingMode(rCtx);
35760
+ if (mode >= 1 && mode <= 8) {
35761
+ rCtx.mapMode = mode;
35762
+ if (mode === 1) {
35763
+ rCtx.windowExt = { cx: 1, cy: 1 };
35764
+ rCtx.viewportExt = { cx: 1, cy: 1 };
35765
+ }
35766
+ if (mode === 1 || mode === 8 || mode === 7) {
35767
+ activateGdiMappingMode(rCtx);
35768
+ }
35642
35769
  }
35643
35770
  }
35644
35771
  return true;
35645
35772
  }
35646
35773
  case EMR_SCALEVIEWPORTEXTEX: {
35647
- if (recSize >= 24) {
35774
+ if (recSize >= 24 && extentsSettable(rCtx)) {
35648
35775
  const xNum = view.getInt32(dataOff, true);
35649
35776
  const xDenom = view.getInt32(dataOff + 4, true);
35650
35777
  const yNum = view.getInt32(dataOff + 8, true);
@@ -35660,7 +35787,7 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35660
35787
  return true;
35661
35788
  }
35662
35789
  case EMR_SCALEWINDOWEXTEX: {
35663
- if (recSize >= 24) {
35790
+ if (recSize >= 24 && extentsSettable(rCtx)) {
35664
35791
  const xNum = view.getInt32(dataOff, true);
35665
35792
  const xDenom = view.getInt32(dataOff + 4, true);
35666
35793
  const yNum = view.getInt32(dataOff + 8, true);
@@ -35811,6 +35938,15 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
35811
35938
  }
35812
35939
  rCtx.clipStack ?? (rCtx.clipStack = []);
35813
35940
  rCtx.clipStack.push({ region: rCtx.clipRegion ?? null });
35941
+ rCtx.mappingStack ?? (rCtx.mappingStack = []);
35942
+ rCtx.mappingStack.push({
35943
+ mapMode: rCtx.mapMode,
35944
+ windowOrg: { ...rCtx.windowOrg },
35945
+ windowExt: { ...rCtx.windowExt },
35946
+ viewportOrg: { ...rCtx.viewportOrg },
35947
+ viewportExt: { ...rCtx.viewportExt },
35948
+ useMappingMode: rCtx.useMappingMode
35949
+ });
35814
35950
  rCtx.stateStack.push(cloneState(state));
35815
35951
  ctx.save();
35816
35952
  if (rCtx.clipRegion) {
@@ -35820,23 +35956,31 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
35820
35956
  }
35821
35957
  case EMR_RESTOREDC: {
35822
35958
  if (recSize >= 12) {
35823
- while (rCtx.clipSaveDepth > 0) {
35824
- ctx.restore();
35825
- rCtx.clipSaveDepth--;
35826
- }
35827
35959
  let rel = view.getInt32(dataOff, true);
35828
35960
  if (rel < 0) {
35829
35961
  rel = rCtx.stateStack.length + rel + 1;
35830
35962
  }
35831
- while (rCtx.stateStack.length > rel && rCtx.stateStack.length > 0) {
35963
+ if (rel < 1 || rel > rCtx.stateStack.length) {
35964
+ return true;
35965
+ }
35966
+ while (rCtx.clipSaveDepth > 0) {
35967
+ ctx.restore();
35968
+ rCtx.clipSaveDepth--;
35969
+ }
35970
+ while (rCtx.stateStack.length > rel) {
35832
35971
  rCtx.stateStack.pop();
35833
35972
  rCtx.clipStack?.pop();
35973
+ rCtx.mappingStack?.pop();
35834
35974
  ctx.restore();
35835
35975
  }
35836
35976
  const restored = rCtx.stateStack.pop();
35837
35977
  if (restored) {
35838
35978
  const clipSnapshot = rCtx.clipStack?.pop();
35979
+ const mappingSnapshot = rCtx.mappingStack?.pop();
35839
35980
  Object.assign(state, restored);
35981
+ if (mappingSnapshot) {
35982
+ Object.assign(rCtx, mappingSnapshot);
35983
+ }
35840
35984
  ctx.restore();
35841
35985
  rCtx.clipRegion = clipSnapshot?.region ?? null;
35842
35986
  if (rCtx.clipRegion) {
@@ -37935,9 +38079,11 @@ function replayEmfRecords(view, ctx, bounds, canvasW, canvasH, dpiScale = 1, rep
37935
38079
  // canvas like every other device coordinate (bounds' top-left to the
37936
38080
  // canvas origin, scaled by sx/sy); see `deviceToCanvas`.
37937
38081
  windowOrg: { x: 0, y: 0 },
37938
- windowExt: { cx: logicalW, cy: logicalH },
38082
+ windowExt: { cx: 1, cy: 1 },
37939
38083
  viewportOrg: { x: 0, y: 0 },
37940
- viewportExt: { cx: logicalW, cy: logicalH },
38084
+ viewportExt: { cx: 1, cy: 1 },
38085
+ mapMode: 1,
38086
+ // MM_TEXT: the default DC uses one-to-one page/device units.
37941
38087
  useMappingMode: false,
37942
38088
  deviceToCanvas: true,
37943
38089
  clipSaveDepth: 0,
@@ -38189,18 +38335,18 @@ function setMapMode(m, mode) {
38189
38335
  }
38190
38336
  m.mode = mode;
38191
38337
  }
38192
- function extentsSettable(m) {
38338
+ function extentsSettable2(m) {
38193
38339
  return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
38194
38340
  }
38195
38341
  function setWindowExt(m, cx, cy) {
38196
- if (!extentsSettable(m) || cx === 0 || cy === 0) {
38342
+ if (!extentsSettable2(m) || cx === 0 || cy === 0) {
38197
38343
  return;
38198
38344
  }
38199
38345
  m.winExt = { cx, cy };
38200
38346
  fixIsotropic(m);
38201
38347
  }
38202
38348
  function setViewportExt(m, cx, cy) {
38203
- if (!extentsSettable(m) || cx === 0 || cy === 0) {
38349
+ if (!extentsSettable2(m) || cx === 0 || cy === 0) {
38204
38350
  return;
38205
38351
  }
38206
38352
  m.vpExt = { cx, cy };
@@ -38210,7 +38356,7 @@ function scaled(v, num, den) {
38210
38356
  return Math.trunc(v * num / den);
38211
38357
  }
38212
38358
  function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
38213
- if (!extentsSettable(m) || !xDen || !yDen) {
38359
+ if (!extentsSettable2(m) || !xDen || !yDen) {
38214
38360
  return;
38215
38361
  }
38216
38362
  const cx = scaled(m.winExt.cx, xNum, xDen);
@@ -38222,7 +38368,7 @@ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
38222
38368
  fixIsotropic(m);
38223
38369
  }
38224
38370
  function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
38225
- if (!extentsSettable(m) || !xDen || !yDen) {
38371
+ if (!extentsSettable2(m) || !xDen || !yDen) {
38226
38372
  return;
38227
38373
  }
38228
38374
  const cx = scaled(m.vpExt.cx, xNum, xDen);