emf-converter 4.8.21 → 4.10.0

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
@@ -29643,7 +29643,7 @@ var Outliner = class {
29643
29643
  this.flush();
29644
29644
  }
29645
29645
  };
29646
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29646
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29647
29647
  const out = [];
29648
29648
  const dashes = [];
29649
29649
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29663,8 +29663,8 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29663
29663
  const [x0, y0] = P[i];
29664
29664
  const [x1, y1] = P[i + 1];
29665
29665
  const dir = [x1 - x0, y1 - y0];
29666
- const real = Math.hypot(dir[0], dir[1]);
29667
- const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29666
+ const real = metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29667
+ const len = metric ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29668
29668
  if (len === 0) {
29669
29669
  if (on && cur) {
29670
29670
  cur.pts.push(P[i + 1]);
@@ -29708,7 +29708,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29708
29708
  }
29709
29709
  return out;
29710
29710
  }
29711
+ function widenInLogicalSpace(path, opts, m) {
29712
+ const [a, b, c, d] = m;
29713
+ const det = a * d - b * c;
29714
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29715
+ const logical = new GdiRasterPath();
29716
+ for (const fig of path.figures) {
29717
+ const pts = [];
29718
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29719
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29720
+ }
29721
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29722
+ if (fig.tangents) {
29723
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29724
+ }
29725
+ logical.figures.push(copy);
29726
+ }
29727
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29728
+ return outline.map((poly) => {
29729
+ const out = [];
29730
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29731
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29732
+ }
29733
+ return out;
29734
+ });
29735
+ }
29711
29736
  function widenPath(path, opts) {
29737
+ if (opts.matrix) {
29738
+ return widenInLogicalSpace(path, opts, opts.matrix);
29739
+ }
29712
29740
  const out = [];
29713
29741
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29714
29742
  for (const fig of path.figures) {
@@ -29737,10 +29765,10 @@ function widenPath(path, opts) {
29737
29765
  }
29738
29766
  if (dashed) {
29739
29767
  const run = closed ? [...P, P[0]] : P;
29740
- const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29768
+ const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29741
29769
  const runTangents = closed ? [...dirs, void 0] : dirs;
29742
29770
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29743
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29771
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29744
29772
  const pts = [piece.pts[0]];
29745
29773
  const pdirs = [];
29746
29774
  const pdraws = [];
@@ -30007,8 +30035,24 @@ function penWidenOptions(rCtx, opts = {}) {
30007
30035
  const widthPx = rCtx.wholeDevicePixels && (flags & 15) === 6 ? state.penWidth * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) : penDeviceWidth(rCtx);
30008
30036
  const capBits = flags & 3840;
30009
30037
  const joinBits = flags & 61440;
30010
- const dashes = state.penExtended ? geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30011
- const ellipse = !dashes && !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30038
+ const ellipse = !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30039
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30040
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30041
+ const similar = Math.abs(matrix[0] - matrix[3]) < 1e-6 && Math.abs(matrix[1] + matrix[2]) < 1e-6 || Math.abs(matrix[0] + matrix[3]) < 1e-6 && Math.abs(matrix[1] - matrix[2]) < 1e-6;
30042
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !similar && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30043
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30044
+ const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30045
+ if (general) {
30046
+ return {
30047
+ width: Math.round(state.penWidth * 16),
30048
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30049
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30050
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30051
+ miterLimit: state.miterLimit ?? 10,
30052
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30053
+ shortenDashes: (flags & 15) !== 7
30054
+ };
30055
+ }
30012
30056
  return {
30013
30057
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30014
30058
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
@@ -30016,6 +30060,7 @@ function penWidenOptions(rCtx, opts = {}) {
30016
30060
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30017
30061
  miterLimit: state.miterLimit ?? 10,
30018
30062
  dashes: dashes ? dashes.map((v) => v * 16) : null,
30063
+ ...dashMetric ? { dashMetric } : {},
30019
30064
  shortenDashes: (flags & 15) !== 7,
30020
30065
  // One logical unit per device pixel, unrotated: GDI measures dash
30021
30066
  // segments in whole pixels.
package/dist/browser.mjs CHANGED
@@ -29641,7 +29641,7 @@ var Outliner = class {
29641
29641
  this.flush();
29642
29642
  }
29643
29643
  };
29644
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29644
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29645
29645
  const out = [];
29646
29646
  const dashes = [];
29647
29647
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29661,8 +29661,8 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29661
29661
  const [x0, y0] = P[i];
29662
29662
  const [x1, y1] = P[i + 1];
29663
29663
  const dir = [x1 - x0, y1 - y0];
29664
- const real = Math.hypot(dir[0], dir[1]);
29665
- const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29664
+ const real = metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29665
+ const len = metric ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29666
29666
  if (len === 0) {
29667
29667
  if (on && cur) {
29668
29668
  cur.pts.push(P[i + 1]);
@@ -29706,7 +29706,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29706
29706
  }
29707
29707
  return out;
29708
29708
  }
29709
+ function widenInLogicalSpace(path, opts, m) {
29710
+ const [a, b, c, d] = m;
29711
+ const det = a * d - b * c;
29712
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29713
+ const logical = new GdiRasterPath();
29714
+ for (const fig of path.figures) {
29715
+ const pts = [];
29716
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29717
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29718
+ }
29719
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29720
+ if (fig.tangents) {
29721
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29722
+ }
29723
+ logical.figures.push(copy);
29724
+ }
29725
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29726
+ return outline.map((poly) => {
29727
+ const out = [];
29728
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29729
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29730
+ }
29731
+ return out;
29732
+ });
29733
+ }
29709
29734
  function widenPath(path, opts) {
29735
+ if (opts.matrix) {
29736
+ return widenInLogicalSpace(path, opts, opts.matrix);
29737
+ }
29710
29738
  const out = [];
29711
29739
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29712
29740
  for (const fig of path.figures) {
@@ -29735,10 +29763,10 @@ function widenPath(path, opts) {
29735
29763
  }
29736
29764
  if (dashed) {
29737
29765
  const run = closed ? [...P, P[0]] : P;
29738
- const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29766
+ const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29739
29767
  const runTangents = closed ? [...dirs, void 0] : dirs;
29740
29768
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29741
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29769
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29742
29770
  const pts = [piece.pts[0]];
29743
29771
  const pdirs = [];
29744
29772
  const pdraws = [];
@@ -30005,8 +30033,24 @@ function penWidenOptions(rCtx, opts = {}) {
30005
30033
  const widthPx = rCtx.wholeDevicePixels && (flags & 15) === 6 ? state.penWidth * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) : penDeviceWidth(rCtx);
30006
30034
  const capBits = flags & 3840;
30007
30035
  const joinBits = flags & 61440;
30008
- const dashes = state.penExtended ? geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30009
- const ellipse = !dashes && !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30036
+ const ellipse = !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30037
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30038
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30039
+ const similar = Math.abs(matrix[0] - matrix[3]) < 1e-6 && Math.abs(matrix[1] + matrix[2]) < 1e-6 || Math.abs(matrix[0] + matrix[3]) < 1e-6 && Math.abs(matrix[1] - matrix[2]) < 1e-6;
30040
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !similar && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30041
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30042
+ const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30043
+ if (general) {
30044
+ return {
30045
+ width: Math.round(state.penWidth * 16),
30046
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30047
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30048
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30049
+ miterLimit: state.miterLimit ?? 10,
30050
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30051
+ shortenDashes: (flags & 15) !== 7
30052
+ };
30053
+ }
30010
30054
  return {
30011
30055
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30012
30056
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
@@ -30014,6 +30058,7 @@ function penWidenOptions(rCtx, opts = {}) {
30014
30058
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30015
30059
  miterLimit: state.miterLimit ?? 10,
30016
30060
  dashes: dashes ? dashes.map((v) => v * 16) : null,
30061
+ ...dashMetric ? { dashMetric } : {},
30017
30062
  shortenDashes: (flags & 15) !== 7,
30018
30063
  // One logical unit per device pixel, unrotated: GDI measures dash
30019
30064
  // segments in whole pixels.
package/dist/index.js CHANGED
@@ -29644,7 +29644,7 @@ var Outliner = class {
29644
29644
  this.flush();
29645
29645
  }
29646
29646
  };
29647
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29647
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29648
29648
  const out = [];
29649
29649
  const dashes = [];
29650
29650
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29664,8 +29664,8 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29664
29664
  const [x0, y0] = P[i];
29665
29665
  const [x1, y1] = P[i + 1];
29666
29666
  const dir = [x1 - x0, y1 - y0];
29667
- const real = Math.hypot(dir[0], dir[1]);
29668
- const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29667
+ const real = metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29668
+ const len = metric ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29669
29669
  if (len === 0) {
29670
29670
  if (on && cur) {
29671
29671
  cur.pts.push(P[i + 1]);
@@ -29709,7 +29709,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29709
29709
  }
29710
29710
  return out;
29711
29711
  }
29712
+ function widenInLogicalSpace(path, opts, m) {
29713
+ const [a, b, c, d] = m;
29714
+ const det = a * d - b * c;
29715
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29716
+ const logical = new GdiRasterPath();
29717
+ for (const fig of path.figures) {
29718
+ const pts = [];
29719
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29720
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29721
+ }
29722
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29723
+ if (fig.tangents) {
29724
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29725
+ }
29726
+ logical.figures.push(copy);
29727
+ }
29728
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29729
+ return outline.map((poly) => {
29730
+ const out = [];
29731
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29732
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29733
+ }
29734
+ return out;
29735
+ });
29736
+ }
29712
29737
  function widenPath(path, opts) {
29738
+ if (opts.matrix) {
29739
+ return widenInLogicalSpace(path, opts, opts.matrix);
29740
+ }
29713
29741
  const out = [];
29714
29742
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29715
29743
  for (const fig of path.figures) {
@@ -29738,10 +29766,10 @@ function widenPath(path, opts) {
29738
29766
  }
29739
29767
  if (dashed) {
29740
29768
  const run = closed ? [...P, P[0]] : P;
29741
- const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29769
+ const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29742
29770
  const runTangents = closed ? [...dirs, void 0] : dirs;
29743
29771
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29744
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29772
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29745
29773
  const pts = [piece.pts[0]];
29746
29774
  const pdirs = [];
29747
29775
  const pdraws = [];
@@ -30008,8 +30036,24 @@ function penWidenOptions(rCtx, opts = {}) {
30008
30036
  const widthPx = rCtx.wholeDevicePixels && (flags & 15) === 6 ? state.penWidth * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) : penDeviceWidth(rCtx);
30009
30037
  const capBits = flags & 3840;
30010
30038
  const joinBits = flags & 61440;
30011
- const dashes = state.penExtended ? geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30012
- const ellipse = !dashes && !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30039
+ const ellipse = !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30040
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30041
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30042
+ const similar = Math.abs(matrix[0] - matrix[3]) < 1e-6 && Math.abs(matrix[1] + matrix[2]) < 1e-6 || Math.abs(matrix[0] + matrix[3]) < 1e-6 && Math.abs(matrix[1] - matrix[2]) < 1e-6;
30043
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !similar && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30044
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30045
+ const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30046
+ if (general) {
30047
+ return {
30048
+ width: Math.round(state.penWidth * 16),
30049
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30050
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30051
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30052
+ miterLimit: state.miterLimit ?? 10,
30053
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30054
+ shortenDashes: (flags & 15) !== 7
30055
+ };
30056
+ }
30013
30057
  return {
30014
30058
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30015
30059
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
@@ -30017,6 +30061,7 @@ function penWidenOptions(rCtx, opts = {}) {
30017
30061
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30018
30062
  miterLimit: state.miterLimit ?? 10,
30019
30063
  dashes: dashes ? dashes.map((v) => v * 16) : null,
30064
+ ...dashMetric ? { dashMetric } : {},
30020
30065
  shortenDashes: (flags & 15) !== 7,
30021
30066
  // One logical unit per device pixel, unrotated: GDI measures dash
30022
30067
  // segments in whole pixels.
package/dist/index.mjs CHANGED
@@ -29642,7 +29642,7 @@ var Outliner = class {
29642
29642
  this.flush();
29643
29643
  }
29644
29644
  };
29645
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
29645
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29646
29646
  const out = [];
29647
29647
  const dashes = [];
29648
29648
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29662,8 +29662,8 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29662
29662
  const [x0, y0] = P[i];
29663
29663
  const [x1, y1] = P[i + 1];
29664
29664
  const dir = [x1 - x0, y1 - y0];
29665
- const real = Math.hypot(dir[0], dir[1]);
29666
- const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29665
+ const real = metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29666
+ const len = metric ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29667
29667
  if (len === 0) {
29668
29668
  if (on && cur) {
29669
29669
  cur.pts.push(P[i + 1]);
@@ -29707,7 +29707,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29707
29707
  }
29708
29708
  return out;
29709
29709
  }
29710
+ function widenInLogicalSpace(path, opts, m) {
29711
+ const [a, b, c, d] = m;
29712
+ const det = a * d - b * c;
29713
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29714
+ const logical = new GdiRasterPath();
29715
+ for (const fig of path.figures) {
29716
+ const pts = [];
29717
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29718
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29719
+ }
29720
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29721
+ if (fig.tangents) {
29722
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29723
+ }
29724
+ logical.figures.push(copy);
29725
+ }
29726
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29727
+ return outline.map((poly) => {
29728
+ const out = [];
29729
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29730
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29731
+ }
29732
+ return out;
29733
+ });
29734
+ }
29710
29735
  function widenPath(path, opts) {
29736
+ if (opts.matrix) {
29737
+ return widenInLogicalSpace(path, opts, opts.matrix);
29738
+ }
29711
29739
  const out = [];
29712
29740
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29713
29741
  for (const fig of path.figures) {
@@ -29736,10 +29764,10 @@ function widenPath(path, opts) {
29736
29764
  }
29737
29765
  if (dashed) {
29738
29766
  const run = closed ? [...P, P[0]] : P;
29739
- const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
29767
+ const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29740
29768
  const runTangents = closed ? [...dirs, void 0] : dirs;
29741
29769
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29742
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
29770
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29743
29771
  const pts = [piece.pts[0]];
29744
29772
  const pdirs = [];
29745
29773
  const pdraws = [];
@@ -30006,8 +30034,24 @@ function penWidenOptions(rCtx, opts = {}) {
30006
30034
  const widthPx = rCtx.wholeDevicePixels && (flags & 15) === 6 ? state.penWidth * Math.sqrt(Math.abs(matrix[0] * matrix[3] - matrix[1] * matrix[2])) : penDeviceWidth(rCtx);
30007
30035
  const capBits = flags & 3840;
30008
30036
  const joinBits = flags & 61440;
30009
- const dashes = state.penExtended ? geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30010
- const ellipse = !dashes && !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30037
+ const ellipse = !rCtx.wholeDevicePixels && state.penWidth * Math.abs(matrix[0]) * 16 >= 1 && state.penWidth * Math.abs(matrix[3]) * 16 >= 1 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6 && Math.abs(Math.abs(matrix[0]) - Math.abs(matrix[3])) > 1e-6;
30038
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30039
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30040
+ const similar = Math.abs(matrix[0] - matrix[3]) < 1e-6 && Math.abs(matrix[1] + matrix[2]) < 1e-6 || Math.abs(matrix[0] + matrix[3]) < 1e-6 && Math.abs(matrix[1] - matrix[2]) < 1e-6;
30041
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !similar && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30042
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30043
+ const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30044
+ if (general) {
30045
+ return {
30046
+ width: Math.round(state.penWidth * 16),
30047
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30048
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30049
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30050
+ miterLimit: state.miterLimit ?? 10,
30051
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30052
+ shortenDashes: (flags & 15) !== 7
30053
+ };
30054
+ }
30011
30055
  return {
30012
30056
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30013
30057
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
@@ -30015,6 +30059,7 @@ function penWidenOptions(rCtx, opts = {}) {
30015
30059
  join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30016
30060
  miterLimit: state.miterLimit ?? 10,
30017
30061
  dashes: dashes ? dashes.map((v) => v * 16) : null,
30062
+ ...dashMetric ? { dashMetric } : {},
30018
30063
  shortenDashes: (flags & 15) !== 7,
30019
30064
  // One logical unit per device pixel, unrotated: GDI measures dash
30020
30065
  // segments in whole pixels.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emf-converter",
3
- "version": "4.8.21",
3
+ "version": "4.10.0",
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",