emf-converter 4.9.0 → 4.11.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
@@ -29238,11 +29238,42 @@ function penPolygon(width, height = width) {
29238
29238
  penCache.set(key, pen);
29239
29239
  return pen;
29240
29240
  }
29241
- function drawVertices(pen, dx, dy, width = 1, height = width) {
29241
+ var matrixPenCache = /* @__PURE__ */ new Map();
29242
+ function penPolygonMatrix(width, m) {
29243
+ const key = `${width},${m.join(",")}`;
29244
+ const cached = matrixPenCache.get(key);
29245
+ if (cached) {
29246
+ return cached;
29247
+ }
29248
+ const r = Math.ceil(width / 2);
29249
+ const mirror2 = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
29250
+ const bez = ellipseBeziers(-r, -r, r, r);
29251
+ const dev = [];
29252
+ for (let i = 0; i < 14; i += 2) {
29253
+ const x = bez[i];
29254
+ const y = bez[i + 1] * mirror2;
29255
+ dev.push(Math.round(m[0] * x + m[2] * y), Math.round(m[1] * x + m[3] * y));
29256
+ }
29257
+ const f = flattenBezierPath(dev);
29258
+ const half = [];
29259
+ for (let i = 0; i + 1 < f.length; i += 2) {
29260
+ half.push([f[i], f[i + 1]]);
29261
+ }
29262
+ half.pop();
29263
+ const pen = [...half, ...half.map((p) => [0 - p[0] || 0, 0 - p[1] || 0])];
29264
+ matrixPenCache.set(key, pen);
29265
+ return pen;
29266
+ }
29267
+ function drawVertices(pen, dx, dy, width = 1, height = width, matrix) {
29242
29268
  const n = pen.length;
29243
29269
  const axisVertex = pen.some((q) => q[1] === 0);
29244
- const yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29245
- const xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29270
+ let yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29271
+ let xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29272
+ if (matrix) {
29273
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29274
+ xMagnitude = Math.abs((matrix[3] * dx - matrix[2] * dy) / det);
29275
+ yMagnitude = Math.abs((-matrix[1] * dx + matrix[0] * dy) / det);
29276
+ }
29246
29277
  const steep = yMagnitude > xMagnitude || yMagnitude === xMagnitude && axisVertex;
29247
29278
  const s = (steep ? dy < 0 : dx < 0 || dx === 0 && dy < 0) ? -1 : 1;
29248
29279
  let best = 0;
@@ -29262,7 +29293,7 @@ function drawVertices(pen, dx, dy, width = 1, height = width) {
29262
29293
  function halfPixel(v) {
29263
29294
  return Math.sign(v) * 8 * Math.floor((Math.abs(v) + 4) / 8);
29264
29295
  }
29265
- function perpendicularVectors(width, dx0, dy0, height = width) {
29296
+ function perpendicularVectors(width, dx0, dy0, height = width, matrixPen) {
29266
29297
  let dx = dx0;
29267
29298
  let dy = dy0;
29268
29299
  const flip = dx < 0 || dx === 0 && dy < 0;
@@ -29270,7 +29301,7 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29270
29301
  dx = -dx;
29271
29302
  dy = -dy;
29272
29303
  }
29273
- const pen = penPolygon(width, height);
29304
+ const pen = matrixPen ?? penPolygon(width, height);
29274
29305
  const n = pen.length;
29275
29306
  const nx = -dy;
29276
29307
  const ny = dx;
@@ -29309,7 +29340,15 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29309
29340
  const vx = rounded[0], vy = rounded[1];
29310
29341
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29311
29342
  }
29312
- function squareExtension(width, dx, dy, scale = 1, height = width) {
29343
+ function squareExtension(width, dx, dy, scale = 1, height = width, matrix) {
29344
+ if (matrix) {
29345
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29346
+ const lx = (matrix[3] * dx - matrix[2] * dy) / det;
29347
+ const ly = (-matrix[1] * dx + matrix[0] * dy) / det;
29348
+ const l = Math.hypot(lx, ly);
29349
+ const q = width / 2 * scale / l;
29350
+ return [Math.floor((matrix[0] * lx + matrix[2] * ly) * q + 0.5), Math.floor((matrix[1] * lx + matrix[3] * ly) * q + 0.5)];
29351
+ }
29313
29352
  const len = width === height ? Math.hypot(dx, dy) : Math.hypot(dx, dy * width / height);
29314
29353
  const r = width / 2 * scale;
29315
29354
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
@@ -29332,7 +29371,7 @@ var Outliner = class {
29332
29371
  this.opts = opts;
29333
29372
  this.out = out;
29334
29373
  this.pts = [];
29335
- this.pen = penPolygon(opts.width, opts.height);
29374
+ this.pen = opts.matrix && opts.deviceNib ? penPolygonMatrix(opts.width, opts.matrix) : penPolygon(opts.width, opts.height);
29336
29375
  this.n = this.pen.length;
29337
29376
  this.rr = opts.cap === "round" && opts.join === "round";
29338
29377
  this.originalRoundJoinSides = opts.join === "round" && opts.cap !== "flat";
@@ -29347,10 +29386,11 @@ var Outliner = class {
29347
29386
  const dx = dir ? dir[0] : b[0] - a[0];
29348
29387
  const dy = dir ? dir[1] : b[1] - a[1];
29349
29388
  const d = drawDir ?? [dx, dy];
29350
- const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height);
29389
+ const nibMatrix = this.opts.deviceNib ? this.opts.matrix : void 0;
29390
+ const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height, nibMatrix);
29351
29391
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29352
- const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height);
29353
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29392
+ const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height, nibMatrix ? this.pen : void 0);
29393
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height, nibMatrix), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29354
29394
  }
29355
29395
  push(p, v) {
29356
29396
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29463,7 +29503,7 @@ var Outliner = class {
29463
29503
  const sv = this.capSide(s, from);
29464
29504
  const ev = this.capSide(s, to);
29465
29505
  if (cap === "square") {
29466
- const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height);
29506
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0);
29467
29507
  const e = start ? [-e0[0], -e0[1]] : e0;
29468
29508
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29469
29509
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
@@ -29643,7 +29683,7 @@ var Outliner = class {
29643
29683
  this.flush();
29644
29684
  }
29645
29685
  };
29646
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29686
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric, matrix) {
29647
29687
  const out = [];
29648
29688
  const dashes = [];
29649
29689
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29663,8 +29703,9 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29663
29703
  const [x0, y0] = P[i];
29664
29704
  const [x1, y1] = P[i + 1];
29665
29705
  const dir = [x1 - x0, y1 - y0];
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]);
29706
+ const det = matrix ? matrix[0] * matrix[3] - matrix[1] * matrix[2] : 1;
29707
+ const real = matrix ? Math.hypot((matrix[3] * dir[0] - matrix[2] * dir[1]) / det, (-matrix[1] * dir[0] + matrix[0] * dir[1]) / det) : metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29708
+ const len = metric || matrix ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29668
29709
  if (len === 0) {
29669
29710
  if (on && cur) {
29670
29711
  cur.pts.push(P[i + 1]);
@@ -29708,7 +29749,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29708
29749
  }
29709
29750
  return out;
29710
29751
  }
