emf-converter 4.8.0 → 4.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/browser.js +114 -52
- package/dist/browser.mjs +114 -52
- package/dist/index.js +114 -52
- package/dist/index.mjs +114 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -217,7 +217,7 @@ Everything is measured against output painted by Windows itself; `src/gdi-parity
|
|
|
217
217
|
- **Colour adjustment and image effects**: all eleven EMF+ image effects are supported. Complete native tables cover every legal ColorCurve intensity. Deferred draws retain their effects. JPEG, GIF and TIFF have bundled decoders for environments without Canvas. HSL, tint, red-eye, blur, sharpen and GDI colour adjustment retain measured differences; see [the detailed limitations](docs/limitations.md) and the native fixture bounds.
|
|
218
218
|
- **Pen transforms**: EMF+ pen transforms (uniform, nonuniform and skewed) match GDI+ exactly on the 17 pen-transform fixtures, including dashes, which GDI+ lays out along the path in world space at the untransformed pen width. Native fixtures verify dashes under both uniform and non-uniform scales. GDI+ rejects singular pen transforms; the converter ignores such malformed transform data. Square, round, diamond and arrow anchor caps use their native shapes; the new centered-cap fixtures match every pixel with and without antialiasing.
|
|
219
219
|
- **Text**: ANSI, multi-string and small-text records now render; the Windows text fixtures retain a few glyph-edge differences and a `PolyTextOut` C1 control-glyph difference (under 0.1% of pixels; bounds in `src/emf-text-records.fixture.test.ts`). ANSI decoding uses the host's `TextDecoder` for common Windows code pages; Johab and OEM CP437 use bundled Windows mappings. Vertical `ETO_PDY` advances work with and without the `fonts` engine. Without `fonts`, SVG text measurements use deterministic estimates, so precise justification requires supplying the matching fonts.
|
|
220
|
-
- **Wide pens and paths**: flat-capped GDI pens 7 px and wider can differ by a few pixels at round joins, and dashed wide
|
|
220
|
+
- **Wide pens and paths**: flat-capped GDI pens 7 px and wider can differ by a few pixels at round joins, and dashed wide curves follow `WidenPath` (exact for round and flat caps at one logical unit per pixel; square caps differ slightly at path ends); at most 0.2% of pixels on the fixtures. `EMR_WIDENPATH` does not reproduce the extra inner join triangles GDI's own `WidenPath` emits (visible only when the widened outline is itself stroked). EMF+ 1-pixel antialiased lines can differ by one antialiasing sample at their ends, some closed widened outlines by one sample along an edge, and Inset or compound pens on closed figures are approximate.
|
|
221
221
|
- **GM_COMPATIBLE recordings**: EMF files do not record the graphics mode, and Windows plays RoundRect, Arc, Chord, Pie and null-pen Ellipse records back differently from how a GM_COMPATIBLE application drew them on screen; the converter follows Windows' playback.
|
|
222
222
|
- **Small EMF+ residuals**: rotated `HighQualityBicubic` `DrawImage` edge pixels (0.14%), one-level differences at exact half-level `Blend` knots, and a few pixels of a metafile nested in `DrawImage` under a scale.
|
|
223
223
|
- **WMF**: `PS_INSIDEFRAME` boxes can come out a pixel short at non-integer scales, right-to-left (`LAYOUT_RTL`) layouts differ by single pixels on mirrored diagonals, and metric map modes assume a 96 dpi reference device (Windows derives them from the physical display, so its own output varies per machine).
|
package/dist/browser.js
CHANGED
|
@@ -16403,8 +16403,8 @@ function midtoneGamma(t) {
|
|
|
16403
16403
|
low = high;
|
|
16404
16404
|
high = (high + 100) / 2;
|
|
16405
16405
|
}
|
|
16406
|
-
gamma = Math.abs(t) === 100 ? 10 : Math.min(10, gamma + (Math.abs(t) - low) / (high - low));
|
|
16407
|
-
return
|
|
16406
|
+
gamma = Math.abs(t) === 100 ? 10 : Math.min(10, truncF32(gamma + truncF32(truncF32(Math.abs(t) - low) / truncF32(high - low))));
|
|
16407
|
+
return t < 0 ? truncF32(gamma) : truncF32(1 / truncF32(gamma));
|
|
16408
16408
|
}
|
|
16409
16409
|
function brightnessContrastLut(brightness, contrast) {
|
|
16410
16410
|
const gain = contrast >= 100 ? 1e6 : contrast >= 0 ? 100 / (100 - contrast) : (100 + contrast) / 100;
|
|
@@ -16421,6 +16421,23 @@ function curveAdjustmentLut(adjustment, intensity) {
|
|
|
16421
16421
|
return nativeCurveLookup(adjustment, clamp(Math.trunc(intensity), min, max)).slice();
|
|
16422
16422
|
}
|
|
16423
16423
|
function levelsLut(highlight, midtone, shadow) {
|
|
16424
|
+
if (highlight !== shadow) {
|
|
16425
|
+
const forward = highlight > shadow;
|
|
16426
|
+
const lo = truncF32((forward ? shadow : highlight) * 255 / 100);
|
|
16427
|
+
const hi = truncF32((forward ? highlight : shadow) * 255 / 100);
|
|
16428
|
+
const scale = truncF32(1 / truncF32(hi - lo));
|
|
16429
|
+
const exponent2 = midtoneGamma(midtone);
|
|
16430
|
+
const lut = new Uint8Array(256);
|
|
16431
|
+
for (let v = 0; v < 256; v++) {
|
|
16432
|
+
let level = clamp(truncF32(truncF32(v - lo) * scale), 0, 1);
|
|
16433
|
+
if (midtone !== 0) {
|
|
16434
|
+
level = truncF32(level ** exponent2);
|
|
16435
|
+
}
|
|
16436
|
+
const out = forward ? truncF32(255 * level) : truncF32(255 - truncF32(255 * level));
|
|
16437
|
+
lut[v] = clamp(Math.floor(out + 0.5), 0, 255);
|
|
16438
|
+
}
|
|
16439
|
+
return lut;
|
|
16440
|
+
}
|
|
16424
16441
|
const base = shadow * 255 / 100 - (highlight === shadow && shadow < 50 ? 1 : 0);
|
|
16425
16442
|
const span = highlight === shadow ? 1 : (highlight - shadow) * 255 / 100;
|
|
16426
16443
|
const exponent = midtoneGamma(midtone);
|
|
@@ -16453,14 +16470,6 @@ function applyColorMatrix(src, m) {
|
|
|
16453
16470
|
}
|
|
16454
16471
|
return out;
|
|
16455
16472
|
}
|
|
16456
|
-
function hslToRgb(h, s, l) {
|
|
16457
|
-
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
16458
|
-
const hp = (h % 360 + 360) % 360 / 60;
|
|
16459
|
-
const x = c * (1 - Math.abs(hp % 2 - 1));
|
|
16460
|
-
const m = l - c / 2;
|
|
16461
|
-
const [r, g, b] = hp < 1 ? [c, x, 0] : hp < 2 ? [x, c, 0] : hp < 3 ? [0, c, x] : hp < 4 ? [0, x, c] : hp < 5 ? [x, 0, c] : [c, 0, x];
|
|
16462
|
-
return [r + m, g + m, b + m];
|
|
16463
|
-
}
|
|
16464
16473
|
var HUE_SEXTANT = 43;
|
|
16465
16474
|
var HUE_CIRCLE = 255;
|
|
16466
16475
|
function gdipHue(r, g, b) {
|
|
@@ -16483,29 +16492,30 @@ function gdipHue(r, g, b) {
|
|
|
16483
16492
|
function applyHueSaturationLightness(src, hue, saturation, lightness) {
|
|
16484
16493
|
const out = new Uint8ClampedArray(src);
|
|
16485
16494
|
const shift = Math.round(hue * HUE_CIRCLE / 360);
|
|
16486
|
-
const
|
|
16495
|
+
const satScale = 65536 + Math.floor(saturation * 65536 / 100);
|
|
16496
|
+
const lightOffset = Math.round(255 * Math.floor(lightness * 65536 / 100) / 65536);
|
|
16487
16497
|
for (let i = 0; i < src.length; i += 4) {
|
|
16488
16498
|
const r = src[i];
|
|
16489
16499
|
const g = src[i + 1];
|
|
16490
16500
|
const b = src[i + 2];
|
|
16491
16501
|
const max = Math.max(r, g, b);
|
|
16492
16502
|
const min = Math.min(r, g, b);
|
|
16493
|
-
const l = clamp(
|
|
16503
|
+
const l = clamp((max + min >> 1) + lightOffset, 0, 255);
|
|
16494
16504
|
if (max === min) {
|
|
16495
16505
|
out[i] = out[i + 1] = out[i + 2] = l;
|
|
16496
16506
|
continue;
|
|
16497
16507
|
}
|
|
16498
16508
|
const sum = max + min;
|
|
16499
|
-
const
|
|
16500
|
-
const hi = l <= 127 ? l * (
|
|
16501
|
-
const m1 =
|
|
16502
|
-
const m2 =
|
|
16509
|
+
const sat2 = clamp(Math.round(Math.floor((max - min) * 255 / (sum <= 255 ? sum : 510 - sum)) * satScale / 65536), 0, 255);
|
|
16510
|
+
const hi = l <= 127 ? Math.floor(l * (255 + sat2) / 255) : l + sat2 - Math.floor(l * sat2 / 255);
|
|
16511
|
+
const m1 = 2 * l - hi;
|
|
16512
|
+
const m2 = hi;
|
|
16503
16513
|
const index = ((gdipHue(r, g, b) + shift) % HUE_CIRCLE + HUE_CIRCLE) % HUE_CIRCLE;
|
|
16504
16514
|
const q = index + Math.floor((index + 41) / 85);
|
|
16505
16515
|
const sextant = Math.min(5, Math.floor(q / HUE_SEXTANT));
|
|
16506
|
-
const
|
|
16507
|
-
const up =
|
|
16508
|
-
const down =
|
|
16516
|
+
const position = q - sextant * HUE_SEXTANT;
|
|
16517
|
+
const up = m1 + Math.floor((m2 - m1) * position / HUE_SEXTANT);
|
|
16518
|
+
const down = m1 + Math.floor((m2 - m1) * (HUE_SEXTANT - position) / HUE_SEXTANT);
|
|
16509
16519
|
const [nr, ng, nb] = [
|
|
16510
16520
|
[m2, up, m1],
|
|
16511
16521
|
[down, m2, m1],
|
|
@@ -16520,28 +16530,40 @@ function applyHueSaturationLightness(src, hue, saturation, lightness) {
|
|
|
16520
16530
|
}
|
|
16521
16531
|
return out;
|
|
16522
16532
|
}
|
|
16523
|
-
var LUMA_709 = [0.2126, 0.7152, 0.0722];
|
|
16524
|
-
var TINT_CHROMA_SCALE = 0.985;
|
|
16525
16533
|
function applyTint(src, hue, amount) {
|
|
16526
16534
|
const index = (Math.round(hue * 255 / 360) + 256) % 256;
|
|
16527
16535
|
const q = (index + Math.floor((index + 41) / 85)) % 258;
|
|
16528
|
-
const
|
|
16529
|
-
const
|
|
16530
|
-
const
|
|
16531
|
-
const
|
|
16536
|
+
const sextant = Math.min(5, Math.floor(q / HUE_SEXTANT));
|
|
16537
|
+
const position = q - sextant * HUE_SEXTANT;
|
|
16538
|
+
const up = Math.floor(TINT_FULL * position / HUE_SEXTANT);
|
|
16539
|
+
const down = Math.floor(TINT_FULL * (HUE_SEXTANT - position) / HUE_SEXTANT);
|
|
16540
|
+
const [tr, tg, tb] = [
|
|
16541
|
+
[TINT_FULL, up, 0],
|
|
16542
|
+
[down, TINT_FULL, 0],
|
|
16543
|
+
[0, TINT_FULL, up],
|
|
16544
|
+
[0, down, TINT_FULL],
|
|
16545
|
+
[up, 0, TINT_FULL],
|
|
16546
|
+
[TINT_FULL, 0, down]
|
|
16547
|
+
][sextant];
|
|
16548
|
+
const weight = Math.sign(amount) * Math.floor((255 * Math.abs(amount) + 49) / 100);
|
|
16549
|
+
const original = 255 - weight;
|
|
16532
16550
|
const out = new Uint8ClampedArray(src);
|
|
16533
16551
|
for (let i = 0; i < src.length; i += 4) {
|
|
16534
16552
|
const r = src[i];
|
|
16535
16553
|
const g = src[i + 1];
|
|
16536
16554
|
const b = src[i + 2];
|
|
16537
|
-
const
|
|
16538
|
-
const
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16555
|
+
const u = weight * Math.max(r, g, b) >> 8;
|
|
16556
|
+
const x0 = original * r + tr * u;
|
|
16557
|
+
const x1 = original * g + tg * u;
|
|
16558
|
+
const x2 = original * b + tb * u;
|
|
16559
|
+
const base = 54 * r + 183 * g + 19 * b - (54 * (x0 >> 8) + 183 * (x1 >> 8) + 19 * (x2 >> 8));
|
|
16560
|
+
out[i] = base + x0 >> 8;
|
|
16561
|
+
out[i + 1] = base + x1 >> 8;
|
|
16562
|
+
out[i + 2] = base + x2 >> 8;
|
|
16542
16563
|
}
|
|
16543
16564
|
return out;
|
|
16544
16565
|
}
|
|
16566
|
+
var TINT_FULL = 254;
|
|
16545
16567
|
function applyRedEyeCorrection(src, width, height, areas) {
|
|
16546
16568
|
const out = new Uint8ClampedArray(src);
|
|
16547
16569
|
for (const a of areas) {
|
|
@@ -20541,8 +20563,7 @@ function resampleImage(rgba, width, height, spec, surface) {
|
|
|
20541
20563
|
const axisAligned = m[1] === 0 && m[2] === 0;
|
|
20542
20564
|
if (hq && axisAligned) {
|
|
20543
20565
|
const ox = m[0] * spec.srcX + m[4];
|
|
20544
|
-
|
|
20545
|
-
m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5] + mirroredOrigin(oy) - oy];
|
|
20566
|
+
m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5]];
|
|
20546
20567
|
}
|
|
20547
20568
|
const inv2 = invert2(m);
|
|
20548
20569
|
if (!inv2) {
|
|
@@ -23355,6 +23376,21 @@ var nestedReplayer = null;
|
|
|
23355
23376
|
function registerNestedMetafileReplayer(fn) {
|
|
23356
23377
|
nestedReplayer = fn;
|
|
23357
23378
|
}
|
|
23379
|
+
function inclusiveNestedMapping(toDevice, srcX, srcY, srcW, srcH) {
|
|
23380
|
+
const [a, b, c, d, e, f] = toDevice;
|
|
23381
|
+
const lengthU = Math.hypot(a, b) * srcW;
|
|
23382
|
+
const lengthV = Math.hypot(c, d) * srcH;
|
|
23383
|
+
if (!(srcW > 1 && srcH > 1 && lengthU > 1 && lengthV > 1)) {
|
|
23384
|
+
return toDevice;
|
|
23385
|
+
}
|
|
23386
|
+
const ku = (lengthU - 1) / lengthU * (srcW / (srcW - 1));
|
|
23387
|
+
const kv = (lengthV - 1) / lengthV * (srcH / (srcH - 1));
|
|
23388
|
+
const na = a * ku;
|
|
23389
|
+
const nb = b * ku;
|
|
23390
|
+
const nc = c * kv;
|
|
23391
|
+
const nd = d * kv;
|
|
23392
|
+
return [na, nb, nc, nd, e + (a - na) * srcX + (c - nc) * srcY, f + (b - nb) * srcX + (d - nd) * srcY];
|
|
23393
|
+
}
|
|
23358
23394
|
function drawNestedMetafile(rCtx, img, cached, source) {
|
|
23359
23395
|
const depth = rCtx.nestingDepth ?? 0;
|
|
23360
23396
|
if (!nestedReplayer || !source || !img.data || source.unit !== UNIT_PIXEL || depth >= MAX_NESTED_METAFILE_DEPTH) {
|
|
@@ -23368,9 +23404,12 @@ function drawNestedMetafile(rCtx, img, cached, source) {
|
|
|
23368
23404
|
if (!size) {
|
|
23369
23405
|
return false;
|
|
23370
23406
|
}
|
|
23371
|
-
const toCanvas =
|
|
23372
|
-
|
|
23373
|
-
|
|
23407
|
+
const toCanvas = inclusiveNestedMapping(
|
|
23408
|
+
mulMatrix(plusWorldMatrix(rCtx), source.toWorld(srcX, srcY, srcW, srcH)),
|
|
23409
|
+
srcX,
|
|
23410
|
+
srcY,
|
|
23411
|
+
srcW,
|
|
23412
|
+
srcH
|
|
23374
23413
|
);
|
|
23375
23414
|
const bytes = img.data.slice(0);
|
|
23376
23415
|
const caches = cached && cached.kind === "metafile" ? cached.caches : void 0;
|
|
@@ -29189,9 +29228,9 @@ function perpendicularVectors(width, dx0, dy0) {
|
|
|
29189
29228
|
const vx = rounded[0], vy = rounded[1];
|
|
29190
29229
|
return { v: flip ? [-vx, -vy] : [vx, vy], ray: flip ? [-x, -y] : [x, y] };
|
|
29191
29230
|
}
|
|
29192
|
-
function squareExtension(width, dx, dy) {
|
|
29231
|
+
function squareExtension(width, dx, dy, scale = 1) {
|
|
29193
29232
|
const len = Math.hypot(dx, dy);
|
|
29194
|
-
const r = width / 2;
|
|
29233
|
+
const r = width / 2 * scale;
|
|
29195
29234
|
return [Math.floor(dx / len * r + 0.5), Math.floor(dy / len * r + 0.5)];
|
|
29196
29235
|
}
|
|
29197
29236
|
function turnSign(ax, ay, bx, by) {
|
|
@@ -29230,7 +29269,7 @@ var Outliner = class {
|
|
|
29230
29269
|
const [L, R] = drawVertices(this.pen, d[0], d[1]);
|
|
29231
29270
|
const perpendicular = curve && drawDir ? drawDir : [dx, dy];
|
|
29232
29271
|
const vectors = perpendicularVectors(this.opts.width, perpendicular[0], perpendicular[1]);
|
|
29233
|
-
return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1]), curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
|
|
29272
|
+
return { dx, dy, L, R, v: vectors.v, vRaw: vectors.ray, e: squareExtension(this.opts.width, perpendicular[0], perpendicular[1]), pe: [perpendicular[0], perpendicular[1]], curveEnd: !!drawDir, tangentLength: drawDir ? drawDir[0] * drawDir[0] + drawDir[1] * drawDir[1] : 0, curve };
|
|
29234
29273
|
}
|
|
29235
29274
|
push(p, v) {
|
|
29236
29275
|
this.pts.push([p[0] + v[0], p[1] + v[1]]);
|
|
@@ -29325,7 +29364,7 @@ var Outliner = class {
|
|
|
29325
29364
|
return side === "R" ? s.v : [-s.v[0], -s.v[1]];
|
|
29326
29365
|
}
|
|
29327
29366
|
/** A cap at `p` from the `from` side of `s` round to the other side (`start`: around the back). */
|
|
29328
|
-
cap(p, s, start) {
|
|
29367
|
+
cap(p, s, start, scale = 1) {
|
|
29329
29368
|
const from = start ? "L" : "R";
|
|
29330
29369
|
const to = start ? "R" : "L";
|
|
29331
29370
|
const { cap } = this.opts;
|
|
@@ -29343,7 +29382,8 @@ var Outliner = class {
|
|
|
29343
29382
|
const sv = this.capSide(s, from);
|
|
29344
29383
|
const ev = this.capSide(s, to);
|
|
29345
29384
|
if (cap === "square") {
|
|
29346
|
-
const
|
|
29385
|
+
const e0 = scale === 1 ? s.e : squareExtension(this.opts.width, s.pe[0], s.pe[1], scale);
|
|
29386
|
+
const e = start ? [-e0[0], -e0[1]] : e0;
|
|
29347
29387
|
this.push(p, [sv[0] + e[0], sv[1] + e[1]]);
|
|
29348
29388
|
this.push(p, [ev[0] + e[0], ev[1] + e[1]]);
|
|
29349
29389
|
} else {
|
|
@@ -29439,7 +29479,7 @@ var Outliner = class {
|
|
|
29439
29479
|
* lets a single point stand for a zero-length dash along `dirs[0]`;
|
|
29440
29480
|
* `draws` (curve end tangents) picks draw vertices only.
|
|
29441
29481
|
*/
|
|
29442
|
-
open(P, dirs, draws, curves) {
|
|
29482
|
+
open(P, dirs, draws, curves, startScale = 1, endScale = 1) {
|
|
29443
29483
|
if (P.length < 2 && !dirs?.[0]) {
|
|
29444
29484
|
this.dot(P[0]);
|
|
29445
29485
|
return;
|
|
@@ -29450,12 +29490,12 @@ var Outliner = class {
|
|
|
29450
29490
|
}
|
|
29451
29491
|
if (segs2.length === 0) {
|
|
29452
29492
|
const s = this.seg(P[0], P[0], dirs?.[0], draws?.[0], curves?.[0]);
|
|
29453
|
-
this.cap(P[0], s, true);
|
|
29454
|
-
this.cap(P[0], s, false);
|
|
29493
|
+
this.cap(P[0], s, true, startScale);
|
|
29494
|
+
this.cap(P[0], s, false, endScale);
|
|
29455
29495
|
this.flush();
|
|
29456
29496
|
return;
|
|
29457
29497
|
}
|
|
29458
|
-
this.cap(P[0], segs2[0], true);
|
|
29498
|
+
this.cap(P[0], segs2[0], true, startScale);
|
|
29459
29499
|
for (let i = 0; i + 1 < segs2.length; i++) {
|
|
29460
29500
|
const s = segs2[i];
|
|
29461
29501
|
const t = segs2[i + 1];
|
|
@@ -29466,7 +29506,7 @@ var Outliner = class {
|
|
|
29466
29506
|
this.join(P[i + 1], s, t, "R", tr < 0);
|
|
29467
29507
|
}
|
|
29468
29508
|
}
|
|
29469
|
-
this.cap(P[P.length - 1], segs2[segs2.length - 1], false);
|
|
29509
|
+
this.cap(P[P.length - 1], segs2[segs2.length - 1], false, endScale);
|
|
29470
29510
|
for (let i = segs2.length - 1; i > 0; i--) {
|
|
29471
29511
|
const s = segs2[i];
|
|
29472
29512
|
const t = segs2[i - 1];
|
|
@@ -29522,7 +29562,7 @@ var Outliner = class {
|
|
|
29522
29562
|
this.flush();
|
|
29523
29563
|
}
|
|
29524
29564
|
};
|
|
29525
|
-
function dashPieces(P, tangents, pattern, shorten) {
|
|
29565
|
+
function dashPieces(P, tangents, curveFlags, pattern, shorten, wholePixelVectors) {
|
|
29526
29566
|
const out = [];
|
|
29527
29567
|
const dashes = [];
|
|
29528
29568
|
for (let i = 0; i < pattern.length; i += 2) {
|
|
@@ -29537,12 +29577,22 @@ function dashPieces(P, tangents, pattern, shorten) {
|
|
|
29537
29577
|
let idx = 0;
|
|
29538
29578
|
let left = dashes[0];
|
|
29539
29579
|
let on = true;
|
|
29540
|
-
let cur = { pts: [P[0]], dirs: [], draws: [] };
|
|
29580
|
+
let cur = { pts: [P[0]], dirs: [], draws: [], curves: [], startScale: 1, endScale: 1 };
|
|
29541
29581
|
for (let i = 0; i + 1 < P.length; i++) {
|
|
29542
29582
|
const [x0, y0] = P[i];
|
|
29543
29583
|
const [x1, y1] = P[i + 1];
|
|
29544
29584
|
const dir = [x1 - x0, y1 - y0];
|
|
29545
|
-
const
|
|
29585
|
+
const real = Math.hypot(dir[0], dir[1]);
|
|
29586
|
+
const len = wholePixelVectors ? Math.hypot(Math.floor(dir[0] / 16), Math.floor(dir[1] / 16)) * 16 : Math.hypot(dir[0], dir[1]);
|
|
29587
|
+
if (len === 0) {
|
|
29588
|
+
if (on && cur) {
|
|
29589
|
+
cur.pts.push(P[i + 1]);
|
|
29590
|
+
cur.dirs.push(dir);
|
|
29591
|
+
cur.draws.push(tangents[i]);
|
|
29592
|
+
cur.curves.push(curveFlags[i]);
|
|
29593
|
+
}
|
|
29594
|
+
continue;
|
|
29595
|
+
}
|
|
29546
29596
|
let t = 0;
|
|
29547
29597
|
while (len - t > left || left === 0 && on) {
|
|
29548
29598
|
t += left;
|
|
@@ -29551,10 +29601,12 @@ function dashPieces(P, tangents, pattern, shorten) {
|
|
|
29551
29601
|
cur.pts.push(q);
|
|
29552
29602
|
cur.dirs.push(dir);
|
|
29553
29603
|
cur.draws.push(tangents[i]);
|
|
29604
|
+
cur.curves.push(curveFlags[i]);
|
|
29605
|
+
cur.endScale = cur.pts[0] === P[0] && q[0] === P[0][0] && q[1] === P[0][1] ? 1 : real / len;
|
|
29554
29606
|
out.push(cur);
|
|
29555
29607
|
cur = null;
|
|
29556
29608
|
} else {
|
|
29557
|
-
cur = { pts: [q], dirs: [], draws: [] };
|
|
29609
|
+
cur = { pts: [q], dirs: [], draws: [], curves: [], startScale: real / len, endScale: 1 };
|
|
29558
29610
|
}
|
|
29559
29611
|
on = !on;
|
|
29560
29612
|
idx = (idx + 1) % dashes.length;
|
|
@@ -29565,9 +29617,12 @@ function dashPieces(P, tangents, pattern, shorten) {
|
|
|
29565
29617
|
cur.pts.push(P[i + 1]);
|
|
29566
29618
|
cur.dirs.push(dir);
|
|
29567
29619
|
cur.draws.push(tangents[i]);
|
|
29620
|
+
cur.curves.push(curveFlags[i]);
|
|
29621
|
+
cur.endScale = real / len;
|
|
29568
29622
|
}
|
|
29569
29623
|
}
|
|
29570
29624
|
if (on && cur && cur.dirs.length > 0) {
|
|
29625
|
+
cur.endScale = 1;
|
|
29571
29626
|
out.push(cur);
|
|
29572
29627
|
}
|
|
29573
29628
|
return out;
|
|
@@ -29602,10 +29657,13 @@ function widenPath(path, opts) {
|
|
|
29602
29657
|
if (dashed) {
|
|
29603
29658
|
const run = closed ? [...P, P[0]] : P;
|
|
29604
29659
|
const shorten = opts.cap === "flat" || opts.shortenDashes === false ? 0 : opts.width;
|
|
29605
|
-
|
|
29660
|
+
const runTangents = closed ? [...dirs, void 0] : dirs;
|
|
29661
|
+
const runCurves = closed ? [...curves, !!fig.roundWiden] : curves;
|
|
29662
|
+
for (const piece of dashPieces(run, runTangents, runCurves, opts.dashes, shorten, !!opts.wholePixelDashVectors)) {
|
|
29606
29663
|
const pts = [piece.pts[0]];
|
|
29607
29664
|
const pdirs = [];
|
|
29608
29665
|
const pdraws = [];
|
|
29666
|
+
const pcurves = [];
|
|
29609
29667
|
for (let i = 1; i < piece.pts.length; i++) {
|
|
29610
29668
|
const q = piece.pts[i];
|
|
29611
29669
|
const last = pts[pts.length - 1];
|
|
@@ -29613,9 +29671,10 @@ function widenPath(path, opts) {
|
|
|
29613
29671
|
pts.push(q);
|
|
29614
29672
|
pdirs.push(piece.dirs[i - 1]);
|
|
29615
29673
|
pdraws.push(piece.draws[i - 1]);
|
|
29674
|
+
pcurves.push(piece.curves[i - 1]);
|
|
29616
29675
|
}
|
|
29617
29676
|
}
|
|
29618
|
-
outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]],
|
|
29677
|
+
outliner.open(pts, pdirs.length > 0 ? pdirs : [piece.dirs[0]], pdirs.length > 0 ? pdraws : [piece.draws[0]], pdirs.length > 0 ? pcurves : [piece.curves[0]], piece.startScale, piece.endScale);
|
|
29619
29678
|
}
|
|
29620
29679
|
} else if (closed && P.length >= 3) {
|
|
29621
29680
|
outliner.closed(P, dirs, curves);
|
|
@@ -29823,7 +29882,10 @@ function penWidenOptions(rCtx, opts = {}) {
|
|
|
29823
29882
|
join: opts.roundPen ? "round" : opts.rectangle && !state.penExtended ? "miter" : !state.penExtended || joinBits === 0 ? "round" : joinBits === 4096 ? "bevel" : "miter",
|
|
29824
29883
|
miterLimit: state.miterLimit ?? 10,
|
|
29825
29884
|
dashes: dashes ? dashes.map((v) => v * 16) : null,
|
|
29826
|
-
shortenDashes: (flags & 15) !== 7
|
|
29885
|
+
shortenDashes: (flags & 15) !== 7,
|
|
29886
|
+
// One logical unit per device pixel, unrotated: GDI measures dash
|
|
29887
|
+
// segments in whole pixels.
|
|
29888
|
+
wholePixelDashVectors: Math.abs(matrix[0] - 1) < 1e-6 && Math.abs(matrix[3] - 1) < 1e-6 && Math.abs(matrix[1]) < 1e-6 && Math.abs(matrix[2]) < 1e-6
|
|
29827
29889
|
};
|
|
29828
29890
|
}
|
|
29829
29891
|
function hatchBackgroundMask(hatch) {
|