emf-converter 4.8.3 → 4.8.5
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 +244 -169
- package/dist/browser.mjs +244 -169
- package/dist/index.js +244 -169
- package/dist/index.mjs +244 -169
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -214,7 +214,7 @@ Everything below is verified against output painted by Windows itself; `src/gdi-
|
|
|
214
214
|
|
|
215
215
|
Everything is measured against output painted by Windows itself; `src/gdi-parity.fixture.test.ts` holds the exact per-fixture bounds. Open work items are tracked in [docs/outstanding-work.md](docs/outstanding-work.md).
|
|
216
216
|
|
|
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
|
|
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. Blur and sharpen are exact; HSL, tint, red-eye 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
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.
|
package/dist/browser.js
CHANGED
|
@@ -11706,6 +11706,11 @@ function ellipsePoints(box, cwControls) {
|
|
|
11706
11706
|
P(hCtl, full);
|
|
11707
11707
|
P(full, rightLower);
|
|
11708
11708
|
P(full, vMidHi);
|
|
11709
|
+
if (box.halfX) {
|
|
11710
|
+
for (const k of [0, 1, 2, 3, 4, 5, 12]) {
|
|
11711
|
+
out[2 * k]++;
|
|
11712
|
+
}
|
|
11713
|
+
}
|
|
11709
11714
|
return out;
|
|
11710
11715
|
}
|
|
11711
11716
|
function ellipseBeziers(l, t, r, b) {
|
|
@@ -11775,76 +11780,15 @@ function roundRectCorners(l, t, r, b, cw, ch, compatible = false, clockwise = fa
|
|
|
11775
11780
|
];
|
|
11776
11781
|
}
|
|
11777
11782
|
var TRIG_STEP = 2 * Math.PI / 128;
|
|
11778
|
-
var
|
|
11779
|
-
|
|
11780
|
-
0.99879566,
|
|
11781
|
-
0.99518639,
|
|
11782
|
-
0.98917961,
|
|
11783
|
-
0.98079146,
|
|
11784
|
-
0.97003981,
|
|
11785
|
-
0.95695228,
|
|
11786
|
-
0.94155978,
|
|
11787
|
-
0.92389844,
|
|
11788
|
-
0.90401145,
|
|
11789
|
-
0.88194619,
|
|
11790
|
-
0.85775575,
|
|
11791
|
-
0.83149879,
|
|
11792
|
-
0.80323775,
|
|
11793
|
-
0.77303903,
|
|
11794
|
-
0.74098864,
|
|
11795
|
-
0.70710648,
|
|
11796
|
-
0.67151859,
|
|
11797
|
-
0.63435836,
|
|
11798
|
-
0.59565849,
|
|
11799
|
-
0.55552672,
|
|
11800
|
-
0.51405765,
|
|
11801
|
-
0.47135039,
|
|
11802
|
-
0.42750875,
|
|
11803
|
-
0.38263811,
|
|
11804
|
-
0.33684632,
|
|
11805
|
-
0.29024443,
|
|
11806
|
-
0.24294646,
|
|
11807
|
-
0.19505974,
|
|
11808
|
-
0.14670808,
|
|
11809
|
-
0.0980012,
|
|
11810
|
-
0.04906089,
|
|
11811
|
-
0
|
|
11812
|
-
];
|
|
11813
|
-
var TRIG_TABLE = (() => {
|
|
11814
|
-
const cos = [];
|
|
11815
|
-
const sin = [];
|
|
11816
|
-
for (let k = 0; k <= 128; k++) {
|
|
11817
|
-
const q = k >> 5;
|
|
11818
|
-
const i = k & 31;
|
|
11819
|
-
const c = TRIG_NODES[i];
|
|
11820
|
-
const s = TRIG_NODES[32 - i];
|
|
11821
|
-
if (k === 128) {
|
|
11822
|
-
cos.push(1);
|
|
11823
|
-
sin.push(0);
|
|
11824
|
-
continue;
|
|
11825
|
-
}
|
|
11826
|
-
cos.push([c, -s, -c, s][q]);
|
|
11827
|
-
sin.push([s, c, -s, -c][q]);
|
|
11828
|
-
}
|
|
11829
|
-
return { cos, sin };
|
|
11830
|
-
})();
|
|
11831
|
-
function tableTrig(table) {
|
|
11832
|
-
return (a) => {
|
|
11833
|
-
let b = a % (2 * Math.PI);
|
|
11834
|
-
if (b < 0) {
|
|
11835
|
-
b += 2 * Math.PI;
|
|
11836
|
-
}
|
|
11837
|
-
const x = b / TRIG_STEP;
|
|
11838
|
-
const i = Math.min(127, Math.floor(x));
|
|
11839
|
-
const f = x - i;
|
|
11840
|
-
return table[i] * (1 - f) + table[i + 1] * f;
|
|
11841
|
-
};
|
|
11842
|
-
}
|
|
11843
|
-
var tableCos = tableTrig(TRIG_TABLE.cos);
|
|
11844
|
-
var tableSin = tableTrig(TRIG_TABLE.sin);
|
|
11783
|
+
var tableCos = (angle) => polygonTrig(angle)[0];
|
|
11784
|
+
var tableSin = (angle) => polygonTrig(angle)[1];
|
|
11845
11785
|
function angleArcPieces(startDeg, sweepDeg) {
|
|
11846
11786
|
const out = [];
|
|
11847
11787
|
const arc = (from, to) => {
|
|
11788
|
+
if (Math.abs(to - from) < 90) {
|
|
11789
|
+
out.push({ from, to, first: true });
|
|
11790
|
+
return;
|
|
11791
|
+
}
|
|
11848
11792
|
const lo = Math.min(from, to);
|
|
11849
11793
|
const hi = Math.max(from, to);
|
|
11850
11794
|
const pieces = Math.floor(hi / 90) - Math.floor(lo / 90) + 1;
|
|
@@ -11893,7 +11837,8 @@ function angleArcFix(box, startDeg, sweepDeg) {
|
|
|
11893
11837
|
const E = ellipseBeziers(l, t, l + w, t + h);
|
|
11894
11838
|
const Ecw = clockwiseEllipseBeziersBox(axisBox(l, t, l + w, t + h));
|
|
11895
11839
|
const start = startDeg * Math.PI / 180;
|
|
11896
|
-
const
|
|
11840
|
+
const startUnit = Math.abs(sweepDeg) <= 3 ? [Math.cos(start), Math.sin(start)] : polygonTrig(start);
|
|
11841
|
+
const out = [Math.round(cx + w / 2 * startUnit[0]), Math.round(cy - h / 2 * startUnit[1])];
|
|
11897
11842
|
for (const p of angleArcPieces(startDeg, sweepDeg)) {
|
|
11898
11843
|
const span = p.to - p.from;
|
|
11899
11844
|
if (!p.first && Math.abs(span) === 90 && p.from % 90 === 0) {
|
|
@@ -11906,43 +11851,80 @@ function angleArcFix(box, startDeg, sweepDeg) {
|
|
|
11906
11851
|
}
|
|
11907
11852
|
continue;
|
|
11908
11853
|
}
|
|
11909
|
-
|
|
11910
|
-
|
|
11854
|
+
const piece = unitPiece(p.from * Math.PI / 180, p.to * Math.PI / 180, Math.abs(sweepDeg) <= 3);
|
|
11855
|
+
for (let i = 0; i < 6; i += 2) {
|
|
11856
|
+
out.push(Math.round(cx + w / 2 * piece.ctrl[i]), Math.round(cy - h / 2 * piece.ctrl[i + 1]));
|
|
11911
11857
|
}
|
|
11912
11858
|
}
|
|
11913
11859
|
return out;
|
|
11914
11860
|
}
|
|
11915
11861
|
var SMALL_SWEEP = 3 * Math.PI / 180;
|
|
11916
|
-
|
|
11917
|
-
const
|
|
11918
|
-
const
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
let
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11862
|
+
var POLYGON_NODES = (() => {
|
|
11863
|
+
const cos = [];
|
|
11864
|
+
const sin = [];
|
|
11865
|
+
for (let k = 0; k <= 129; k++) {
|
|
11866
|
+
cos.push(Math.cos(k * TRIG_STEP));
|
|
11867
|
+
sin.push(Math.sin(k * TRIG_STEP));
|
|
11868
|
+
}
|
|
11869
|
+
for (let k = 0; k <= 128; k += 32) {
|
|
11870
|
+
cos[k] = [1, 0, -1, 0, 1][k / 32];
|
|
11871
|
+
sin[k] = [0, 1, 0, -1, 0][k / 32];
|
|
11872
|
+
}
|
|
11873
|
+
return { cos, sin };
|
|
11874
|
+
})();
|
|
11875
|
+
function polygonTrig(angle) {
|
|
11876
|
+
let b = angle % (2 * Math.PI);
|
|
11877
|
+
if (b < 0) {
|
|
11878
|
+
b += 2 * Math.PI;
|
|
11879
|
+
}
|
|
11880
|
+
const x = b / TRIG_STEP;
|
|
11881
|
+
const i = Math.min(127, Math.floor(x));
|
|
11882
|
+
const f = x - i;
|
|
11883
|
+
return [
|
|
11884
|
+
POLYGON_NODES.cos[i] * (1 - f) + POLYGON_NODES.cos[i + 1] * f,
|
|
11885
|
+
POLYGON_NODES.sin[i] * (1 - f) + POLYGON_NODES.sin[i + 1] * f
|
|
11886
|
+
];
|
|
11887
|
+
}
|
|
11888
|
+
var ATAN_KNOTS = Array.from({ length: 33 }, (_, j) => Math.atan(j / 32));
|
|
11889
|
+
function interpolatedAtan(t) {
|
|
11890
|
+
const x = t * 32;
|
|
11891
|
+
const j = Math.min(31, Math.floor(x));
|
|
11892
|
+
return ATAN_KNOTS[j] + (ATAN_KNOTS[j + 1] - ATAN_KNOTS[j]) * (x - j);
|
|
11893
|
+
}
|
|
11894
|
+
function approximateArcAngle(x, y) {
|
|
11895
|
+
const ax = Math.abs(x);
|
|
11896
|
+
const ay = Math.abs(y);
|
|
11897
|
+
if (ax === 0 && ay === 0) {
|
|
11898
|
+
return 0;
|
|
11899
|
+
}
|
|
11900
|
+
const a = ay <= ax ? interpolatedAtan(ay / ax) : Math.PI / 2 - interpolatedAtan(ax / ay);
|
|
11901
|
+
if (x >= 0) {
|
|
11902
|
+
return y >= 0 ? a : 2 * Math.PI - a;
|
|
11903
|
+
}
|
|
11904
|
+
return y >= 0 ? Math.PI - a : Math.PI + a;
|
|
11905
|
+
}
|
|
11906
|
+
function unitPiece(from, to, small) {
|
|
11907
|
+
const trig = small ? (a) => [Math.cos(a), Math.sin(a)] : polygonTrig;
|
|
11908
|
+
const p0 = trig(from);
|
|
11909
|
+
const p3 = trig(to);
|
|
11910
|
+
const det = p0[0] * p3[1] - p0[1] * p3[0];
|
|
11911
|
+
let ctrl;
|
|
11912
|
+
if (Math.abs(det) < 1e-12) {
|
|
11913
|
+
ctrl = [p0[0], p0[1], p3[0], p3[1], p3[0], p3[1]];
|
|
11928
11914
|
} else {
|
|
11929
|
-
const
|
|
11930
|
-
const
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
free: point,
|
|
11943
|
-
cAnchor: [anchor[0] + kappa * (X[0] - anchor[0]), anchor[1] + kappa * (X[1] - anchor[1])],
|
|
11944
|
-
cFree: [point[0] + kappa * (X[0] - point[0]), point[1] + kappa * (X[1] - point[1])]
|
|
11945
|
-
};
|
|
11915
|
+
const X = [(p3[1] - p0[1]) / det, (p0[0] - p3[0]) / det];
|
|
11916
|
+
const c = polygonTrig(Math.abs(to - from) / 2)[0];
|
|
11917
|
+
const kappa = 4 / 3 * c / (1 + c);
|
|
11918
|
+
ctrl = [
|
|
11919
|
+
p0[0] + kappa * (X[0] - p0[0]),
|
|
11920
|
+
p0[1] + kappa * (X[1] - p0[1]),
|
|
11921
|
+
p3[0] + kappa * (X[0] - p3[0]),
|
|
11922
|
+
p3[1] + kappa * (X[1] - p3[1]),
|
|
11923
|
+
p3[0],
|
|
11924
|
+
p3[1]
|
|
11925
|
+
];
|
|
11926
|
+
}
|
|
11927
|
+
return { start: p0, ctrl };
|
|
11946
11928
|
}
|
|
11947
11929
|
function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
|
|
11948
11930
|
const w = r - l;
|
|
@@ -11954,24 +11936,30 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
|
|
|
11954
11936
|
const cy = t + Math.ceil(h / 2);
|
|
11955
11937
|
const tcx = (l + r) / 2;
|
|
11956
11938
|
const tcy = (t + b) / 2;
|
|
11957
|
-
const angle = (x, y) =>
|
|
11939
|
+
const angle = (x, y) => approximateArcAngle((x - tcx) / (w / 2 || 1), -(y - tcy) / (h / 2 || 1));
|
|
11958
11940
|
const a0 = angle(xs, ys);
|
|
11959
11941
|
let a1 = angle(xe, ye);
|
|
11942
|
+
const small = a1 !== a0 && Math.abs(a1 - a0) <= SMALL_SWEEP;
|
|
11960
11943
|
const s = clockwise ? -1 : 1;
|
|
11961
11944
|
if (s > 0) {
|
|
11962
11945
|
while (a1 <= a0) a1 += 2 * Math.PI;
|
|
11963
11946
|
} else {
|
|
11964
11947
|
while (a1 >= a0) a1 -= 2 * Math.PI;
|
|
11965
11948
|
}
|
|
11966
|
-
const px = (
|
|
11967
|
-
const py = (
|
|
11949
|
+
const px = (u) => Math.round(cx + rx * u);
|
|
11950
|
+
const py = (v) => Math.round(cy - ry * v);
|
|
11968
11951
|
const E = clockwise ? clockwiseEllipseBeziersBox(axisBox(l, t, r, b)) : ellipseBeziers(l, t, r, b);
|
|
11969
|
-
const
|
|
11952
|
+
const startUnit = small ? [Math.cos(a0), Math.sin(a0)] : polygonTrig(a0);
|
|
11953
|
+
const out = [px(startUnit[0]), py(startUnit[1])];
|
|
11970
11954
|
let a = a0;
|
|
11971
11955
|
for (let guard = 0; guard < 8 && (s > 0 ? a < a1 - 1e-12 : a > a1 + 1e-12); guard++) {
|
|
11972
11956
|
const next = s > 0 ? Math.floor(a / Q + 1e-9) * Q + Q : Math.ceil(a / Q - 1e-9) * Q - Q;
|
|
11973
11957
|
const onBoundary = Math.abs(a / Q - Math.round(a / Q)) < 1e-9;
|
|
11974
|
-
|
|
11958
|
+
const reachesEnd = s > 0 ? next >= a1 - 1e-12 : next <= a1 + 1e-12;
|
|
11959
|
+
const quadrantFrom = (Math.round(a / Q) % 4 + 4) % 4;
|
|
11960
|
+
const quadrantTo = (Math.round(next / Q) % 4 + 4) % 4;
|
|
11961
|
+
const generic = guard === 0 && (s > 0 ? quadrantFrom === 0 || quadrantFrom === 3 : quadrantFrom === 0 || quadrantFrom === 1) || reachesEnd && (s > 0 ? quadrantTo === 1 || quadrantTo === 2 : quadrantTo === 2 || quadrantTo === 3);
|
|
11962
|
+
if (!generic && onBoundary && (s > 0 ? next <= a1 + 1e-12 : next >= a1 - 1e-12)) {
|
|
11975
11963
|
const qi = (Math.round(Math.min(a, next) / Q) % 4 + 4) % 4 * 6;
|
|
11976
11964
|
if (s > 0) {
|
|
11977
11965
|
out.push(E[qi + 2], E[qi + 3], E[qi + 4], E[qi + 5], E[qi + 6], E[qi + 7]);
|
|
@@ -11982,30 +11970,10 @@ function arcBeziers(l, t, r, b, xs, ys, xe, ye, clockwise) {
|
|
|
11982
11970
|
continue;
|
|
11983
11971
|
}
|
|
11984
11972
|
const e = s > 0 ? Math.min(next, a1) : Math.max(next, a1);
|
|
11985
|
-
const
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
if (onBoundary) {
|
|
11989
|
-
out.push(...[piece.cAnchor, piece.cFree, piece.free].flatMap((q) => [Math.round(q[0]), Math.round(q[1])]));
|
|
11990
|
-
} else {
|
|
11991
|
-
if (out.length === 2) {
|
|
11992
|
-
out[0] = Math.round(piece.free[0]);
|
|
11993
|
-
out[1] = Math.round(piece.free[1]);
|
|
11994
|
-
}
|
|
11995
|
-
out.push(...[piece.cFree, piece.cAnchor, piece.anchor].flatMap((q) => [Math.round(q[0]), Math.round(q[1])]));
|
|
11996
|
-
}
|
|
11997
|
-
a = e;
|
|
11998
|
-
continue;
|
|
11973
|
+
const piece = unitPiece(a, e, small);
|
|
11974
|
+
for (let i = 0; i < 6; i += 2) {
|
|
11975
|
+
out.push(px(piece.ctrl[i]), py(piece.ctrl[i + 1]));
|
|
11999
11976
|
}
|
|
12000
|
-
const k = 4 / 3 * Math.tan((e - a) / 4);
|
|
12001
|
-
out.push(
|
|
12002
|
-
Math.round(px(a) - k * rx * tableSin(a)),
|
|
12003
|
-
Math.round(py(a) - k * ry * tableCos(a)),
|
|
12004
|
-
Math.round(px(e) + k * rx * tableSin(e)),
|
|
12005
|
-
Math.round(py(e) + k * ry * tableCos(e)),
|
|
12006
|
-
Math.round(px(e)),
|
|
12007
|
-
Math.round(py(e))
|
|
12008
|
-
);
|
|
12009
11977
|
a = e;
|
|
12010
11978
|
}
|
|
12011
11979
|
return out;
|
|
@@ -16810,14 +16778,21 @@ function blurKernel(radius) {
|
|
|
16810
16778
|
k[0] = 1;
|
|
16811
16779
|
return k;
|
|
16812
16780
|
}
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16781
|
+
const step = truncF32(truncF32(1.4) / Math.fround(radius));
|
|
16782
|
+
const w = new Float64Array(taps + 1);
|
|
16783
|
+
w[0] = 1;
|
|
16784
|
+
let offset = 0;
|
|
16785
|
+
let sum = 1;
|
|
16786
|
+
for (let i = 1; i <= taps; i++) {
|
|
16787
|
+
offset = truncF32(offset + step);
|
|
16788
|
+
w[i] = truncF32(Math.exp(-truncF32(offset * offset)));
|
|
16789
|
+
sum = truncF32(sum + truncF32(2 * w[i]));
|
|
16790
|
+
}
|
|
16791
|
+
const scale = truncF32(256 / sum);
|
|
16792
|
+
for (let i = 0; i <= taps; i++) {
|
|
16793
|
+
const weight = truncF32(w[i] * scale) / 256;
|
|
16794
|
+
k[taps + i] = weight;
|
|
16795
|
+
k[taps - i] = weight;
|
|
16821
16796
|
}
|
|
16822
16797
|
return k;
|
|
16823
16798
|
}
|
|
@@ -29843,6 +29818,11 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = fal
|
|
|
29843
29818
|
for (let i = 0; i < q.length; i += 2) {
|
|
29844
29819
|
pts.push(...map(q[i], clockwise ? f.t + f.b - q[i + 1] : q[i + 1]));
|
|
29845
29820
|
}
|
|
29821
|
+
if (box.halfX && !clockwise) {
|
|
29822
|
+
for (const k of [1, 2, 3, 4, 5, 6, 8, 15]) {
|
|
29823
|
+
pts[2 * k]++;
|
|
29824
|
+
}
|
|
29825
|
+
}
|
|
29846
29826
|
return pts;
|
|
29847
29827
|
}
|
|
29848
29828
|
function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
|
|
@@ -30924,6 +30904,51 @@ function fixExtent(rCtx, v, axis) {
|
|
|
30924
30904
|
const k = axis === 0 ? Math.hypot(m[0], m[1]) : Math.hypot(m[2], m[3]);
|
|
30925
30905
|
return Math.round(Math.abs(v) * k * 16);
|
|
30926
30906
|
}
|
|
30907
|
+
var PS_INSIDEFRAME = 6;
|
|
30908
|
+
function insideFrameInset(rCtx, box, rectangle = false) {
|
|
30909
|
+
if ((rCtx.state.penStyle & 15) !== PS_INSIDEFRAME || !isAxisBox(box) || hasWorldRotation(rCtx)) {
|
|
30910
|
+
return null;
|
|
30911
|
+
}
|
|
30912
|
+
const m = gdiDeviceMatrix(rCtx);
|
|
30913
|
+
const px = gdiDevicePixelX(rCtx);
|
|
30914
|
+
const py = gdiDevicePixelY(rCtx);
|
|
30915
|
+
const widthX = Math.abs(rCtx.state.penWidth * m[0]) / px * 16;
|
|
30916
|
+
const widthY = Math.abs(rCtx.state.penWidth * m[3]) / py * 16;
|
|
30917
|
+
if (Math.max(widthX, widthY) < 24) {
|
|
30918
|
+
return null;
|
|
30919
|
+
}
|
|
30920
|
+
const wx = Math.round(widthX);
|
|
30921
|
+
const wy = Math.round(widthY);
|
|
30922
|
+
if (Math.abs(box.exx) / px < wx || Math.abs(box.eyy) / py < wy) {
|
|
30923
|
+
return null;
|
|
30924
|
+
}
|
|
30925
|
+
const lo = Math.floor(wx / 2);
|
|
30926
|
+
const hi = Math.ceil(wx / 2);
|
|
30927
|
+
const y = Math.round(Math.ceil(wy / 2) * py);
|
|
30928
|
+
return {
|
|
30929
|
+
left: Math.round((rectangle ? hi : lo) * px),
|
|
30930
|
+
right: Math.round((rectangle ? lo : hi) * px),
|
|
30931
|
+
top: y,
|
|
30932
|
+
bottom: y,
|
|
30933
|
+
half: wx % 2 === 1 && !rectangle
|
|
30934
|
+
};
|
|
30935
|
+
}
|
|
30936
|
+
function insetFixBox(box, inset) {
|
|
30937
|
+
const sx = box.exx < 0 ? -1 : 1;
|
|
30938
|
+
const sy = box.eyy < 0 ? -1 : 1;
|
|
30939
|
+
const framed = {
|
|
30940
|
+
ax: box.ax + sx * inset.left,
|
|
30941
|
+
ay: box.ay + sy * inset.top,
|
|
30942
|
+
exx: box.exx - sx * (inset.left + inset.right),
|
|
30943
|
+
exy: 0,
|
|
30944
|
+
eyx: 0,
|
|
30945
|
+
eyy: box.eyy - sy * (inset.top + inset.bottom)
|
|
30946
|
+
};
|
|
30947
|
+
if (inset.half && sx > 0) {
|
|
30948
|
+
framed.halfX = true;
|
|
30949
|
+
}
|
|
30950
|
+
return framed;
|
|
30951
|
+
}
|
|
30927
30952
|
function handleSetPixelV(rCtx, dataOff, recSize) {
|
|
30928
30953
|
const { ctx, view } = rCtx;
|
|
30929
30954
|
if (recSize >= 20) {
|
|
@@ -30996,7 +31021,9 @@ function handleRectangle(rCtx, dataOff, recSize) {
|
|
|
30996
31021
|
const t = view.getInt32(dataOff + 4, true);
|
|
30997
31022
|
const r = view.getInt32(dataOff + 8, true);
|
|
30998
31023
|
const b = view.getInt32(dataOff + 12, true);
|
|
30999
|
-
const
|
|
31024
|
+
const unframed = uprightFixBox(rCtx, l, t, r, b);
|
|
31025
|
+
const inset = insideFrameInset(rCtx, unframed, true);
|
|
31026
|
+
const box = inset ? insetFixBox(unframed, inset) : unframed;
|
|
31000
31027
|
const clockwise = rCtx.state.arcDirection === 2;
|
|
31001
31028
|
if (!inPath) {
|
|
31002
31029
|
resetLineStyle(rCtx);
|
|
@@ -31031,10 +31058,16 @@ function handleRectangle(rCtx, dataOff, recSize) {
|
|
|
31031
31058
|
}
|
|
31032
31059
|
return true;
|
|
31033
31060
|
}
|
|
31034
|
-
|
|
31035
|
-
|
|
31036
|
-
|
|
31037
|
-
|
|
31061
|
+
let x = gmx(rCtx, l);
|
|
31062
|
+
let y = gmy(rCtx, t);
|
|
31063
|
+
let w = gmw(rCtx, r - l);
|
|
31064
|
+
let h = gmh(rCtx, b - t);
|
|
31065
|
+
if (inset) {
|
|
31066
|
+
x = Math.min(box.ax, box.ax + box.exx) / 16;
|
|
31067
|
+
y = Math.min(box.ay, box.ay + box.eyy) / 16;
|
|
31068
|
+
w = Math.abs(box.exx) / 16;
|
|
31069
|
+
h = Math.abs(box.eyy) / 16;
|
|
31070
|
+
}
|
|
31038
31071
|
if (inPath) {
|
|
31039
31072
|
recordRectangle(rCtx, box, clockwise);
|
|
31040
31073
|
} else if (needsPathBasedRectangle(rCtx)) {
|
|
@@ -31146,7 +31179,26 @@ function handleRoundRect(rCtx, dataOff, recSize) {
|
|
|
31146
31179
|
const b = view.getInt32(dataOff + 12, true);
|
|
31147
31180
|
const cornerW = view.getInt32(dataOff + 16, true);
|
|
31148
31181
|
const cornerH = view.getInt32(dataOff + 20, true);
|
|
31149
|
-
const
|
|
31182
|
+
const clockwise = rCtx.state.arcDirection === 2;
|
|
31183
|
+
const unframed = uprightFixBox(rCtx, l, t, r, b);
|
|
31184
|
+
const inset = insideFrameInset(rCtx, unframed);
|
|
31185
|
+
const framed = inset ? insetFixBox(unframed, inset) : unframed;
|
|
31186
|
+
const devM = gdiDeviceMatrix(rCtx);
|
|
31187
|
+
const cornerFixW = inset ? Math.abs(cornerW * devM[0]) * 16 : fixExtent(rCtx, cornerW, 0);
|
|
31188
|
+
const cornerFixH = inset ? Math.abs(cornerH * devM[3]) * 16 : fixExtent(rCtx, cornerH, 1);
|
|
31189
|
+
const cornerOnFrame = (fix, size, framedSize) => inset && size !== 0 ? Math.floor(Math.min(fix, size) * framedSize / size) : fix;
|
|
31190
|
+
const cw = cornerOnFrame(cornerFixW, Math.abs((r - l) * devM[0]) * 16, Math.abs(framed.exx));
|
|
31191
|
+
const ch = cornerOnFrame(cornerFixH, Math.abs((b - t) * devM[3]) * 16, Math.abs(framed.eyy));
|
|
31192
|
+
const drawRoundRect = inset ? (c) => appendRoundRectPath(
|
|
31193
|
+
c,
|
|
31194
|
+
Math.min(framed.ax, framed.ax + framed.exx) / 16,
|
|
31195
|
+
Math.min(framed.ay, framed.ay + framed.eyy) / 16,
|
|
31196
|
+
Math.max(framed.ax, framed.ax + framed.exx) / 16,
|
|
31197
|
+
Math.max(framed.ay, framed.ay + framed.eyy) / 16,
|
|
31198
|
+
cw / 32,
|
|
31199
|
+
ch / 32,
|
|
31200
|
+
null
|
|
31201
|
+
) : hasWorldRotation(rCtx) ? (c) => appendRoundRectPath(c, l, t, r, b, cornerW / 2, cornerH / 2, (x, y) => gmapPoint(rCtx, x, y)) : (c) => appendRoundRectPath(
|
|
31150
31202
|
c,
|
|
31151
31203
|
gmx(rCtx, l),
|
|
31152
31204
|
gmy(rCtx, t),
|
|
@@ -31156,13 +31208,12 @@ function handleRoundRect(rCtx, dataOff, recSize) {
|
|
|
31156
31208
|
gmh(rCtx, cornerH) / 2,
|
|
31157
31209
|
null
|
|
31158
31210
|
);
|
|
31159
|
-
const
|
|
31160
|
-
const raster = (box = uprightFixBox(rCtx, l, t, r, b)) => roundRectRasterPath(box, fixExtent(rCtx, cornerW, 0), fixExtent(rCtx, cornerH, 1), clockwise, cornerW === 0 || cornerH === 0);
|
|
31211
|
+
const raster = (box = framed) => roundRectRasterPath(box, cw, ch, clockwise, cornerW === 0 || cornerH === 0);
|
|
31161
31212
|
if (inPath) {
|
|
31162
|
-
const box =
|
|
31213
|
+
const box = framed;
|
|
31163
31214
|
if (cornerW === 0 || cornerH === 0) recordRectangle(rCtx, box, clockwise);
|
|
31164
31215
|
else {
|
|
31165
|
-
recordBezierShape(rCtx, roundRectDeviceBeziers(box,
|
|
31216
|
+
recordBezierShape(rCtx, roundRectDeviceBeziers(box, cw, ch, clockwise), 8);
|
|
31166
31217
|
rasterPathOf(rCtx).append(raster(box));
|
|
31167
31218
|
}
|
|
31168
31219
|
} else {
|
|
@@ -31172,7 +31223,7 @@ function handleRoundRect(rCtx, dataOff, recSize) {
|
|
|
31172
31223
|
c.beginPath();
|
|
31173
31224
|
drawRoundRect(c);
|
|
31174
31225
|
},
|
|
31175
|
-
raster: () => raster(curvedFixBox(rCtx, l, t, r, b, true)),
|
|
31226
|
+
raster: () => raster(inset ? framed : curvedFixBox(rCtx, l, t, r, b, true)),
|
|
31176
31227
|
roundPen: true,
|
|
31177
31228
|
fill: true,
|
|
31178
31229
|
stroke: true
|
|
@@ -31209,7 +31260,10 @@ function handleEllipse(rCtx, dataOff, recSize) {
|
|
|
31209
31260
|
const r = view.getInt32(dataOff + 8, true);
|
|
31210
31261
|
const b = view.getInt32(dataOff + 12, true);
|
|
31211
31262
|
const clockwise = rCtx.state.arcDirection === 2;
|
|
31212
|
-
const
|
|
31263
|
+
const unframed = uprightFixBox(rCtx, l, t, r, b);
|
|
31264
|
+
const inset = insideFrameInset(rCtx, unframed);
|
|
31265
|
+
const framed = inset ? insetFixBox(unframed, inset) : unframed;
|
|
31266
|
+
const params = inset ? { cx: (framed.ax + framed.exx / 2) / 16, cy: (framed.ay + framed.eyy / 2) / 16, rx: Math.abs(framed.exx) / 32, ry: Math.abs(framed.eyy) / 32, rotation: 0 } : hasWorldRotation(rCtx) ? gdiEllipseParams(rCtx, (l + r) / 2, (t + b) / 2, Math.abs(r - l) / 2, Math.abs(b - t) / 2) : {
|
|
31213
31267
|
cx: gmx(rCtx, (l + r) / 2),
|
|
31214
31268
|
cy: gmy(rCtx, (t + b) / 2),
|
|
31215
31269
|
rx: Math.abs(gmw(rCtx, r - l)) / 2,
|
|
@@ -31217,7 +31271,7 @@ function handleEllipse(rCtx, dataOff, recSize) {
|
|
|
31217
31271
|
rotation: 0
|
|
31218
31272
|
};
|
|
31219
31273
|
if (inPath) {
|
|
31220
|
-
const box =
|
|
31274
|
+
const box = framed;
|
|
31221
31275
|
recordBezierShape(rCtx, ellipseBeziersBox(box, clockwise), 6);
|
|
31222
31276
|
rasterPathOf(rCtx).append(ellipseRasterPath(box, clockwise));
|
|
31223
31277
|
} else {
|
|
@@ -31227,7 +31281,7 @@ function handleEllipse(rCtx, dataOff, recSize) {
|
|
|
31227
31281
|
c.beginPath();
|
|
31228
31282
|
c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, 0, Math.PI * 2);
|
|
31229
31283
|
},
|
|
31230
|
-
raster: () => ellipseRasterPath(curvedFixBox(rCtx, l, t, r, b, true), clockwise),
|
|
31284
|
+
raster: () => ellipseRasterPath(inset ? framed : curvedFixBox(rCtx, l, t, r, b, true), clockwise),
|
|
31231
31285
|
roundPen: true,
|
|
31232
31286
|
fill: true,
|
|
31233
31287
|
stroke: true
|
|
@@ -31254,7 +31308,10 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31254
31308
|
const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
|
|
31255
31309
|
const endAngle = Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
|
|
31256
31310
|
const rotated = hasWorldRotation(rCtx);
|
|
31257
|
-
const
|
|
31311
|
+
const unframed = fixBox(rCtx, l, t, r, b);
|
|
31312
|
+
const inset = insideFrameInset(rCtx, unframed);
|
|
31313
|
+
const framed = inset ? insetFixBox(unframed, inset) : unframed;
|
|
31314
|
+
const params = inset ? { cx: (framed.ax + framed.exx / 2) / 16, cy: (framed.ay + framed.eyy / 2) / 16, rx: Math.abs(framed.exx) / 32, ry: Math.abs(framed.eyy) / 32, rotation: 0 } : rotated ? gdiEllipseParams(rCtx, cxA, cyA, rx, ry) : {
|
|
31258
31315
|
cx: gmx(rCtx, cxA),
|
|
31259
31316
|
cy: gmy(rCtx, cyA),
|
|
31260
31317
|
rx: Math.abs(gmw(rCtx, rx)),
|
|
@@ -31278,10 +31335,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31278
31335
|
}
|
|
31279
31336
|
};
|
|
31280
31337
|
const kind = isArcTo ? "arcto" : recType === EMR_PIE ? "pie" : recType === EMR_CHORD ? "chord" : "arc";
|
|
31338
|
+
const radialOnBox = (p) => {
|
|
31339
|
+
if (!inset) {
|
|
31340
|
+
return p;
|
|
31341
|
+
}
|
|
31342
|
+
const kx = unframed.exx !== 0 ? framed.exx / unframed.exx : 1;
|
|
31343
|
+
const ky = unframed.eyy !== 0 ? framed.eyy / unframed.eyy : 1;
|
|
31344
|
+
return [framed.ax + framed.exx / 2 + (p[0] - (unframed.ax + unframed.exx / 2)) * kx, framed.ay + framed.eyy / 2 + (p[1] - (unframed.ay + unframed.eyy / 2)) * ky];
|
|
31345
|
+
};
|
|
31281
31346
|
const rasterArgs = (immediate = false) => ({
|
|
31282
|
-
box: immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) :
|
|
31283
|
-
s: fixPoint(rCtx, startX, startY),
|
|
31284
|
-
e: fixPoint(rCtx, endX, endY),
|
|
31347
|
+
box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
|
|
31348
|
+
s: radialOnBox(fixPoint(rCtx, startX, startY)),
|
|
31349
|
+
e: radialOnBox(fixPoint(rCtx, endX, endY)),
|
|
31285
31350
|
from: currentFix(rCtx)
|
|
31286
31351
|
});
|
|
31287
31352
|
if (inPath) {
|
|
@@ -39316,7 +39381,7 @@ function wmfExtFloodFill(p, x, y, colorRef, type) {
|
|
|
39316
39381
|
|
|
39317
39382
|
// src/wmf-shapes.ts
|
|
39318
39383
|
var PS_NULL3 = 5;
|
|
39319
|
-
var
|
|
39384
|
+
var PS_INSIDEFRAME2 = 6;
|
|
39320
39385
|
function compatBox(p, l, t, r, b, opts = {}) {
|
|
39321
39386
|
const exclusive = opts.exclusive !== false;
|
|
39322
39387
|
const a = fixPoint(p.rCtx, l, t);
|
|
@@ -39338,23 +39403,32 @@ function compatBox(p, l, t, r, b, opts = {}) {
|
|
|
39338
39403
|
box.x1 -= Math.round(ux * 3 / 4);
|
|
39339
39404
|
box.y1 -= Math.round(uy * 3 / 4);
|
|
39340
39405
|
}
|
|
39341
|
-
if ((p.rCtx.state.penStyle & 15) ===
|
|
39406
|
+
if ((p.rCtx.state.penStyle & 15) === PS_INSIDEFRAME2) {
|
|
39342
39407
|
const w = Math.round(penDeviceWidth(p.rCtx) / p.kx);
|
|
39343
39408
|
if (w > 1) {
|
|
39344
39409
|
const matrix = gdiDeviceMatrix(p.rCtx);
|
|
39345
|
-
const
|
|
39410
|
+
const wx = Math.round(Math.abs(p.rCtx.state.penWidth * matrix[0]) / p.kx * 16);
|
|
39411
|
+
const wy = Math.round(Math.abs(p.rCtx.state.penWidth * matrix[3]) / p.ky * 16);
|
|
39346
39412
|
box.x1 += Math.round(ux);
|
|
39347
39413
|
box.y1 += Math.round(uy);
|
|
39348
|
-
box.x0 += Math.round(
|
|
39349
|
-
box.y0 += Math.round(
|
|
39350
|
-
|
|
39351
|
-
box.
|
|
39414
|
+
box.x0 += Math.round((opts.curved || opts.roundFrame ? Math.floor(wx / 2) : Math.ceil(wx / 2)) * ux / 16);
|
|
39415
|
+
box.y0 += Math.round(Math.ceil(wy / 2) * uy / 16);
|
|
39416
|
+
const half = !!opts.half && wx % 2 === 1;
|
|
39417
|
+
box.x1 -= Math.round((half ? Math.ceil(wx / 2) : Math.floor(wx / 2)) * ux / 16);
|
|
39418
|
+
box.y1 -= Math.round(Math.ceil(wy / 2) * uy / 16);
|
|
39419
|
+
if (half) {
|
|
39420
|
+
box.halfX = true;
|
|
39421
|
+
}
|
|
39352
39422
|
}
|
|
39353
39423
|
}
|
|
39354
39424
|
return box;
|
|
39355
39425
|
}
|
|
39356
39426
|
function fixBoxOf(box) {
|
|
39357
|
-
|
|
39427
|
+
const fix = axisBox(box.x0, box.y0, Math.max(box.x0, box.x1), Math.max(box.y0, box.y1));
|
|
39428
|
+
if (box.halfX) {
|
|
39429
|
+
fix.halfX = true;
|
|
39430
|
+
}
|
|
39431
|
+
return fix;
|
|
39358
39432
|
}
|
|
39359
39433
|
function canvasRect(box) {
|
|
39360
39434
|
return { x: box.x0 / 16, y: box.y0 / 16, w: Math.max(0, box.x1 - box.x0) / 16, h: Math.max(0, box.y1 - box.y0) / 16 };
|
|
@@ -39408,14 +39482,15 @@ function wmfRectangle(p, l, t, r, b) {
|
|
|
39408
39482
|
}
|
|
39409
39483
|
function compatCorner(p, w, h, box, logical) {
|
|
39410
39484
|
const m = gdiDeviceMatrix(p.rCtx);
|
|
39411
|
-
|
|
39412
|
-
|
|
39485
|
+
Math.round(Math.abs(w * m[0]) * 16);
|
|
39486
|
+
Math.round(Math.abs(h * m[3]) * 16);
|
|
39413
39487
|
const ux = 16 * p.kx;
|
|
39414
39488
|
const uy = 16 * p.ky;
|
|
39415
|
-
if ((p.rCtx.state.penStyle & 15) ===
|
|
39416
|
-
const penWidth = p.rCtx.state.penWidth * Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2])) * 16;
|
|
39489
|
+
if ((p.rCtx.state.penStyle & 15) === PS_INSIDEFRAME2 && !penIsCosmetic(p.rCtx)) {
|
|
39417
39490
|
const width2 = box.x1 - box.x0, height2 = box.y1 - box.y0;
|
|
39418
|
-
|
|
39491
|
+
const fullW2 = Math.abs((logical[2] - logical[0]) * m[0]) * 16 || width2;
|
|
39492
|
+
const fullH2 = Math.abs((logical[3] - logical[1]) * m[3]) * 16 || height2;
|
|
39493
|
+
return [Math.floor(Math.min(Math.abs(w * m[0]) * 16, fullW2) * width2 / fullW2), Math.floor(Math.min(Math.abs(h * m[3]) * 16, fullH2) * height2 / fullH2)];
|
|
39419
39494
|
}
|
|
39420
39495
|
const width = box.x1 - box.x0, height = box.y1 - box.y0;
|
|
39421
39496
|
const fullW = Math.abs((logical[2] - logical[0]) * m[0]) * 16 || width + ux;
|
|
@@ -39424,7 +39499,7 @@ function compatCorner(p, w, h, box, logical) {
|
|
|
39424
39499
|
return penIsCosmetic(p.rCtx) && !penIsNull(p) ? scaled2 : [Math.floor(scaled2[0]), Math.floor(scaled2[1])];
|
|
39425
39500
|
}
|
|
39426
39501
|
function wmfRoundRect(p, l, t, r, b, w, h) {
|
|
39427
|
-
const box = compatBox(p, l, t, r, b, { curved: true });
|
|
39502
|
+
const box = compatBox(p, l, t, r, b, { curved: true, half: true });
|
|
39428
39503
|
if (box.x1 < box.x0 || box.y1 < box.y0) {
|
|
39429
39504
|
return;
|
|
39430
39505
|
}
|
|
@@ -39460,7 +39535,7 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
|
|
|
39460
39535
|
});
|
|
39461
39536
|
}
|
|
39462
39537
|
function wmfEllipse(p, l, t, r, b) {
|
|
39463
|
-
const box = compatBox(p, l, t, r, b, { curved: true });
|
|
39538
|
+
const box = compatBox(p, l, t, r, b, { curved: true, half: true });
|
|
39464
39539
|
if (box.x1 < box.x0 || box.y1 < box.y0) {
|
|
39465
39540
|
return;
|
|
39466
39541
|
}
|
|
@@ -39477,7 +39552,7 @@ function wmfEllipse(p, l, t, r, b) {
|
|
|
39477
39552
|
});
|
|
39478
39553
|
}
|
|
39479
39554
|
function compatArc(p, kind, l, t, r, b, xs, ys, xe, ye) {
|
|
39480
|
-
const box = compatBox(p, l, t, r, b, { curved: kind === "chord" || kind === "pie" });
|
|
39555
|
+
const box = compatBox(p, l, t, r, b, { curved: kind === "chord" || kind === "pie", roundFrame: true });
|
|
39481
39556
|
if (box.x1 < box.x0 || box.y1 < box.y0) {
|
|
39482
39557
|
return null;
|
|
39483
39558
|
}
|