29752
+ function widenInLogicalSpace(path, opts, m) {
29753
+ const [a, b, c, d] = m;
29754
+ const det = a * d - b * c;
29755
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29756
+ const logical = new GdiRasterPath();
29757
+ for (const fig of path.figures) {
29758
+ const pts = [];
29759
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29760
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29761
+ }
29762
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29763
+ if (fig.tangents) {
29764
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29765
+ }
29766
+ logical.figures.push(copy);
29767
+ }
29768
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29769
+ return outline.map((poly) => {
29770
+ const out = [];
29771
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29772
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29773
+ }
29774
+ return out;
29775
+ });
29776
+ }
29711
29777
  function widenPath(path, opts) {
29778
+ if (opts.matrix && !(opts.deviceNib && opts.join === "round")) {
29779
+ return widenInLogicalSpace(path, opts, opts.matrix);
29780
+ }
29712
29781
  const out = [];
29713
29782
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29714
29783
  for (const fig of path.figures) {
@@ -29740,7 +29809,7 @@ function widenPath(path, opts) {
29740
29809
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29741
29810
  const runTangents = closed ? [...dirs, void 0] : dirs;
29742
29811
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29743
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29812
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric, opts.deviceNib ? opts.matrix : void 0)) {
29744
29813
  const pts = [piece.pts[0]];
29745
29814
  const pdirs = [];
29746
29815
  const pdraws = [];
@@ -30008,8 +30077,24 @@ function penWidenOptions(rCtx, opts = {}) {
30008
30077
  const capBits = flags & 3840;
30009
30078
  const joinBits = flags & 61440;
30010
30079
  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;
30011
- const dashes = state.penExtended ? ellipse ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30080
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30081
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30082
+ const quarterTurn = Math.abs(matrix[0]) < 1e-9 && Math.abs(matrix[3]) < 1e-9;
30083
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !quarterTurn && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30084
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30012
30085
  const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30086
+ if (general) {
30087
+ return {
30088
+ width: Math.round(state.penWidth * 16),
30089
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30090
+ deviceNib: true,
30091
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30092
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30093
+ miterLimit: state.miterLimit ?? 10,
30094
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30095
+ shortenDashes: (flags & 15) !== 7
30096
+ };
30097
+ }
30013
30098
  return {
30014
30099
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30015
30100
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
package/dist/browser.mjs CHANGED
@@ -29236,11 +29236,42 @@ function penPolygon(width, height = width) {
29236
29236
  penCache.set(key, pen);
29237
29237
  return pen;
29238
29238
  }
29239
- function drawVertices(pen, dx, dy, width = 1, height = width) {
29239
+ var matrixPenCache = /* @__PURE__ */ new Map();
29240
+ function penPolygonMatrix(width, m) {
29241
+ const key = `${width},${m.join(",")}`;
29242
+ const cached = matrixPenCache.get(key);
29243
+ if (cached) {
29244
+ return cached;
29245
+ }
29246
+ const r = Math.ceil(width / 2);
29247
+ const mirror2 = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
29248
+ const bez = ellipseBeziers(-r, -r, r, r);
29249
+ const dev = [];
29250
+ for (let i = 0; i < 14; i += 2) {
29251
+ const x = bez[i];
29252
+ const y = bez[i + 1] * mirror2;
29253
+ dev.push(Math.round(m[0] * x + m[2] * y), Math.round(m[1] * x + m[3] * y));
29254
+ }
29255
+ const f = flattenBezierPath(dev);
29256
+ const half = [];
29257
+ for (let i = 0; i + 1 < f.length; i += 2) {
29258
+ half.push([f[i], f[i + 1]]);
29259
+ }
29260
+ half.pop();
29261
+ const pen = [...half, ...half.map((p) => [0 - p[0] || 0, 0 - p[1] || 0])];
29262
+ matrixPenCache.set(key, pen);
29263
+ return pen;
29264
+ }
29265
+ function drawVertices(pen, dx, dy, width = 1, height = width, matrix) {
29240
29266
  const n = pen.length;
29241
29267
  const axisVertex = pen.some((q) => q[1] === 0);
29242
- const yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29243
- const xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29268
+ let yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29269
+ let xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29270
+ if (matrix) {
29271
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29272
+ xMagnitude = Math.abs((matrix[3] * dx - matrix[2] * dy) / det);
29273
+ yMagnitude = Math.abs((-matrix[1] * dx + matrix[0] * dy) / det);
29274
+ }
29244
29275
  const steep = yMagnitude > xMagnitude || yMagnitude === xMagnitude && axisVertex;
29245
29276
  const s = (steep ? dy < 0 : dx < 0 || dx === 0 && dy < 0) ? -1 : 1;
29246
29277
  let best = 0;
@@ -29260,7 +29291,7 @@ function drawVertices(pen, dx, dy, width = 1, height = width) {
29260
29291
  function halfPixel(v) {
29261
29292
  return Math.sign(v) * 8 * Math.floor((Math.abs(v) + 4) / 8);
29262
29293
  }
29263
- function perpendicularVectors(width, dx0, dy0, height = width) {
29294
+ function perpendicularVectors(width, dx0, dy0, height = width, matrixPen) {
29264
29295
  let dx = dx0;
29265
29296
  let dy = dy0;
29266
29297
  const flip = dx < 0 || dx === 0 && dy < 0;
@@ -29268,7 +29299,7 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29268
29299
  dx = -dx;
29269
29300
  dy = -dy;
29270
29301
  }
29271
- const pen = penPolygon(width, height);
29302
+ const pen = matrixPen ?? penPolygon(width, height);
29272
29303
  const n = pen.length;
29273
29304
  const nx = -dy;
29274
29305
  const ny = dx;
@@ -29307,7 +29338,15 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29307
29338
  const vx = rounded[0], vy = rounded[1];
29308
29339
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29309
29340
  }
29310
- function squareExtension(width, dx, dy, scale = 1, height = width) {
29341
+ function squareExtension(width, dx, dy, scale = 1, height = width, matrix) {
29342
+ if (matrix) {
29343
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29344
+ const lx = (matrix[3] * dx - matrix[2] * dy) / det;
29345
+ const ly = (-matrix[1] * dx + matrix[0] * dy) / det;
29346
+ const l = Math.hypot(lx, ly);
29347
+ const q = width / 2 * scale / l;
29348
+ return [Math.floor((matrix[0] * lx + matrix[2] * ly) * q + 0.5), Math.floor((matrix[1] * lx + matrix[3] * ly) * q + 0.5)];
29349
+ }
29311
29350
  const len = width === height ? Math.hypot(dx, dy) : Math.hypot(dx, dy * width / height);
29312
29351
  const r = width / 2 * scale;
29313
29352
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
@@ -29330,7 +29369,7 @@ var Outliner = class {
29330
29369
  this.opts = opts;
29331
29370
  this.out = out;
29332
29371
  this.pts = [];
29333
- this.pen = penPolygon(opts.width, opts.height);
29372
+ this.pen = opts.matrix && opts.deviceNib ? penPolygonMatrix(opts.width, opts.matrix) : penPolygon(opts.width, opts.height);
29334
29373
  this.n = this.pen.length;
29335
29374
  this.rr = opts.cap === "round" && opts.join === "round";
29336
29375
  this.originalRoundJoinSides = opts.join === "round" && opts.cap !== "flat";
@@ -29345,10 +29384,11 @@ var Outliner = class {
29345
29384
  const dx = dir ? dir[0] : b[0] - a[0];
29346
29385
  const dy = dir ? dir[1] : b[1] - a[1];
29347
29386
  const d = drawDir ?? [dx, dy];
29348
- const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height);
29387
+ const nibMatrix = this.opts.deviceNib ? this.opts.matrix : void 0;
29388
+ const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height, nibMatrix);
29349
29389
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29350
- const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height);
29351
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29390
+ const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height, nibMatrix ? this.pen : void 0);
29391
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height, nibMatrix), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29352
29392
  }
29353
29393
  push(p, v) {
29354
29394
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29461,7 +29501,7 @@ var Outliner = class {
29461
29501
  const sv = this.capSide(s, from);
29462
29502
  const ev = this.capSide(s, to);
29463
29503
  if (cap === "square") {
29464
- const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height);
29504
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0);
29465
29505
  const e = start ? [-e0[0], -e0[1]] : e0;
29466
29506
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29467
29507
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
@@ -29641,7 +29681,7 @@ var Outliner = class {
29641
29681
  this.flush();
29642
29682
  }
29643
29683
  };
29644
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29684
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric, matrix) {
29645
29685
  const out = [];
29646
29686
  const dashes = [];
29647
29687
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29661,8 +29701,9 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29661
29701
  const [x0, y0] = P[i];
29662
29702
  const [x1, y1] = P[i + 1];
29663
29703
  const dir = [x1 - x0, y1 - y0];
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]);
29704
+ const det = matrix ? matrix[0] * matrix[3] - matrix[1] * matrix[2] : 1;
29705
+ const real = matrix ? Math.hypot((matrix[3] * dir[0] - matrix[2] * dir[1]) / det, (-matrix[1] * dir[0] + matrix[0] * dir[1]) / det) : metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29706
+ const len = metric || matrix ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29666
29707
  if (len === 0) {
29667
29708
  if (on && cur) {
29668
29709
  cur.pts.push(P[i + 1]);
@@ -29706,7 +29747,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29706
29747
  }
29707
29748
  return out;
29708
29749
  }
29750
+ function widenInLogicalSpace(path, opts, m) {
29751
+ const [a, b, c, d] = m;
29752
+ const det = a * d - b * c;
29753
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29754
+ const logical = new GdiRasterPath();
29755
+ for (const fig of path.figures) {
29756
+ const pts = [];
29757
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29758
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29759
+ }
29760
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29761
+ if (fig.tangents) {
29762
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29763
+ }
29764
+ logical.figures.push(copy);
29765
+ }
29766
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29767
+ return outline.map((poly) => {
29768
+ const out = [];
29769
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29770
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29771
+ }
29772
+ return out;
29773
+ });
29774
+ }
29709
29775
  function widenPath(path, opts) {
29776
+ if (opts.matrix && !(opts.deviceNib && opts.join === "round")) {
29777
+ return widenInLogicalSpace(path, opts, opts.matrix);
29778
+ }
29710
29779
  const out = [];
29711
29780
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29712
29781
  for (const fig of path.figures) {
@@ -29738,7 +29807,7 @@ function widenPath(path, opts) {
29738
29807
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29739
29808
  const runTangents = closed ? [...dirs, void 0] : dirs;
29740
29809
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29741
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29810
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric, opts.deviceNib ? opts.matrix : void 0)) {
29742
29811
  const pts = [piece.pts[0]];
29743
29812
  const pdirs = [];
29744
29813
  const pdraws = [];
@@ -30006,8 +30075,24 @@ function penWidenOptions(rCtx, opts = {}) {
30006
30075
  const capBits = flags & 3840;
30007
30076
  const joinBits = flags & 61440;
30008
30077
  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;
30009
- const dashes = state.penExtended ? ellipse ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30078
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30079
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30080
+ const quarterTurn = Math.abs(matrix[0]) < 1e-9 && Math.abs(matrix[3]) < 1e-9;
30081
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !quarterTurn && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30082
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30010
30083
  const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30084
+ if (general) {
30085
+ return {
30086
+ width: Math.round(state.penWidth * 16),
30087
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30088
+ deviceNib: true,
30089
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30090
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30091
+ miterLimit: state.miterLimit ?? 10,
30092
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30093
+ shortenDashes: (flags & 15) !== 7
30094
+ };
30095
+ }
30011
30096
  return {
30012
30097
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30013
30098
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
package/dist/index.js CHANGED
@@ -29239,11 +29239,42 @@ function penPolygon(width, height = width) {
29239
29239
  penCache.set(key, pen);
29240
29240
  return pen;
29241
29241
  }
29242
- function drawVertices(pen, dx, dy, width = 1, height = width) {
29242
+ var matrixPenCache = /* @__PURE__ */ new Map();
29243
+ function penPolygonMatrix(width, m) {
29244
+ const key = `${width},${m.join(",")}`;
29245
+ const cached = matrixPenCache.get(key);
29246
+ if (cached) {
29247
+ return cached;
29248
+ }
29249
+ const r = Math.ceil(width / 2);
29250
+ const mirror2 = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
29251
+ const bez = ellipseBeziers(-r, -r, r, r);
29252
+ const dev = [];
29253
+ for (let i = 0; i < 14; i += 2) {
29254
+ const x = bez[i];
29255
+ const y = bez[i + 1] * mirror2;
29256
+ dev.push(Math.round(m[0] * x + m[2] * y), Math.round(m[1] * x + m[3] * y));
29257
+ }
29258
+ const f = flattenBezierPath(dev);
29259
+ const half = [];
29260
+ for (let i = 0; i + 1 < f.length; i += 2) {
29261
+ half.push([f[i], f[i + 1]]);
29262
+ }
29263
+ half.pop();
29264
+ const pen = [...half, ...half.map((p) => [0 - p[0] || 0, 0 - p[1] || 0])];
29265
+ matrixPenCache.set(key, pen);
29266
+ return pen;
29267
+ }
29268
+ function drawVertices(pen, dx, dy, width = 1, height = width, matrix) {
29243
29269
  const n = pen.length;
29244
29270
  const axisVertex = pen.some((q) => q[1] === 0);
29245
- const yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29246
- const xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29271
+ let yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29272
+ let xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29273
+ if (matrix) {
29274
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29275
+ xMagnitude = Math.abs((matrix[3] * dx - matrix[2] * dy) / det);
29276
+ yMagnitude = Math.abs((-matrix[1] * dx + matrix[0] * dy) / det);
29277
+ }
29247
29278
  const steep = yMagnitude > xMagnitude || yMagnitude === xMagnitude && axisVertex;
29248
29279
  const s = (steep ? dy < 0 : dx < 0 || dx === 0 && dy < 0) ? -1 : 1;
29249
29280
  let best = 0;
@@ -29263,7 +29294,7 @@ function drawVertices(pen, dx, dy, width = 1, height = width) {
29263
29294
  function halfPixel(v) {
29264
29295
  return Math.sign(v) * 8 * Math.floor((Math.abs(v) + 4) / 8);
29265
29296
  }
29266
- function perpendicularVectors(width, dx0, dy0, height = width) {
29297
+ function perpendicularVectors(width, dx0, dy0, height = width, matrixPen) {
29267
29298
  let dx = dx0;
29268
29299
  let dy = dy0;
29269
29300
  const flip = dx < 0 || dx === 0 && dy < 0;
@@ -29271,7 +29302,7 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29271
29302
  dx = -dx;
29272
29303
  dy = -dy;
29273
29304
  }
29274
- const pen = penPolygon(width, height);
29305
+ const pen = matrixPen ?? penPolygon(width, height);
29275
29306
  const n = pen.length;
29276
29307
  const nx = -dy;
29277
29308
  const ny = dx;
@@ -29310,7 +29341,15 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29310
29341
  const vx = rounded[0], vy = rounded[1];
29311
29342
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29312
29343
  }
29313
- function squareExtension(width, dx, dy, scale = 1, height = width) {
29344
+ function squareExtension(width, dx, dy, scale = 1, height = width, matrix) {
29345
+ if (matrix) {
29346
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29347
+ const lx = (matrix[3] * dx - matrix[2] * dy) / det;
29348
+ const ly = (-matrix[1] * dx + matrix[0] * dy) / det;
29349
+ const l = Math.hypot(lx, ly);
29350
+ const q = width / 2 * scale / l;
29351
+ return [Math.floor((matrix[0] * lx + matrix[2] * ly) * q + 0.5), Math.floor((matrix[1] * lx + matrix[3] * ly) * q + 0.5)];
29352
+ }
29314
29353
  const len = width === height ? Math.hypot(dx, dy) : Math.hypot(dx, dy * width / height);
29315
29354
  const r = width / 2 * scale;
29316
29355
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
@@ -29333,7 +29372,7 @@ var Outliner = class {
29333
29372
  this.opts = opts;
29334
29373
  this.out = out;
29335
29374
  this.pts = [];
29336
- this.pen = penPolygon(opts.width, opts.height);
29375
+ this.pen = opts.matrix && opts.deviceNib ? penPolygonMatrix(opts.width, opts.matrix) : penPolygon(opts.width, opts.height);
29337
29376
  this.n = this.pen.length;
29338
29377
  this.rr = opts.cap === "round" && opts.join === "round";
29339
29378
  this.originalRoundJoinSides = opts.join === "round" && opts.cap !== "flat";
@@ -29348,10 +29387,11 @@ var Outliner = class {
29348
29387
  const dx = dir ? dir[0] : b[0] - a[0];
29349
29388
  const dy = dir ? dir[1] : b[1] - a[1];
29350
29389
  const d = drawDir ?? [dx, dy];
29351
- const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height);
29390
+ const nibMatrix = this.opts.deviceNib ? this.opts.matrix : void 0;
29391
+ const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height, nibMatrix);
29352
29392
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29353
- const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height);
29354
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29393
+ const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height, nibMatrix ? this.pen : void 0);
29394
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height, nibMatrix), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29355
29395
  }
29356
29396
  push(p, v) {
29357
29397
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29464,7 +29504,7 @@ var Outliner = class {
29464
29504
  const sv = this.capSide(s, from);
29465
29505
  const ev = this.capSide(s, to);
29466
29506
  if (cap === "square") {
29467
- const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height);
29507
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0);
29468
29508
  const e = start ? [-e0[0], -e0[1]] : e0;
29469
29509
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29470
29510
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
@@ -29644,7 +29684,7 @@ var Outliner = class {
29644
29684
  this.flush();
29645
29685
  }
29646
29686
  };
29647
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29687
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric, matrix) {
29648
29688
  const out = [];
29649
29689
  const dashes = [];
29650
29690
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29664,8 +29704,9 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29664
29704
  const [x0, y0] = P[i];
29665
29705
  const [x1, y1] = P[i + 1];
29666
29706
  const dir = [x1 - x0, y1 - y0];
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]);
29707
+ const det = matrix ? matrix[0] * matrix[3] - matrix[1] * matrix[2] : 1;
29708
+ const real = matrix ? Math.hypot((matrix[3] * dir[0] - matrix[2] * dir[1]) / det, (-matrix[1] * dir[0] + matrix[0] * dir[1]) / det) : metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29709
+ const len = metric || matrix ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29669
29710
  if (len === 0) {
29670
29711
  if (on && cur) {
29671
29712
  cur.pts.push(P[i + 1]);
@@ -29709,7 +29750,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29709
29750
  }
29710
29751
  return out;
29711
29752
  }
29753
+ function widenInLogicalSpace(path, opts, m) {
29754
+ const [a, b, c, d] = m;
29755
+ const det = a * d - b * c;
29756
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29757
+ const logical = new GdiRasterPath();
29758
+ for (const fig of path.figures) {
29759
+ const pts = [];
29760
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29761
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29762
+ }
29763
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29764
+ if (fig.tangents) {
29765
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29766
+ }
29767
+ logical.figures.push(copy);
29768
+ }
29769
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29770
+ return outline.map((poly) => {
29771
+ const out = [];
29772
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29773
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29774
+ }
29775
+ return out;
29776
+ });
29777
+ }
29712
29778
  function widenPath(path, opts) {
29779
+ if (opts.matrix && !(opts.deviceNib && opts.join === "round")) {
29780
+ return widenInLogicalSpace(path, opts, opts.matrix);
29781
+ }
29713
29782
  const out = [];
29714
29783
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29715
29784
  for (const fig of path.figures) {
@@ -29741,7 +29810,7 @@ function widenPath(path, opts) {
29741
29810
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29742
29811
  const runTangents = closed ? [...dirs, void 0] : dirs;
29743
29812
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29744
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29813
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric, opts.deviceNib ? opts.matrix : void 0)) {
29745
29814
  const pts = [piece.pts[0]];
29746
29815
  const pdirs = [];
29747
29816
  const pdraws = [];
@@ -30009,8 +30078,24 @@ function penWidenOptions(rCtx, opts = {}) {
30009
30078
  const capBits = flags & 3840;
30010
30079
  const joinBits = flags & 61440;
30011
30080
  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;
30012
- const dashes = state.penExtended ? ellipse ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30081
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30082
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30083
+ const quarterTurn = Math.abs(matrix[0]) < 1e-9 && Math.abs(matrix[3]) < 1e-9;
30084
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !quarterTurn && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30085
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30013
30086
  const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30087
+ if (general) {
30088
+ return {
30089
+ width: Math.round(state.penWidth * 16),
30090
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30091
+ deviceNib: true,
30092
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30093
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30094
+ miterLimit: state.miterLimit ?? 10,
30095
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30096
+ shortenDashes: (flags & 15) !== 7
30097
+ };
30098
+ }
30014
30099
  return {
30015
30100
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30016
30101
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
package/dist/index.mjs CHANGED
@@ -29237,11 +29237,42 @@ function penPolygon(width, height = width) {
29237
29237
  penCache.set(key, pen);
29238
29238
  return pen;
29239
29239
  }
29240
- function drawVertices(pen, dx, dy, width = 1, height = width) {
29240
+ var matrixPenCache = /* @__PURE__ */ new Map();
29241
+ function penPolygonMatrix(width, m) {
29242
+ const key = `${width},${m.join(",")}`;
29243
+ const cached = matrixPenCache.get(key);
29244
+ if (cached) {
29245
+ return cached;
29246
+ }
29247
+ const r = Math.ceil(width / 2);
29248
+ const mirror2 = m[0] * m[3] - m[1] * m[2] < 0 ? -1 : 1;
29249
+ const bez = ellipseBeziers(-r, -r, r, r);
29250
+ const dev = [];
29251
+ for (let i = 0; i < 14; i += 2) {
29252
+ const x = bez[i];
29253
+ const y = bez[i + 1] * mirror2;
29254
+ dev.push(Math.round(m[0] * x + m[2] * y), Math.round(m[1] * x + m[3] * y));
29255
+ }
29256
+ const f = flattenBezierPath(dev);
29257
+ const half = [];
29258
+ for (let i = 0; i + 1 < f.length; i += 2) {
29259
+ half.push([f[i], f[i + 1]]);
29260
+ }
29261
+ half.pop();
29262
+ const pen = [...half, ...half.map((p) => [0 - p[0] || 0, 0 - p[1] || 0])];
29263
+ matrixPenCache.set(key, pen);
29264
+ return pen;
29265
+ }
29266
+ function drawVertices(pen, dx, dy, width = 1, height = width, matrix) {
29241
29267
  const n = pen.length;
29242
29268
  const axisVertex = pen.some((q) => q[1] === 0);
29243
- const yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29244
- const xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29269
+ let yMagnitude = Math.abs(dy) * (width === height ? 1 : width);
29270
+ let xMagnitude = Math.abs(dx) * (width === height ? 2 : height);
29271
+ if (matrix) {
29272
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29273
+ xMagnitude = Math.abs((matrix[3] * dx - matrix[2] * dy) / det);
29274
+ yMagnitude = Math.abs((-matrix[1] * dx + matrix[0] * dy) / det);
29275
+ }
29245
29276
  const steep = yMagnitude > xMagnitude || yMagnitude === xMagnitude && axisVertex;
29246
29277
  const s = (steep ? dy < 0 : dx < 0 || dx === 0 && dy < 0) ? -1 : 1;
29247
29278
  let best = 0;
@@ -29261,7 +29292,7 @@ function drawVertices(pen, dx, dy, width = 1, height = width) {
29261
29292
  function halfPixel(v) {
29262
29293
  return Math.sign(v) * 8 * Math.floor((Math.abs(v) + 4) / 8);
29263
29294
  }
29264
- function perpendicularVectors(width, dx0, dy0, height = width) {
29295
+ function perpendicularVectors(width, dx0, dy0, height = width, matrixPen) {
29265
29296
  let dx = dx0;
29266
29297
  let dy = dy0;
29267
29298
  const flip = dx < 0 || dx === 0 && dy < 0;
@@ -29269,7 +29300,7 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29269
29300
  dx = -dx;
29270
29301
  dy = -dy;
29271
29302
  }
29272
- const pen = penPolygon(width, height);
29303
+ const pen = matrixPen ?? penPolygon(width, height);
29273
29304
  const n = pen.length;
29274
29305
  const nx = -dy;
29275
29306
  const ny = dx;
@@ -29308,7 +29339,15 @@ function perpendicularVectors(width, dx0, dy0, height = width) {
29308
29339
  const vx = rounded[0], vy = rounded[1];
29309
29340
  return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
29310
29341
  }
29311
- function squareExtension(width, dx, dy, scale = 1, height = width) {
29342
+ function squareExtension(width, dx, dy, scale = 1, height = width, matrix) {
29343
+ if (matrix) {
29344
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
29345
+ const lx = (matrix[3] * dx - matrix[2] * dy) / det;
29346
+ const ly = (-matrix[1] * dx + matrix[0] * dy) / det;
29347
+ const l = Math.hypot(lx, ly);
29348
+ const q = width / 2 * scale / l;
29349
+ return [Math.floor((matrix[0] * lx + matrix[2] * ly) * q + 0.5), Math.floor((matrix[1] * lx + matrix[3] * ly) * q + 0.5)];
29350
+ }
29312
29351
  const len = width === height ? Math.hypot(dx, dy) : Math.hypot(dx, dy * width / height);
29313
29352
  const r = width / 2 * scale;
29314
29353
  return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
@@ -29331,7 +29370,7 @@ var Outliner = class {
29331
29370
  this.opts = opts;
29332
29371
  this.out = out;
29333
29372
  this.pts = [];
29334
- this.pen = penPolygon(opts.width, opts.height);
29373
+ this.pen = opts.matrix && opts.deviceNib ? penPolygonMatrix(opts.width, opts.matrix) : penPolygon(opts.width, opts.height);
29335
29374
  this.n = this.pen.length;
29336
29375
  this.rr = opts.cap === "round" && opts.join === "round";
29337
29376
  this.originalRoundJoinSides = opts.join === "round" && opts.cap !== "flat";
@@ -29346,10 +29385,11 @@ var Outliner = class {
29346
29385
  const dx = dir ? dir[0] : b[0] - a[0];
29347
29386
  const dy = dir ? dir[1] : b[1] - a[1];
29348
29387
  const d = drawDir ?? [dx, dy];
29349
- const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height);
29388
+ const nibMatrix = this.opts.deviceNib ? this.opts.matrix : void 0;
29389
+ const [L, R] = drawVertices(this.pen, d[0], d[1], this.opts.width, this.opts.height, nibMatrix);
29350
29390
  const perpendicular = curve && drawDir ? drawDir : [dx, dy];
29351
- const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height);
29352
- return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29391
+ const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1], this.opts.height, nibMatrix ? this.pen : void 0);
29392
+ return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1], 1, this.opts.height, nibMatrix), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
29353
29393
  }
29354
29394
  push(p, v) {
29355
29395
  this.pts.push([p[0] + v[0], p[1] + v[1]]);
@@ -29462,7 +29502,7 @@ var Outliner = class {
29462
29502
  const sv = this.capSide(s, from);
29463
29503
  const ev = this.capSide(s, to);
29464
29504
  if (cap === "square") {
29465
- const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height);
29505
+ const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale, this.opts.height, this.opts.deviceNib ? this.opts.matrix : void 0);
29466
29506
  const e = start ? [-e0[0], -e0[1]] : e0;
29467
29507
  this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
29468
29508
  this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
@@ -29642,7 +29682,7 @@ var Outliner = class {
29642
29682
  this.flush();
29643
29683
  }
29644
29684
  };
29645
- function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric) {
29685
+ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors, metric, matrix) {
29646
29686
  const out = [];
29647
29687
  const dashes = [];
29648
29688
  for (let i = 0; i < pattern.length; i += 2) {
@@ -29662,8 +29702,9 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29662
29702
  const [x0, y0] = P[i];
29663
29703
  const [x1, y1] = P[i + 1];
29664
29704
  const dir = [x1 - x0, y1 - y0];
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]);
29705
+ const det = matrix ? matrix[0] * matrix[3] - matrix[1] * matrix[2] : 1;
29706
+ const real = matrix ? Math.hypot((matrix[3] * dir[0] - matrix[2] * dir[1]) / det, (-matrix[1] * dir[0] + matrix[0] * dir[1]) / det) : metric ? Math.hypot(dir[0] / metric[0], dir[1] / metric[1]) : Math.hypot(dir[0], dir[1]);
29707
+ const len = metric || matrix ? real : wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
29667
29708
  if (len === 0) {
29668
29709
  if (on && cur) {
29669
29710
  cur.pts.push(P[i + 1]);
@@ -29707,7 +29748,35 @@ function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors
29707
29748
  }
29708
29749
  return out;
29709
29750
  }
29751
+ function widenInLogicalSpace(path, opts, m) {
29752
+ const [a, b, c, d] = m;
29753
+ const det = a * d - b * c;
29754
+ const inverse = (x, y) => [(d * x - c * y) / det, (-b * x + a * y) / det];
29755
+ const logical = new GdiRasterPath();
29756
+ for (const fig of path.figures) {
29757
+ const pts = [];
29758
+ for (let i = 0; i + 1 < fig.pts.length; i += 2) {
29759
+ pts.push(...inverse(fig.pts[i], fig.pts[i + 1]));
29760
+ }
29761
+ const copy = { pts, closed: fig.closed, roundWiden: fig.roundWiden, curveSegs: fig.curveSegs };
29762
+ if (fig.tangents) {
29763
+ copy.tangents = new Map([...fig.tangents].map(([k, v]) => [k, inverse(v[0], v[1])]));
29764
+ }
29765
+ logical.figures.push(copy);
29766
+ }
29767
+ const outline = widenPath(logical, { ...opts, matrix: void 0, height: void 0 });
29768
+ return outline.map((poly) => {
29769
+ const out = [];
29770
+ for (let i = 0; i + 1 < poly.length; i += 2) {
29771
+ out.push(Math.round(a * poly[i] + c * poly[i + 1]), Math.round(b * poly[i] + d * poly[i + 1]));
29772
+ }
29773
+ return out;
29774
+ });
29775
+ }
29710
29776
  function widenPath(path, opts) {
29777
+ if (opts.matrix && !(opts.deviceNib && opts.join === "round")) {
29778
+ return widenInLogicalSpace(path, opts, opts.matrix);
29779
+ }
29711
29780
  const out = [];
29712
29781
  const dashed = !!opts.dashes && opts.dashes.length > 0;
29713
29782
  for (const fig of path.figures) {
@@ -29739,7 +29808,7 @@ function widenPath(path, opts) {
29739
29808
  const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.dashMetric ? opts.width / opts.dashMetric[0] : opts.width;
29740
29809
  const runTangents = closed ? [...dirs, void 0] : dirs;
29741
29810
  const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
29742
- for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric)) {
29811
+ for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors, opts.dashMetric, opts.deviceNib ? opts.matrix : void 0)) {
29743
29812
  const pts = [piece.pts[0]];
29744
29813
  const pdirs = [];
29745
29814
  const pdraws = [];
@@ -30007,8 +30076,24 @@ function penWidenOptions(rCtx, opts = {}) {
30007
30076
  const capBits = flags & 3840;
30008
30077
  const joinBits = flags & 61440;
30009
30078
  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;
30010
- const dashes = state.penExtended ? ellipse ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30079
+ const det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
30080
+ const rotatedOrSheared = Math.abs(matrix[1]) >= 1e-6 || Math.abs(matrix[2]) >= 1e-6;
30081
+ const quarterTurn = Math.abs(matrix[0]) < 1e-9 && Math.abs(matrix[3]) < 1e-9;
30082
+ const general = !rCtx.wholeDevicePixels && rotatedOrSheared && !quarterTurn && Math.abs(det) > 1e-9 && state.penWidth * Math.sqrt(Math.abs(det)) * 16 >= 1;
30083
+ const dashes = state.penExtended ? ellipse || general ? geometricStyle(flags, state.penWidth, state.penUserStyle, 1) : geometricStyle(flags, widthPx, state.penUserStyle, widthPx / (state.penWidth || 1)) : null;
30011
30084
  const dashMetric = ellipse && dashes ? [Math.abs(matrix[0]), Math.abs(matrix[3])] : void 0;
30085
+ if (general) {
30086
+ return {
30087
+ width: Math.round(state.penWidth * 16),
30088
+ matrix: [matrix[0], matrix[1], matrix[2], matrix[3]],
30089
+ deviceNib: true,
30090
+ cap: opts.roundPen || !state.penExtended || capBits === 0 ? "round" : capBits === 256 ? "square" : "flat",
30091
+ join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
30092
+ miterLimit: state.miterLimit ?? 10,
30093
+ dashes: dashes ? dashes.map((v) => v * 16) : null,
30094
+ shortenDashes: (flags & 15) !== 7
30095
+ };
30096
+ }
30012
30097
  return {
30013
30098
  width: Math.round((ellipse ? state.penWidth * Math.abs(matrix[0]) : widthPx) * 16),
30014
30099
  ...ellipse ? { height: Math.round(state.penWidth * Math.abs(matrix[3]) * 16) } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emf-converter",
3
- "version": "4.9.0",
3
+ "version": "4.11.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",