emf-converter 4.8.7 → 4.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +81 -30
- package/dist/browser.mjs +81 -30
- package/dist/index.js +81 -30
- package/dist/index.mjs +81 -30
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -27798,10 +27798,10 @@ function parseEmfHeader(view) {
|
|
|
27798
27798
|
};
|
|
27799
27799
|
}
|
|
27800
27800
|
function getRenderableEmfBounds(header) {
|
|
27801
|
-
const boundsW = header.bounds.right - header.bounds.left;
|
|
27802
|
-
const boundsH = header.bounds.bottom - header.bounds.top;
|
|
27801
|
+
const boundsW = header.bounds.right - header.bounds.left + 1;
|
|
27802
|
+
const boundsH = header.bounds.bottom - header.bounds.top + 1;
|
|
27803
27803
|
if (boundsW > 0 && boundsH > 0) {
|
|
27804
|
-
return header.bounds;
|
|
27804
|
+
return { ...header.bounds, right: header.bounds.right + 1, bottom: header.bounds.bottom + 1 };
|
|
27805
27805
|
}
|
|
27806
27806
|
if (header.frameW > 0 && header.frameH > 0) {
|
|
27807
27807
|
emfLog(
|
|
@@ -30833,6 +30833,13 @@ function insetFixBox(box, inset) {
|
|
|
30833
30833
|
}
|
|
30834
30834
|
return framed;
|
|
30835
30835
|
}
|
|
30836
|
+
function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
|
|
30837
|
+
const ax = BigInt(2 * sx - l - r);
|
|
30838
|
+
const ay = BigInt(2 * sy - t - b);
|
|
30839
|
+
const bx = BigInt(2 * ex - l - r);
|
|
30840
|
+
const by = BigInt(2 * ey - t - b);
|
|
30841
|
+
return ax * by === ay * bx && ax * bx + ay * by > 0n;
|
|
30842
|
+
}
|
|
30836
30843
|
function handleSetPixelV(rCtx, dataOff, recSize) {
|
|
30837
30844
|
const { ctx, view } = rCtx;
|
|
30838
30845
|
if (recSize >= 20) {
|
|
@@ -31190,7 +31197,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31190
31197
|
const rx = Math.abs(r - l) / 2;
|
|
31191
31198
|
const ry = Math.abs(b - t) / 2;
|
|
31192
31199
|
const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
|
|
31193
|
-
const
|
|
31200
|
+
const clockwise = state.arcDirection === 2;
|
|
31201
|
+
const fullEllipse = recType !== EMR_PIE && rx > 0 && ry > 0 && sameEllipseRay(l, t, r, b, startX, startY, endX, endY);
|
|
31202
|
+
const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
|
|
31194
31203
|
const rotated = hasWorldRotation(rCtx);
|
|
31195
31204
|
const unframed = fixBox(rCtx, l, t, r, b);
|
|
31196
31205
|
const inset = insideFrameInset(rCtx, unframed);
|
|
@@ -31204,13 +31213,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31204
31213
|
};
|
|
31205
31214
|
const isArcTo = recType === EMR_ARCTO;
|
|
31206
31215
|
const needsFill = recType === EMR_PIE || recType === EMR_CHORD;
|
|
31207
|
-
const clockwise = state.arcDirection === 2;
|
|
31208
31216
|
const startPoint = rotated ? gmapPoint(rCtx, cxA + rx * Math.cos(startAngle), cyA + ry * Math.sin(startAngle)) : { x: params.cx + params.rx * Math.cos(startAngle), y: params.cy + params.ry * Math.sin(startAngle) };
|
|
31209
31217
|
const build = (c) => {
|
|
31210
31218
|
if (recType === EMR_PIE) {
|
|
31211
31219
|
c.moveTo(params.cx, params.cy);
|
|
31220
|
+
} else if (!isArcTo && inPath) {
|
|
31221
|
+
c.moveTo(startPoint.x, startPoint.y);
|
|
31212
31222
|
}
|
|
31213
31223
|
if (isArcTo) {
|
|
31224
|
+
if (!inPath) {
|
|
31225
|
+
const from = currentFix(rCtx);
|
|
31226
|
+
c.moveTo(from[0] / 16, from[1] / 16);
|
|
31227
|
+
}
|
|
31214
31228
|
c.lineTo(startPoint.x, startPoint.y);
|
|
31215
31229
|
}
|
|
31216
31230
|
c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, startAngle, endAngle, !clockwise);
|
|
@@ -31230,7 +31244,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31230
31244
|
const rasterArgs = (immediate = false) => ({
|
|
31231
31245
|
box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
|
|
31232
31246
|
s: radialOnBox(fixPoint(rCtx, startX, startY)),
|
|
31233
|
-
|
|
31247
|
+
// Device FIX rounding can separate distinct radial points on the
|
|
31248
|
+
// same logical ray. Preserve their proven endpoint identity.
|
|
31249
|
+
e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
|
|
31234
31250
|
from: currentFix(rCtx)
|
|
31235
31251
|
});
|
|
31236
31252
|
if (inPath) {
|
|
@@ -35696,14 +35712,20 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35696
35712
|
}
|
|
35697
35713
|
|
|
35698
35714
|
// src/emf-gdi-transform-handlers.ts
|
|
35715
|
+
function extentsSettable(rCtx) {
|
|
35716
|
+
return rCtx.mapMode === 7 || rCtx.mapMode === 8;
|
|
35717
|
+
}
|
|
35699
35718
|
function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
35700
35719
|
const { view } = rCtx;
|
|
35701
35720
|
switch (recType) {
|
|
35702
35721
|
case EMR_SETWINDOWEXTEX: {
|
|
35703
|
-
if (recSize >= 16) {
|
|
35704
|
-
|
|
35705
|
-
|
|
35706
|
-
|
|
35722
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35723
|
+
const cx = view.getInt32(dataOff, true);
|
|
35724
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35725
|
+
if (cx !== 0 && cy !== 0) {
|
|
35726
|
+
rCtx.windowExt = { cx, cy };
|
|
35727
|
+
activateGdiMappingMode(rCtx);
|
|
35728
|
+
}
|
|
35707
35729
|
}
|
|
35708
35730
|
return true;
|
|
35709
35731
|
}
|
|
@@ -35716,10 +35738,13 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35716
35738
|
return true;
|
|
35717
35739
|
}
|
|
35718
35740
|
case EMR_SETVIEWPORTEXTEX: {
|
|
35719
|
-
if (recSize >= 16) {
|
|
35720
|
-
|
|
35721
|
-
|
|
35722
|
-
|
|
35741
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35742
|
+
const cx = view.getInt32(dataOff, true);
|
|
35743
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35744
|
+
if (cx !== 0 && cy !== 0) {
|
|
35745
|
+
rCtx.viewportExt = { cx, cy };
|
|
35746
|
+
activateGdiMappingMode(rCtx);
|
|
35747
|
+
}
|
|
35723
35748
|
}
|
|
35724
35749
|
return true;
|
|
35725
35750
|
}
|
|
@@ -35734,14 +35759,21 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35734
35759
|
case EMR_SETMAPMODE: {
|
|
35735
35760
|
if (recSize >= 12) {
|
|
35736
35761
|
const mode = view.getUint32(dataOff, true);
|
|
35737
|
-
if (mode
|
|
35738
|
-
|
|
35762
|
+
if (mode >= 1 && mode <= 8) {
|
|
35763
|
+
rCtx.mapMode = mode;
|
|
35764
|
+
if (mode === 1) {
|
|
35765
|
+
rCtx.windowExt = { cx: 1, cy: 1 };
|
|
35766
|
+
rCtx.viewportExt = { cx: 1, cy: 1 };
|
|
35767
|
+
}
|
|
35768
|
+
if (mode === 1 || mode === 8 || mode === 7) {
|
|
35769
|
+
activateGdiMappingMode(rCtx);
|
|
35770
|
+
}
|
|
35739
35771
|
}
|
|
35740
35772
|
}
|
|
35741
35773
|
return true;
|
|
35742
35774
|
}
|
|
35743
35775
|
case EMR_SCALEVIEWPORTEXTEX: {
|
|
35744
|
-
if (recSize >= 24) {
|
|
35776
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35745
35777
|
const xNum = view.getInt32(dataOff, true);
|
|
35746
35778
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35747
35779
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35757,7 +35789,7 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35757
35789
|
return true;
|
|
35758
35790
|
}
|
|
35759
35791
|
case EMR_SCALEWINDOWEXTEX: {
|
|
35760
|
-
if (recSize >= 24) {
|
|
35792
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35761
35793
|
const xNum = view.getInt32(dataOff, true);
|
|
35762
35794
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35763
35795
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35908,6 +35940,15 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35908
35940
|
}
|
|
35909
35941
|
rCtx.clipStack ?? (rCtx.clipStack = []);
|
|
35910
35942
|
rCtx.clipStack.push({ region: rCtx.clipRegion ?? null });
|
|
35943
|
+
rCtx.mappingStack ?? (rCtx.mappingStack = []);
|
|
35944
|
+
rCtx.mappingStack.push({
|
|
35945
|
+
mapMode: rCtx.mapMode,
|
|
35946
|
+
windowOrg: { ...rCtx.windowOrg },
|
|
35947
|
+
windowExt: { ...rCtx.windowExt },
|
|
35948
|
+
viewportOrg: { ...rCtx.viewportOrg },
|
|
35949
|
+
viewportExt: { ...rCtx.viewportExt },
|
|
35950
|
+
useMappingMode: rCtx.useMappingMode
|
|
35951
|
+
});
|
|
35911
35952
|
rCtx.stateStack.push(cloneState(state));
|
|
35912
35953
|
ctx.save();
|
|
35913
35954
|
if (rCtx.clipRegion) {
|
|
@@ -35917,23 +35958,31 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35917
35958
|
}
|
|
35918
35959
|
case EMR_RESTOREDC: {
|
|
35919
35960
|
if (recSize >= 12) {
|
|
35920
|
-
while (rCtx.clipSaveDepth > 0) {
|
|
35921
|
-
ctx.restore();
|
|
35922
|
-
rCtx.clipSaveDepth--;
|
|
35923
|
-
}
|
|
35924
35961
|
let rel = view.getInt32(dataOff, true);
|
|
35925
35962
|
if (rel < 0) {
|
|
35926
35963
|
rel = rCtx.stateStack.length + rel + 1;
|
|
35927
35964
|
}
|
|
35928
|
-
|
|
35965
|
+
if (rel < 1 || rel > rCtx.stateStack.length) {
|
|
35966
|
+
return true;
|
|
35967
|
+
}
|
|
35968
|
+
while (rCtx.clipSaveDepth > 0) {
|
|
35969
|
+
ctx.restore();
|
|
35970
|
+
rCtx.clipSaveDepth--;
|
|
35971
|
+
}
|
|
35972
|
+
while (rCtx.stateStack.length > rel) {
|
|
35929
35973
|
rCtx.stateStack.pop();
|
|
35930
35974
|
rCtx.clipStack?.pop();
|
|
35975
|
+
rCtx.mappingStack?.pop();
|
|
35931
35976
|
ctx.restore();
|
|
35932
35977
|
}
|
|
35933
35978
|
const restored = rCtx.stateStack.pop();
|
|
35934
35979
|
if (restored) {
|
|
35935
35980
|
const clipSnapshot = rCtx.clipStack?.pop();
|
|
35981
|
+
const mappingSnapshot = rCtx.mappingStack?.pop();
|
|
35936
35982
|
Object.assign(state, restored);
|
|
35983
|
+
if (mappingSnapshot) {
|
|
35984
|
+
Object.assign(rCtx, mappingSnapshot);
|
|
35985
|
+
}
|
|
35937
35986
|
ctx.restore();
|
|
35938
35987
|
rCtx.clipRegion = clipSnapshot?.region ?? null;
|
|
35939
35988
|
if (rCtx.clipRegion) {
|
|
@@ -38032,9 +38081,11 @@ function replayEmfRecords(view, ctx, bounds, canvasW, canvasH, dpiScale = 1, rep
|
|
|
38032
38081
|
// canvas like every other device coordinate (bounds' top-left to the
|
|
38033
38082
|
// canvas origin, scaled by sx/sy); see `deviceToCanvas`.
|
|
38034
38083
|
windowOrg: { x: 0, y: 0 },
|
|
38035
|
-
windowExt: { cx:
|
|
38084
|
+
windowExt: { cx: 1, cy: 1 },
|
|
38036
38085
|
viewportOrg: { x: 0, y: 0 },
|
|
38037
|
-
viewportExt: { cx:
|
|
38086
|
+
viewportExt: { cx: 1, cy: 1 },
|
|
38087
|
+
mapMode: 1,
|
|
38088
|
+
// MM_TEXT: the default DC uses one-to-one page/device units.
|
|
38038
38089
|
useMappingMode: false,
|
|
38039
38090
|
deviceToCanvas: true,
|
|
38040
38091
|
clipSaveDepth: 0,
|
|
@@ -38286,18 +38337,18 @@ function setMapMode(m, mode) {
|
|
|
38286
38337
|
}
|
|
38287
38338
|
m.mode = mode;
|
|
38288
38339
|
}
|
|
38289
|
-
function
|
|
38340
|
+
function extentsSettable2(m) {
|
|
38290
38341
|
return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
|
|
38291
38342
|
}
|
|
38292
38343
|
function setWindowExt(m, cx, cy) {
|
|
38293
|
-
if (!
|
|
38344
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38294
38345
|
return;
|
|
38295
38346
|
}
|
|
38296
38347
|
m.winExt = { cx, cy };
|
|
38297
38348
|
fixIsotropic(m);
|
|
38298
38349
|
}
|
|
38299
38350
|
function setViewportExt(m, cx, cy) {
|
|
38300
|
-
if (!
|
|
38351
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38301
38352
|
return;
|
|
38302
38353
|
}
|
|
38303
38354
|
m.vpExt = { cx, cy };
|
|
@@ -38307,7 +38358,7 @@ function scaled(v, num, den) {
|
|
|
38307
38358
|
return Math.trunc(v * num / den);
|
|
38308
38359
|
}
|
|
38309
38360
|
function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
38310
|
-
if (!
|
|
38361
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38311
38362
|
return;
|
|
38312
38363
|
}
|
|
38313
38364
|
const cx = scaled(m.winExt.cx, xNum, xDen);
|
|
@@ -38319,7 +38370,7 @@ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
|
38319
38370
|
fixIsotropic(m);
|
|
38320
38371
|
}
|
|
38321
38372
|
function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
|
|
38322
|
-
if (!
|
|
38373
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38323
38374
|
return;
|
|
38324
38375
|
}
|
|
38325
38376
|
const cx = scaled(m.vpExt.cx, xNum, xDen);
|
package/dist/browser.mjs
CHANGED
|
@@ -27796,10 +27796,10 @@ function parseEmfHeader(view) {
|
|
|
27796
27796
|
};
|
|
27797
27797
|
}
|
|
27798
27798
|
function getRenderableEmfBounds(header) {
|
|
27799
|
-
const boundsW = header.bounds.right - header.bounds.left;
|
|
27800
|
-
const boundsH = header.bounds.bottom - header.bounds.top;
|
|
27799
|
+
const boundsW = header.bounds.right - header.bounds.left + 1;
|
|
27800
|
+
const boundsH = header.bounds.bottom - header.bounds.top + 1;
|
|
27801
27801
|
if (boundsW > 0 && boundsH > 0) {
|
|
27802
|
-
return header.bounds;
|
|
27802
|
+
return { ...header.bounds, right: header.bounds.right + 1, bottom: header.bounds.bottom + 1 };
|
|
27803
27803
|
}
|
|
27804
27804
|
if (header.frameW > 0 && header.frameH > 0) {
|
|
27805
27805
|
emfLog(
|
|
@@ -30831,6 +30831,13 @@ function insetFixBox(box, inset) {
|
|
|
30831
30831
|
}
|
|
30832
30832
|
return framed;
|
|
30833
30833
|
}
|
|
30834
|
+
function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
|
|
30835
|
+
const ax = BigInt(2 * sx - l - r);
|
|
30836
|
+
const ay = BigInt(2 * sy - t - b);
|
|
30837
|
+
const bx = BigInt(2 * ex - l - r);
|
|
30838
|
+
const by = BigInt(2 * ey - t - b);
|
|
30839
|
+
return ax * by === ay * bx && ax * bx + ay * by > 0n;
|
|
30840
|
+
}
|
|
30834
30841
|
function handleSetPixelV(rCtx, dataOff, recSize) {
|
|
30835
30842
|
const { ctx, view } = rCtx;
|
|
30836
30843
|
if (recSize >= 20) {
|
|
@@ -31188,7 +31195,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31188
31195
|
const rx = Math.abs(r - l) / 2;
|
|
31189
31196
|
const ry = Math.abs(b - t) / 2;
|
|
31190
31197
|
const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
|
|
31191
|
-
const
|
|
31198
|
+
const clockwise = state.arcDirection === 2;
|
|
31199
|
+
const fullEllipse = recType !== EMR_PIE && rx > 0 && ry > 0 && sameEllipseRay(l, t, r, b, startX, startY, endX, endY);
|
|
31200
|
+
const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
|
|
31192
31201
|
const rotated = hasWorldRotation(rCtx);
|
|
31193
31202
|
const unframed = fixBox(rCtx, l, t, r, b);
|
|
31194
31203
|
const inset = insideFrameInset(rCtx, unframed);
|
|
@@ -31202,13 +31211,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31202
31211
|
};
|
|
31203
31212
|
const isArcTo = recType === EMR_ARCTO;
|
|
31204
31213
|
const needsFill = recType === EMR_PIE || recType === EMR_CHORD;
|
|
31205
|
-
const clockwise = state.arcDirection === 2;
|
|
31206
31214
|
const startPoint = rotated ? gmapPoint(rCtx, cxA + rx * Math.cos(startAngle), cyA + ry * Math.sin(startAngle)) : { x: params.cx + params.rx * Math.cos(startAngle), y: params.cy + params.ry * Math.sin(startAngle) };
|
|
31207
31215
|
const build = (c) => {
|
|
31208
31216
|
if (recType === EMR_PIE) {
|
|
31209
31217
|
c.moveTo(params.cx, params.cy);
|
|
31218
|
+
} else if (!isArcTo && inPath) {
|
|
31219
|
+
c.moveTo(startPoint.x, startPoint.y);
|
|
31210
31220
|
}
|
|
31211
31221
|
if (isArcTo) {
|
|
31222
|
+
if (!inPath) {
|
|
31223
|
+
const from = currentFix(rCtx);
|
|
31224
|
+
c.moveTo(from[0] / 16, from[1] / 16);
|
|
31225
|
+
}
|
|
31212
31226
|
c.lineTo(startPoint.x, startPoint.y);
|
|
31213
31227
|
}
|
|
31214
31228
|
c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, startAngle, endAngle, !clockwise);
|
|
@@ -31228,7 +31242,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31228
31242
|
const rasterArgs = (immediate = false) => ({
|
|
31229
31243
|
box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
|
|
31230
31244
|
s: radialOnBox(fixPoint(rCtx, startX, startY)),
|
|
31231
|
-
|
|
31245
|
+
// Device FIX rounding can separate distinct radial points on the
|
|
31246
|
+
// same logical ray. Preserve their proven endpoint identity.
|
|
31247
|
+
e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
|
|
31232
31248
|
from: currentFix(rCtx)
|
|
31233
31249
|
});
|
|
31234
31250
|
if (inPath) {
|
|
@@ -35694,14 +35710,20 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35694
35710
|
}
|
|
35695
35711
|
|
|
35696
35712
|
// src/emf-gdi-transform-handlers.ts
|
|
35713
|
+
function extentsSettable(rCtx) {
|
|
35714
|
+
return rCtx.mapMode === 7 || rCtx.mapMode === 8;
|
|
35715
|
+
}
|
|
35697
35716
|
function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
35698
35717
|
const { view } = rCtx;
|
|
35699
35718
|
switch (recType) {
|
|
35700
35719
|
case EMR_SETWINDOWEXTEX: {
|
|
35701
|
-
if (recSize >= 16) {
|
|
35702
|
-
|
|
35703
|
-
|
|
35704
|
-
|
|
35720
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35721
|
+
const cx = view.getInt32(dataOff, true);
|
|
35722
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35723
|
+
if (cx !== 0 && cy !== 0) {
|
|
35724
|
+
rCtx.windowExt = { cx, cy };
|
|
35725
|
+
activateGdiMappingMode(rCtx);
|
|
35726
|
+
}
|
|
35705
35727
|
}
|
|
35706
35728
|
return true;
|
|
35707
35729
|
}
|
|
@@ -35714,10 +35736,13 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35714
35736
|
return true;
|
|
35715
35737
|
}
|
|
35716
35738
|
case EMR_SETVIEWPORTEXTEX: {
|
|
35717
|
-
if (recSize >= 16) {
|
|
35718
|
-
|
|
35719
|
-
|
|
35720
|
-
|
|
35739
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35740
|
+
const cx = view.getInt32(dataOff, true);
|
|
35741
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35742
|
+
if (cx !== 0 && cy !== 0) {
|
|
35743
|
+
rCtx.viewportExt = { cx, cy };
|
|
35744
|
+
activateGdiMappingMode(rCtx);
|
|
35745
|
+
}
|
|
35721
35746
|
}
|
|
35722
35747
|
return true;
|
|
35723
35748
|
}
|
|
@@ -35732,14 +35757,21 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35732
35757
|
case EMR_SETMAPMODE: {
|
|
35733
35758
|
if (recSize >= 12) {
|
|
35734
35759
|
const mode = view.getUint32(dataOff, true);
|
|
35735
|
-
if (mode
|
|
35736
|
-
|
|
35760
|
+
if (mode >= 1 && mode <= 8) {
|
|
35761
|
+
rCtx.mapMode = mode;
|
|
35762
|
+
if (mode === 1) {
|
|
35763
|
+
rCtx.windowExt = { cx: 1, cy: 1 };
|
|
35764
|
+
rCtx.viewportExt = { cx: 1, cy: 1 };
|
|
35765
|
+
}
|
|
35766
|
+
if (mode === 1 || mode === 8 || mode === 7) {
|
|
35767
|
+
activateGdiMappingMode(rCtx);
|
|
35768
|
+
}
|
|
35737
35769
|
}
|
|
35738
35770
|
}
|
|
35739
35771
|
return true;
|
|
35740
35772
|
}
|
|
35741
35773
|
case EMR_SCALEVIEWPORTEXTEX: {
|
|
35742
|
-
if (recSize >= 24) {
|
|
35774
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35743
35775
|
const xNum = view.getInt32(dataOff, true);
|
|
35744
35776
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35745
35777
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35755,7 +35787,7 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35755
35787
|
return true;
|
|
35756
35788
|
}
|
|
35757
35789
|
case EMR_SCALEWINDOWEXTEX: {
|
|
35758
|
-
if (recSize >= 24) {
|
|
35790
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35759
35791
|
const xNum = view.getInt32(dataOff, true);
|
|
35760
35792
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35761
35793
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35906,6 +35938,15 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35906
35938
|
}
|
|
35907
35939
|
rCtx.clipStack ?? (rCtx.clipStack = []);
|
|
35908
35940
|
rCtx.clipStack.push({ region: rCtx.clipRegion ?? null });
|
|
35941
|
+
rCtx.mappingStack ?? (rCtx.mappingStack = []);
|
|
35942
|
+
rCtx.mappingStack.push({
|
|
35943
|
+
mapMode: rCtx.mapMode,
|
|
35944
|
+
windowOrg: { ...rCtx.windowOrg },
|
|
35945
|
+
windowExt: { ...rCtx.windowExt },
|
|
35946
|
+
viewportOrg: { ...rCtx.viewportOrg },
|
|
35947
|
+
viewportExt: { ...rCtx.viewportExt },
|
|
35948
|
+
useMappingMode: rCtx.useMappingMode
|
|
35949
|
+
});
|
|
35909
35950
|
rCtx.stateStack.push(cloneState(state));
|
|
35910
35951
|
ctx.save();
|
|
35911
35952
|
if (rCtx.clipRegion) {
|
|
@@ -35915,23 +35956,31 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35915
35956
|
}
|
|
35916
35957
|
case EMR_RESTOREDC: {
|
|
35917
35958
|
if (recSize >= 12) {
|
|
35918
|
-
while (rCtx.clipSaveDepth > 0) {
|
|
35919
|
-
ctx.restore();
|
|
35920
|
-
rCtx.clipSaveDepth--;
|
|
35921
|
-
}
|
|
35922
35959
|
let rel = view.getInt32(dataOff, true);
|
|
35923
35960
|
if (rel < 0) {
|
|
35924
35961
|
rel = rCtx.stateStack.length + rel + 1;
|
|
35925
35962
|
}
|
|
35926
|
-
|
|
35963
|
+
if (rel < 1 || rel > rCtx.stateStack.length) {
|
|
35964
|
+
return true;
|
|
35965
|
+
}
|
|
35966
|
+
while (rCtx.clipSaveDepth > 0) {
|
|
35967
|
+
ctx.restore();
|
|
35968
|
+
rCtx.clipSaveDepth--;
|
|
35969
|
+
}
|
|
35970
|
+
while (rCtx.stateStack.length > rel) {
|
|
35927
35971
|
rCtx.stateStack.pop();
|
|
35928
35972
|
rCtx.clipStack?.pop();
|
|
35973
|
+
rCtx.mappingStack?.pop();
|
|
35929
35974
|
ctx.restore();
|
|
35930
35975
|
}
|
|
35931
35976
|
const restored = rCtx.stateStack.pop();
|
|
35932
35977
|
if (restored) {
|
|
35933
35978
|
const clipSnapshot = rCtx.clipStack?.pop();
|
|
35979
|
+
const mappingSnapshot = rCtx.mappingStack?.pop();
|
|
35934
35980
|
Object.assign(state, restored);
|
|
35981
|
+
if (mappingSnapshot) {
|
|
35982
|
+
Object.assign(rCtx, mappingSnapshot);
|
|
35983
|
+
}
|
|
35935
35984
|
ctx.restore();
|
|
35936
35985
|
rCtx.clipRegion = clipSnapshot?.region ?? null;
|
|
35937
35986
|
if (rCtx.clipRegion) {
|
|
@@ -38030,9 +38079,11 @@ function replayEmfRecords(view, ctx, bounds, canvasW, canvasH, dpiScale = 1, rep
|
|
|
38030
38079
|
// canvas like every other device coordinate (bounds' top-left to the
|
|
38031
38080
|
// canvas origin, scaled by sx/sy); see `deviceToCanvas`.
|
|
38032
38081
|
windowOrg: { x: 0, y: 0 },
|
|
38033
|
-
windowExt: { cx:
|
|
38082
|
+
windowExt: { cx: 1, cy: 1 },
|
|
38034
38083
|
viewportOrg: { x: 0, y: 0 },
|
|
38035
|
-
viewportExt: { cx:
|
|
38084
|
+
viewportExt: { cx: 1, cy: 1 },
|
|
38085
|
+
mapMode: 1,
|
|
38086
|
+
// MM_TEXT: the default DC uses one-to-one page/device units.
|
|
38036
38087
|
useMappingMode: false,
|
|
38037
38088
|
deviceToCanvas: true,
|
|
38038
38089
|
clipSaveDepth: 0,
|
|
@@ -38284,18 +38335,18 @@ function setMapMode(m, mode) {
|
|
|
38284
38335
|
}
|
|
38285
38336
|
m.mode = mode;
|
|
38286
38337
|
}
|
|
38287
|
-
function
|
|
38338
|
+
function extentsSettable2(m) {
|
|
38288
38339
|
return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
|
|
38289
38340
|
}
|
|
38290
38341
|
function setWindowExt(m, cx, cy) {
|
|
38291
|
-
if (!
|
|
38342
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38292
38343
|
return;
|
|
38293
38344
|
}
|
|
38294
38345
|
m.winExt = { cx, cy };
|
|
38295
38346
|
fixIsotropic(m);
|
|
38296
38347
|
}
|
|
38297
38348
|
function setViewportExt(m, cx, cy) {
|
|
38298
|
-
if (!
|
|
38349
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38299
38350
|
return;
|
|
38300
38351
|
}
|
|
38301
38352
|
m.vpExt = { cx, cy };
|
|
@@ -38305,7 +38356,7 @@ function scaled(v, num, den) {
|
|
|
38305
38356
|
return Math.trunc(v * num / den);
|
|
38306
38357
|
}
|
|
38307
38358
|
function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
38308
|
-
if (!
|
|
38359
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38309
38360
|
return;
|
|
38310
38361
|
}
|
|
38311
38362
|
const cx = scaled(m.winExt.cx, xNum, xDen);
|
|
@@ -38317,7 +38368,7 @@ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
|
38317
38368
|
fixIsotropic(m);
|
|
38318
38369
|
}
|
|
38319
38370
|
function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
|
|
38320
|
-
if (!
|
|
38371
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38321
38372
|
return;
|
|
38322
38373
|
}
|
|
38323
38374
|
const cx = scaled(m.vpExt.cx, xNum, xDen);
|
package/dist/index.js
CHANGED
|
@@ -27799,10 +27799,10 @@ function parseEmfHeader(view) {
|
|
|
27799
27799
|
};
|
|
27800
27800
|
}
|
|
27801
27801
|
function getRenderableEmfBounds(header) {
|
|
27802
|
-
const boundsW = header.bounds.right - header.bounds.left;
|
|
27803
|
-
const boundsH = header.bounds.bottom - header.bounds.top;
|
|
27802
|
+
const boundsW = header.bounds.right - header.bounds.left + 1;
|
|
27803
|
+
const boundsH = header.bounds.bottom - header.bounds.top + 1;
|
|
27804
27804
|
if (boundsW > 0 && boundsH > 0) {
|
|
27805
|
-
return header.bounds;
|
|
27805
|
+
return { ...header.bounds, right: header.bounds.right + 1, bottom: header.bounds.bottom + 1 };
|
|
27806
27806
|
}
|
|
27807
27807
|
if (header.frameW > 0 && header.frameH > 0) {
|
|
27808
27808
|
emfLog(
|
|
@@ -30834,6 +30834,13 @@ function insetFixBox(box, inset) {
|
|
|
30834
30834
|
}
|
|
30835
30835
|
return framed;
|
|
30836
30836
|
}
|
|
30837
|
+
function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
|
|
30838
|
+
const ax = BigInt(2 * sx - l - r);
|
|
30839
|
+
const ay = BigInt(2 * sy - t - b);
|
|
30840
|
+
const bx = BigInt(2 * ex - l - r);
|
|
30841
|
+
const by = BigInt(2 * ey - t - b);
|
|
30842
|
+
return ax * by === ay * bx && ax * bx + ay * by > 0n;
|
|
30843
|
+
}
|
|
30837
30844
|
function handleSetPixelV(rCtx, dataOff, recSize) {
|
|
30838
30845
|
const { ctx, view } = rCtx;
|
|
30839
30846
|
if (recSize >= 20) {
|
|
@@ -31191,7 +31198,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31191
31198
|
const rx = Math.abs(r - l) / 2;
|
|
31192
31199
|
const ry = Math.abs(b - t) / 2;
|
|
31193
31200
|
const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
|
|
31194
|
-
const
|
|
31201
|
+
const clockwise = state.arcDirection === 2;
|
|
31202
|
+
const fullEllipse = recType !== EMR_PIE && rx > 0 && ry > 0 && sameEllipseRay(l, t, r, b, startX, startY, endX, endY);
|
|
31203
|
+
const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
|
|
31195
31204
|
const rotated = hasWorldRotation(rCtx);
|
|
31196
31205
|
const unframed = fixBox(rCtx, l, t, r, b);
|
|
31197
31206
|
const inset = insideFrameInset(rCtx, unframed);
|
|
@@ -31205,13 +31214,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31205
31214
|
};
|
|
31206
31215
|
const isArcTo = recType === EMR_ARCTO;
|
|
31207
31216
|
const needsFill = recType === EMR_PIE || recType === EMR_CHORD;
|
|
31208
|
-
const clockwise = state.arcDirection === 2;
|
|
31209
31217
|
const startPoint = rotated ? gmapPoint(rCtx, cxA + rx * Math.cos(startAngle), cyA + ry * Math.sin(startAngle)) : { x: params.cx + params.rx * Math.cos(startAngle), y: params.cy + params.ry * Math.sin(startAngle) };
|
|
31210
31218
|
const build = (c) => {
|
|
31211
31219
|
if (recType === EMR_PIE) {
|
|
31212
31220
|
c.moveTo(params.cx, params.cy);
|
|
31221
|
+
} else if (!isArcTo && inPath) {
|
|
31222
|
+
c.moveTo(startPoint.x, startPoint.y);
|
|
31213
31223
|
}
|
|
31214
31224
|
if (isArcTo) {
|
|
31225
|
+
if (!inPath) {
|
|
31226
|
+
const from = currentFix(rCtx);
|
|
31227
|
+
c.moveTo(from[0] / 16, from[1] / 16);
|
|
31228
|
+
}
|
|
31215
31229
|
c.lineTo(startPoint.x, startPoint.y);
|
|
31216
31230
|
}
|
|
31217
31231
|
c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, startAngle, endAngle, !clockwise);
|
|
@@ -31231,7 +31245,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31231
31245
|
const rasterArgs = (immediate = false) => ({
|
|
31232
31246
|
box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
|
|
31233
31247
|
s: radialOnBox(fixPoint(rCtx, startX, startY)),
|
|
31234
|
-
|
|
31248
|
+
// Device FIX rounding can separate distinct radial points on the
|
|
31249
|
+
// same logical ray. Preserve their proven endpoint identity.
|
|
31250
|
+
e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
|
|
31235
31251
|
from: currentFix(rCtx)
|
|
31236
31252
|
});
|
|
31237
31253
|
if (inPath) {
|
|
@@ -35697,14 +35713,20 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35697
35713
|
}
|
|
35698
35714
|
|
|
35699
35715
|
// src/emf-gdi-transform-handlers.ts
|
|
35716
|
+
function extentsSettable(rCtx) {
|
|
35717
|
+
return rCtx.mapMode === 7 || rCtx.mapMode === 8;
|
|
35718
|
+
}
|
|
35700
35719
|
function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
35701
35720
|
const { view } = rCtx;
|
|
35702
35721
|
switch (recType) {
|
|
35703
35722
|
case EMR_SETWINDOWEXTEX: {
|
|
35704
|
-
if (recSize >= 16) {
|
|
35705
|
-
|
|
35706
|
-
|
|
35707
|
-
|
|
35723
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35724
|
+
const cx = view.getInt32(dataOff, true);
|
|
35725
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35726
|
+
if (cx !== 0 && cy !== 0) {
|
|
35727
|
+
rCtx.windowExt = { cx, cy };
|
|
35728
|
+
activateGdiMappingMode(rCtx);
|
|
35729
|
+
}
|
|
35708
35730
|
}
|
|
35709
35731
|
return true;
|
|
35710
35732
|
}
|
|
@@ -35717,10 +35739,13 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35717
35739
|
return true;
|
|
35718
35740
|
}
|
|
35719
35741
|
case EMR_SETVIEWPORTEXTEX: {
|
|
35720
|
-
if (recSize >= 16) {
|
|
35721
|
-
|
|
35722
|
-
|
|
35723
|
-
|
|
35742
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35743
|
+
const cx = view.getInt32(dataOff, true);
|
|
35744
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35745
|
+
if (cx !== 0 && cy !== 0) {
|
|
35746
|
+
rCtx.viewportExt = { cx, cy };
|
|
35747
|
+
activateGdiMappingMode(rCtx);
|
|
35748
|
+
}
|
|
35724
35749
|
}
|
|
35725
35750
|
return true;
|
|
35726
35751
|
}
|
|
@@ -35735,14 +35760,21 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35735
35760
|
case EMR_SETMAPMODE: {
|
|
35736
35761
|
if (recSize >= 12) {
|
|
35737
35762
|
const mode = view.getUint32(dataOff, true);
|
|
35738
|
-
if (mode
|
|
35739
|
-
|
|
35763
|
+
if (mode >= 1 && mode <= 8) {
|
|
35764
|
+
rCtx.mapMode = mode;
|
|
35765
|
+
if (mode === 1) {
|
|
35766
|
+
rCtx.windowExt = { cx: 1, cy: 1 };
|
|
35767
|
+
rCtx.viewportExt = { cx: 1, cy: 1 };
|
|
35768
|
+
}
|
|
35769
|
+
if (mode === 1 || mode === 8 || mode === 7) {
|
|
35770
|
+
activateGdiMappingMode(rCtx);
|
|
35771
|
+
}
|
|
35740
35772
|
}
|
|
35741
35773
|
}
|
|
35742
35774
|
return true;
|
|
35743
35775
|
}
|
|
35744
35776
|
case EMR_SCALEVIEWPORTEXTEX: {
|
|
35745
|
-
if (recSize >= 24) {
|
|
35777
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35746
35778
|
const xNum = view.getInt32(dataOff, true);
|
|
35747
35779
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35748
35780
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35758,7 +35790,7 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35758
35790
|
return true;
|
|
35759
35791
|
}
|
|
35760
35792
|
case EMR_SCALEWINDOWEXTEX: {
|
|
35761
|
-
if (recSize >= 24) {
|
|
35793
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35762
35794
|
const xNum = view.getInt32(dataOff, true);
|
|
35763
35795
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35764
35796
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35909,6 +35941,15 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35909
35941
|
}
|
|
35910
35942
|
rCtx.clipStack ?? (rCtx.clipStack = []);
|
|
35911
35943
|
rCtx.clipStack.push({ region: rCtx.clipRegion ?? null });
|
|
35944
|
+
rCtx.mappingStack ?? (rCtx.mappingStack = []);
|
|
35945
|
+
rCtx.mappingStack.push({
|
|
35946
|
+
mapMode: rCtx.mapMode,
|
|
35947
|
+
windowOrg: { ...rCtx.windowOrg },
|
|
35948
|
+
windowExt: { ...rCtx.windowExt },
|
|
35949
|
+
viewportOrg: { ...rCtx.viewportOrg },
|
|
35950
|
+
viewportExt: { ...rCtx.viewportExt },
|
|
35951
|
+
useMappingMode: rCtx.useMappingMode
|
|
35952
|
+
});
|
|
35912
35953
|
rCtx.stateStack.push(cloneState(state));
|
|
35913
35954
|
ctx.save();
|
|
35914
35955
|
if (rCtx.clipRegion) {
|
|
@@ -35918,23 +35959,31 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35918
35959
|
}
|
|
35919
35960
|
case EMR_RESTOREDC: {
|
|
35920
35961
|
if (recSize >= 12) {
|
|
35921
|
-
while (rCtx.clipSaveDepth > 0) {
|
|
35922
|
-
ctx.restore();
|
|
35923
|
-
rCtx.clipSaveDepth--;
|
|
35924
|
-
}
|
|
35925
35962
|
let rel = view.getInt32(dataOff, true);
|
|
35926
35963
|
if (rel < 0) {
|
|
35927
35964
|
rel = rCtx.stateStack.length + rel + 1;
|
|
35928
35965
|
}
|
|
35929
|
-
|
|
35966
|
+
if (rel < 1 || rel > rCtx.stateStack.length) {
|
|
35967
|
+
return true;
|
|
35968
|
+
}
|
|
35969
|
+
while (rCtx.clipSaveDepth > 0) {
|
|
35970
|
+
ctx.restore();
|
|
35971
|
+
rCtx.clipSaveDepth--;
|
|
35972
|
+
}
|
|
35973
|
+
while (rCtx.stateStack.length > rel) {
|
|
35930
35974
|
rCtx.stateStack.pop();
|
|
35931
35975
|
rCtx.clipStack?.pop();
|
|
35976
|
+
rCtx.mappingStack?.pop();
|
|
35932
35977
|
ctx.restore();
|
|
35933
35978
|
}
|
|
35934
35979
|
const restored = rCtx.stateStack.pop();
|
|
35935
35980
|
if (restored) {
|
|
35936
35981
|
const clipSnapshot = rCtx.clipStack?.pop();
|
|
35982
|
+
const mappingSnapshot = rCtx.mappingStack?.pop();
|
|
35937
35983
|
Object.assign(state, restored);
|
|
35984
|
+
if (mappingSnapshot) {
|
|
35985
|
+
Object.assign(rCtx, mappingSnapshot);
|
|
35986
|
+
}
|
|
35938
35987
|
ctx.restore();
|
|
35939
35988
|
rCtx.clipRegion = clipSnapshot?.region ?? null;
|
|
35940
35989
|
if (rCtx.clipRegion) {
|
|
@@ -38033,9 +38082,11 @@ function replayEmfRecords(view, ctx, bounds, canvasW, canvasH, dpiScale = 1, rep
|
|
|
38033
38082
|
// canvas like every other device coordinate (bounds' top-left to the
|
|
38034
38083
|
// canvas origin, scaled by sx/sy); see `deviceToCanvas`.
|
|
38035
38084
|
windowOrg: { x: 0, y: 0 },
|
|
38036
|
-
windowExt: { cx:
|
|
38085
|
+
windowExt: { cx: 1, cy: 1 },
|
|
38037
38086
|
viewportOrg: { x: 0, y: 0 },
|
|
38038
|
-
viewportExt: { cx:
|
|
38087
|
+
viewportExt: { cx: 1, cy: 1 },
|
|
38088
|
+
mapMode: 1,
|
|
38089
|
+
// MM_TEXT: the default DC uses one-to-one page/device units.
|
|
38039
38090
|
useMappingMode: false,
|
|
38040
38091
|
deviceToCanvas: true,
|
|
38041
38092
|
clipSaveDepth: 0,
|
|
@@ -38287,18 +38338,18 @@ function setMapMode(m, mode) {
|
|
|
38287
38338
|
}
|
|
38288
38339
|
m.mode = mode;
|
|
38289
38340
|
}
|
|
38290
|
-
function
|
|
38341
|
+
function extentsSettable2(m) {
|
|
38291
38342
|
return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
|
|
38292
38343
|
}
|
|
38293
38344
|
function setWindowExt(m, cx, cy) {
|
|
38294
|
-
if (!
|
|
38345
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38295
38346
|
return;
|
|
38296
38347
|
}
|
|
38297
38348
|
m.winExt = { cx, cy };
|
|
38298
38349
|
fixIsotropic(m);
|
|
38299
38350
|
}
|
|
38300
38351
|
function setViewportExt(m, cx, cy) {
|
|
38301
|
-
if (!
|
|
38352
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38302
38353
|
return;
|
|
38303
38354
|
}
|
|
38304
38355
|
m.vpExt = { cx, cy };
|
|
@@ -38308,7 +38359,7 @@ function scaled(v, num, den) {
|
|
|
38308
38359
|
return Math.trunc(v * num / den);
|
|
38309
38360
|
}
|
|
38310
38361
|
function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
38311
|
-
if (!
|
|
38362
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38312
38363
|
return;
|
|
38313
38364
|
}
|
|
38314
38365
|
const cx = scaled(m.winExt.cx, xNum, xDen);
|
|
@@ -38320,7 +38371,7 @@ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
|
38320
38371
|
fixIsotropic(m);
|
|
38321
38372
|
}
|
|
38322
38373
|
function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
|
|
38323
|
-
if (!
|
|
38374
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38324
38375
|
return;
|
|
38325
38376
|
}
|
|
38326
38377
|
const cx = scaled(m.vpExt.cx, xNum, xDen);
|
package/dist/index.mjs
CHANGED
|
@@ -27797,10 +27797,10 @@ function parseEmfHeader(view) {
|
|
|
27797
27797
|
};
|
|
27798
27798
|
}
|
|
27799
27799
|
function getRenderableEmfBounds(header) {
|
|
27800
|
-
const boundsW = header.bounds.right - header.bounds.left;
|
|
27801
|
-
const boundsH = header.bounds.bottom - header.bounds.top;
|
|
27800
|
+
const boundsW = header.bounds.right - header.bounds.left + 1;
|
|
27801
|
+
const boundsH = header.bounds.bottom - header.bounds.top + 1;
|
|
27802
27802
|
if (boundsW > 0 && boundsH > 0) {
|
|
27803
|
-
return header.bounds;
|
|
27803
|
+
return { ...header.bounds, right: header.bounds.right + 1, bottom: header.bounds.bottom + 1 };
|
|
27804
27804
|
}
|
|
27805
27805
|
if (header.frameW > 0 && header.frameH > 0) {
|
|
27806
27806
|
emfLog(
|
|
@@ -30832,6 +30832,13 @@ function insetFixBox(box, inset) {
|
|
|
30832
30832
|
}
|
|
30833
30833
|
return framed;
|
|
30834
30834
|
}
|
|
30835
|
+
function sameEllipseRay(l, t, r, b, sx, sy, ex, ey) {
|
|
30836
|
+
const ax = BigInt(2 * sx - l - r);
|
|
30837
|
+
const ay = BigInt(2 * sy - t - b);
|
|
30838
|
+
const bx = BigInt(2 * ex - l - r);
|
|
30839
|
+
const by = BigInt(2 * ey - t - b);
|
|
30840
|
+
return ax * by === ay * bx && ax * bx + ay * by > 0n;
|
|
30841
|
+
}
|
|
30835
30842
|
function handleSetPixelV(rCtx, dataOff, recSize) {
|
|
30836
30843
|
const { ctx, view } = rCtx;
|
|
30837
30844
|
if (recSize >= 20) {
|
|
@@ -31189,7 +31196,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31189
31196
|
const rx = Math.abs(r - l) / 2;
|
|
31190
31197
|
const ry = Math.abs(b - t) / 2;
|
|
31191
31198
|
const startAngle = Math.atan2((startY - cyA) / (ry || 1), (startX - cxA) / (rx || 1));
|
|
31192
|
-
const
|
|
31199
|
+
const clockwise = state.arcDirection === 2;
|
|
31200
|
+
const fullEllipse = recType !== EMR_PIE && rx > 0 && ry > 0 && sameEllipseRay(l, t, r, b, startX, startY, endX, endY);
|
|
31201
|
+
const endAngle = fullEllipse ? startAngle + (clockwise ? 2 : -2) * Math.PI : Math.atan2((endY - cyA) / (ry || 1), (endX - cxA) / (rx || 1));
|
|
31193
31202
|
const rotated = hasWorldRotation(rCtx);
|
|
31194
31203
|
const unframed = fixBox(rCtx, l, t, r, b);
|
|
31195
31204
|
const inset = insideFrameInset(rCtx, unframed);
|
|
@@ -31203,13 +31212,18 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31203
31212
|
};
|
|
31204
31213
|
const isArcTo = recType === EMR_ARCTO;
|
|
31205
31214
|
const needsFill = recType === EMR_PIE || recType === EMR_CHORD;
|
|
31206
|
-
const clockwise = state.arcDirection === 2;
|
|
31207
31215
|
const startPoint = rotated ? gmapPoint(rCtx, cxA + rx * Math.cos(startAngle), cyA + ry * Math.sin(startAngle)) : { x: params.cx + params.rx * Math.cos(startAngle), y: params.cy + params.ry * Math.sin(startAngle) };
|
|
31208
31216
|
const build = (c) => {
|
|
31209
31217
|
if (recType === EMR_PIE) {
|
|
31210
31218
|
c.moveTo(params.cx, params.cy);
|
|
31219
|
+
} else if (!isArcTo && inPath) {
|
|
31220
|
+
c.moveTo(startPoint.x, startPoint.y);
|
|
31211
31221
|
}
|
|
31212
31222
|
if (isArcTo) {
|
|
31223
|
+
if (!inPath) {
|
|
31224
|
+
const from = currentFix(rCtx);
|
|
31225
|
+
c.moveTo(from[0] / 16, from[1] / 16);
|
|
31226
|
+
}
|
|
31213
31227
|
c.lineTo(startPoint.x, startPoint.y);
|
|
31214
31228
|
}
|
|
31215
31229
|
c.ellipse(params.cx, params.cy, params.rx, params.ry, params.rotation, startAngle, endAngle, !clockwise);
|
|
@@ -31229,7 +31243,9 @@ function handleArcFamily(rCtx, recType, dataOff, recSize) {
|
|
|
31229
31243
|
const rasterArgs = (immediate = false) => ({
|
|
31230
31244
|
box: inset ? framed : immediate && needsFill ? curvedFixBox(rCtx, l, t, r, b) : unframed,
|
|
31231
31245
|
s: radialOnBox(fixPoint(rCtx, startX, startY)),
|
|
31232
|
-
|
|
31246
|
+
// Device FIX rounding can separate distinct radial points on the
|
|
31247
|
+
// same logical ray. Preserve their proven endpoint identity.
|
|
31248
|
+
e: fullEllipse ? radialOnBox(fixPoint(rCtx, startX, startY)) : radialOnBox(fixPoint(rCtx, endX, endY)),
|
|
31233
31249
|
from: currentFix(rCtx)
|
|
31234
31250
|
});
|
|
31235
31251
|
if (inPath) {
|
|
@@ -35695,14 +35711,20 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35695
35711
|
}
|
|
35696
35712
|
|
|
35697
35713
|
// src/emf-gdi-transform-handlers.ts
|
|
35714
|
+
function extentsSettable(rCtx) {
|
|
35715
|
+
return rCtx.mapMode === 7 || rCtx.mapMode === 8;
|
|
35716
|
+
}
|
|
35698
35717
|
function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
35699
35718
|
const { view } = rCtx;
|
|
35700
35719
|
switch (recType) {
|
|
35701
35720
|
case EMR_SETWINDOWEXTEX: {
|
|
35702
|
-
if (recSize >= 16) {
|
|
35703
|
-
|
|
35704
|
-
|
|
35705
|
-
|
|
35721
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35722
|
+
const cx = view.getInt32(dataOff, true);
|
|
35723
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35724
|
+
if (cx !== 0 && cy !== 0) {
|
|
35725
|
+
rCtx.windowExt = { cx, cy };
|
|
35726
|
+
activateGdiMappingMode(rCtx);
|
|
35727
|
+
}
|
|
35706
35728
|
}
|
|
35707
35729
|
return true;
|
|
35708
35730
|
}
|
|
@@ -35715,10 +35737,13 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35715
35737
|
return true;
|
|
35716
35738
|
}
|
|
35717
35739
|
case EMR_SETVIEWPORTEXTEX: {
|
|
35718
|
-
if (recSize >= 16) {
|
|
35719
|
-
|
|
35720
|
-
|
|
35721
|
-
|
|
35740
|
+
if (recSize >= 16 && extentsSettable(rCtx)) {
|
|
35741
|
+
const cx = view.getInt32(dataOff, true);
|
|
35742
|
+
const cy = view.getInt32(dataOff + 4, true);
|
|
35743
|
+
if (cx !== 0 && cy !== 0) {
|
|
35744
|
+
rCtx.viewportExt = { cx, cy };
|
|
35745
|
+
activateGdiMappingMode(rCtx);
|
|
35746
|
+
}
|
|
35722
35747
|
}
|
|
35723
35748
|
return true;
|
|
35724
35749
|
}
|
|
@@ -35733,14 +35758,21 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35733
35758
|
case EMR_SETMAPMODE: {
|
|
35734
35759
|
if (recSize >= 12) {
|
|
35735
35760
|
const mode = view.getUint32(dataOff, true);
|
|
35736
|
-
if (mode
|
|
35737
|
-
|
|
35761
|
+
if (mode >= 1 && mode <= 8) {
|
|
35762
|
+
rCtx.mapMode = mode;
|
|
35763
|
+
if (mode === 1) {
|
|
35764
|
+
rCtx.windowExt = { cx: 1, cy: 1 };
|
|
35765
|
+
rCtx.viewportExt = { cx: 1, cy: 1 };
|
|
35766
|
+
}
|
|
35767
|
+
if (mode === 1 || mode === 8 || mode === 7) {
|
|
35768
|
+
activateGdiMappingMode(rCtx);
|
|
35769
|
+
}
|
|
35738
35770
|
}
|
|
35739
35771
|
}
|
|
35740
35772
|
return true;
|
|
35741
35773
|
}
|
|
35742
35774
|
case EMR_SCALEVIEWPORTEXTEX: {
|
|
35743
|
-
if (recSize >= 24) {
|
|
35775
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35744
35776
|
const xNum = view.getInt32(dataOff, true);
|
|
35745
35777
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35746
35778
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35756,7 +35788,7 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
|
|
|
35756
35788
|
return true;
|
|
35757
35789
|
}
|
|
35758
35790
|
case EMR_SCALEWINDOWEXTEX: {
|
|
35759
|
-
if (recSize >= 24) {
|
|
35791
|
+
if (recSize >= 24 && extentsSettable(rCtx)) {
|
|
35760
35792
|
const xNum = view.getInt32(dataOff, true);
|
|
35761
35793
|
const xDenom = view.getInt32(dataOff + 4, true);
|
|
35762
35794
|
const yNum = view.getInt32(dataOff + 8, true);
|
|
@@ -35907,6 +35939,15 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35907
35939
|
}
|
|
35908
35940
|
rCtx.clipStack ?? (rCtx.clipStack = []);
|
|
35909
35941
|
rCtx.clipStack.push({ region: rCtx.clipRegion ?? null });
|
|
35942
|
+
rCtx.mappingStack ?? (rCtx.mappingStack = []);
|
|
35943
|
+
rCtx.mappingStack.push({
|
|
35944
|
+
mapMode: rCtx.mapMode,
|
|
35945
|
+
windowOrg: { ...rCtx.windowOrg },
|
|
35946
|
+
windowExt: { ...rCtx.windowExt },
|
|
35947
|
+
viewportOrg: { ...rCtx.viewportOrg },
|
|
35948
|
+
viewportExt: { ...rCtx.viewportExt },
|
|
35949
|
+
useMappingMode: rCtx.useMappingMode
|
|
35950
|
+
});
|
|
35910
35951
|
rCtx.stateStack.push(cloneState(state));
|
|
35911
35952
|
ctx.save();
|
|
35912
35953
|
if (rCtx.clipRegion) {
|
|
@@ -35916,23 +35957,31 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
35916
35957
|
}
|
|
35917
35958
|
case EMR_RESTOREDC: {
|
|
35918
35959
|
if (recSize >= 12) {
|
|
35919
|
-
while (rCtx.clipSaveDepth > 0) {
|
|
35920
|
-
ctx.restore();
|
|
35921
|
-
rCtx.clipSaveDepth--;
|
|
35922
|
-
}
|
|
35923
35960
|
let rel = view.getInt32(dataOff, true);
|
|
35924
35961
|
if (rel < 0) {
|
|
35925
35962
|
rel = rCtx.stateStack.length + rel + 1;
|
|
35926
35963
|
}
|
|
35927
|
-
|
|
35964
|
+
if (rel < 1 || rel > rCtx.stateStack.length) {
|
|
35965
|
+
return true;
|
|
35966
|
+
}
|
|
35967
|
+
while (rCtx.clipSaveDepth > 0) {
|
|
35968
|
+
ctx.restore();
|
|
35969
|
+
rCtx.clipSaveDepth--;
|
|
35970
|
+
}
|
|
35971
|
+
while (rCtx.stateStack.length > rel) {
|
|
35928
35972
|
rCtx.stateStack.pop();
|
|
35929
35973
|
rCtx.clipStack?.pop();
|
|
35974
|
+
rCtx.mappingStack?.pop();
|
|
35930
35975
|
ctx.restore();
|
|
35931
35976
|
}
|
|
35932
35977
|
const restored = rCtx.stateStack.pop();
|
|
35933
35978
|
if (restored) {
|
|
35934
35979
|
const clipSnapshot = rCtx.clipStack?.pop();
|
|
35980
|
+
const mappingSnapshot = rCtx.mappingStack?.pop();
|
|
35935
35981
|
Object.assign(state, restored);
|
|
35982
|
+
if (mappingSnapshot) {
|
|
35983
|
+
Object.assign(rCtx, mappingSnapshot);
|
|
35984
|
+
}
|
|
35936
35985
|
ctx.restore();
|
|
35937
35986
|
rCtx.clipRegion = clipSnapshot?.region ?? null;
|
|
35938
35987
|
if (rCtx.clipRegion) {
|
|
@@ -38031,9 +38080,11 @@ function replayEmfRecords(view, ctx, bounds, canvasW, canvasH, dpiScale = 1, rep
|
|
|
38031
38080
|
// canvas like every other device coordinate (bounds' top-left to the
|
|
38032
38081
|
// canvas origin, scaled by sx/sy); see `deviceToCanvas`.
|
|
38033
38082
|
windowOrg: { x: 0, y: 0 },
|
|
38034
|
-
windowExt: { cx:
|
|
38083
|
+
windowExt: { cx: 1, cy: 1 },
|
|
38035
38084
|
viewportOrg: { x: 0, y: 0 },
|
|
38036
|
-
viewportExt: { cx:
|
|
38085
|
+
viewportExt: { cx: 1, cy: 1 },
|
|
38086
|
+
mapMode: 1,
|
|
38087
|
+
// MM_TEXT: the default DC uses one-to-one page/device units.
|
|
38037
38088
|
useMappingMode: false,
|
|
38038
38089
|
deviceToCanvas: true,
|
|
38039
38090
|
clipSaveDepth: 0,
|
|
@@ -38285,18 +38336,18 @@ function setMapMode(m, mode) {
|
|
|
38285
38336
|
}
|
|
38286
38337
|
m.mode = mode;
|
|
38287
38338
|
}
|
|
38288
|
-
function
|
|
38339
|
+
function extentsSettable2(m) {
|
|
38289
38340
|
return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
|
|
38290
38341
|
}
|
|
38291
38342
|
function setWindowExt(m, cx, cy) {
|
|
38292
|
-
if (!
|
|
38343
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38293
38344
|
return;
|
|
38294
38345
|
}
|
|
38295
38346
|
m.winExt = { cx, cy };
|
|
38296
38347
|
fixIsotropic(m);
|
|
38297
38348
|
}
|
|
38298
38349
|
function setViewportExt(m, cx, cy) {
|
|
38299
|
-
if (!
|
|
38350
|
+
if (!extentsSettable2(m) || cx === 0 || cy === 0) {
|
|
38300
38351
|
return;
|
|
38301
38352
|
}
|
|
38302
38353
|
m.vpExt = { cx, cy };
|
|
@@ -38306,7 +38357,7 @@ function scaled(v, num, den) {
|
|
|
38306
38357
|
return Math.trunc(v * num / den);
|
|
38307
38358
|
}
|
|
38308
38359
|
function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
38309
|
-
if (!
|
|
38360
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38310
38361
|
return;
|
|
38311
38362
|
}
|
|
38312
38363
|
const cx = scaled(m.winExt.cx, xNum, xDen);
|
|
@@ -38318,7 +38369,7 @@ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
|
|
|
38318
38369
|
fixIsotropic(m);
|
|
38319
38370
|
}
|
|
38320
38371
|
function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
|
|
38321
|
-
if (!
|
|
38372
|
+
if (!extentsSettable2(m) || !xDen || !yDen) {
|
|
38322
38373
|
return;
|
|
38323
38374
|
}
|
|
38324
38375
|
const cx = scaled(m.vpExt.cx, xNum, xDen);
|