emf-converter 1.6.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -10
- package/dist/index.d.mts +8 -12
- package/dist/index.d.ts +8 -12
- package/dist/index.js +24 -29
- package/dist/index.mjs +24 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,22 +44,20 @@ const pngDataUrl = await convertEmfToDataUrl(emfBuffer);
|
|
|
44
44
|
const wmfPng = await convertWmfToDataUrl(wmfBuffer);
|
|
45
45
|
|
|
46
46
|
// Optional: limit output dimensions (aspect ratio preserved)
|
|
47
|
-
const scaled = await convertEmfToDataUrl(emfBuffer, 1024, 768);
|
|
47
|
+
const scaled = await convertEmfToDataUrl(emfBuffer, { maxWidth: 1024, maxHeight: 768 });
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Both functions return `Promise<string | null>` — `null` if the buffer is invalid or no Canvas API is available.
|
|
51
51
|
|
|
52
52
|
## API
|
|
53
53
|
|
|
54
|
-
### `convertEmfToDataUrl(buffer,
|
|
54
|
+
### `convertEmfToDataUrl(buffer, options?)` · `convertWmfToDataUrl(buffer, options?)`
|
|
55
55
|
|
|
56
|
-
| Parameter | Type
|
|
57
|
-
| ----------- |
|
|
58
|
-
| `buffer` | `ArrayBuffer`
|
|
59
|
-
| `
|
|
60
|
-
|
|
|
61
|
-
| `options` | `EmfConvertOptions \| number` (opt.) | Options object, or a numeric `dpiScale` (legacy) |
|
|
62
|
-
| **Returns** | `Promise<string \| null>` | PNG data URL or `null` on failure |
|
|
56
|
+
| Parameter | Type | Description |
|
|
57
|
+
| ----------- | ----------------------------- | ---------------------------------------------------- |
|
|
58
|
+
| `buffer` | `ArrayBuffer` | Raw EMF/WMF file bytes |
|
|
59
|
+
| `options` | `EmfConvertOptions` (optional)| Output size, DPI scale, record limits, font mapping |
|
|
60
|
+
| **Returns** | `Promise<string \| null>` | PNG data URL or `null` on failure |
|
|
63
61
|
|
|
64
62
|
#### `EmfConvertOptions`
|
|
65
63
|
|
|
@@ -73,7 +71,7 @@ Both functions return `Promise<string | null>` — `null` if the buffer is inval
|
|
|
73
71
|
| `fontFamilyMap` | `Record<string, string>` | — | Maps Windows face names (case-insensitive) to fonts available locally, e.g. `{ calibri: 'Carlito' }` |
|
|
74
72
|
|
|
75
73
|
```ts
|
|
76
|
-
const png = await convertEmfToDataUrl(buffer,
|
|
74
|
+
const png = await convertEmfToDataUrl(buffer, {
|
|
77
75
|
dpiScale: 2,
|
|
78
76
|
fontFamilyMap: { calibri: 'Carlito', 'ms shell dlg': 'Tahoma' },
|
|
79
77
|
});
|
package/dist/index.d.mts
CHANGED
|
@@ -58,14 +58,12 @@ interface EmfConvertOptions {
|
|
|
58
58
|
* - The logical bounds are zero-sized or negative.
|
|
59
59
|
* - No canvas API is available (e.g. headless test environment).
|
|
60
60
|
*
|
|
61
|
-
* @param buffer
|
|
62
|
-
* @param
|
|
63
|
-
*
|
|
64
|
-
* @param optionsOrDpiScale - Either an {@link EmfConvertOptions} object, or
|
|
65
|
-
* a numeric DPI scale (for backward compatibility). Default DPI scale is 2.
|
|
61
|
+
* @param buffer - The raw EMF file bytes.
|
|
62
|
+
* @param options - Optional {@link EmfConvertOptions} controlling output size,
|
|
63
|
+
* DPI scale, record limits, and font mapping.
|
|
66
64
|
* @returns A `data:image/png;base64,…` string, or `null` on failure.
|
|
67
65
|
*/
|
|
68
|
-
declare function convertEmfToDataUrl(buffer: ArrayBuffer,
|
|
66
|
+
declare function convertEmfToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
|
|
69
67
|
/**
|
|
70
68
|
* Converts a WMF (Windows Metafile) binary buffer to a PNG data-URL string.
|
|
71
69
|
*
|
|
@@ -80,14 +78,12 @@ declare function convertEmfToDataUrl(buffer: ArrayBuffer, maxWidth?: number, max
|
|
|
80
78
|
* - The header cannot be parsed or reports invalid dimensions.
|
|
81
79
|
* - No canvas API is available.
|
|
82
80
|
*
|
|
83
|
-
* @param buffer
|
|
84
|
-
* @param
|
|
85
|
-
*
|
|
86
|
-
* @param optionsOrDpiScale - Either an {@link EmfConvertOptions} object, or
|
|
87
|
-
* a numeric DPI scale. Default DPI scale is 2.
|
|
81
|
+
* @param buffer - The raw WMF file bytes.
|
|
82
|
+
* @param options - Optional {@link EmfConvertOptions} controlling output size,
|
|
83
|
+
* DPI scale, record limits, and font mapping.
|
|
88
84
|
* @returns A `data:image/png;base64,…` string, or `null` on failure.
|
|
89
85
|
*/
|
|
90
|
-
declare function convertWmfToDataUrl(buffer: ArrayBuffer,
|
|
86
|
+
declare function convertWmfToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
|
|
91
87
|
|
|
92
88
|
/**
|
|
93
89
|
* Canvas creation, styling, string reading, stock objects, and export helpers.
|
package/dist/index.d.ts
CHANGED
|
@@ -58,14 +58,12 @@ interface EmfConvertOptions {
|
|
|
58
58
|
* - The logical bounds are zero-sized or negative.
|
|
59
59
|
* - No canvas API is available (e.g. headless test environment).
|
|
60
60
|
*
|
|
61
|
-
* @param buffer
|
|
62
|
-
* @param
|
|
63
|
-
*
|
|
64
|
-
* @param optionsOrDpiScale - Either an {@link EmfConvertOptions} object, or
|
|
65
|
-
* a numeric DPI scale (for backward compatibility). Default DPI scale is 2.
|
|
61
|
+
* @param buffer - The raw EMF file bytes.
|
|
62
|
+
* @param options - Optional {@link EmfConvertOptions} controlling output size,
|
|
63
|
+
* DPI scale, record limits, and font mapping.
|
|
66
64
|
* @returns A `data:image/png;base64,…` string, or `null` on failure.
|
|
67
65
|
*/
|
|
68
|
-
declare function convertEmfToDataUrl(buffer: ArrayBuffer,
|
|
66
|
+
declare function convertEmfToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
|
|
69
67
|
/**
|
|
70
68
|
* Converts a WMF (Windows Metafile) binary buffer to a PNG data-URL string.
|
|
71
69
|
*
|
|
@@ -80,14 +78,12 @@ declare function convertEmfToDataUrl(buffer: ArrayBuffer, maxWidth?: number, max
|
|
|
80
78
|
* - The header cannot be parsed or reports invalid dimensions.
|
|
81
79
|
* - No canvas API is available.
|
|
82
80
|
*
|
|
83
|
-
* @param buffer
|
|
84
|
-
* @param
|
|
85
|
-
*
|
|
86
|
-
* @param optionsOrDpiScale - Either an {@link EmfConvertOptions} object, or
|
|
87
|
-
* a numeric DPI scale. Default DPI scale is 2.
|
|
81
|
+
* @param buffer - The raw WMF file bytes.
|
|
82
|
+
* @param options - Optional {@link EmfConvertOptions} controlling output size,
|
|
83
|
+
* DPI scale, record limits, and font mapping.
|
|
88
84
|
* @returns A `data:image/png;base64,…` string, or `null` on failure.
|
|
89
85
|
*/
|
|
90
|
-
declare function convertWmfToDataUrl(buffer: ArrayBuffer,
|
|
86
|
+
declare function convertWmfToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
|
|
91
87
|
|
|
92
88
|
/**
|
|
93
89
|
* Canvas creation, styling, string reading, stock objects, and export helpers.
|
package/dist/index.js
CHANGED
|
@@ -1402,14 +1402,9 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
|
|
|
1402
1402
|
if (text.length > 0) {
|
|
1403
1403
|
applyFont(ctx, state);
|
|
1404
1404
|
ctx.fillStyle = state.textColor;
|
|
1405
|
-
|
|
1405
|
+
const vAlign = state.textAlign & 24;
|
|
1406
|
+
const alignBaseline = vAlign === 24 ? "alphabetic" : vAlign === 8 ? "bottom" : "top";
|
|
1406
1407
|
let alignHoriz = "left";
|
|
1407
|
-
if (state.textAlign & 8) {
|
|
1408
|
-
alignBaseline = "bottom";
|
|
1409
|
-
}
|
|
1410
|
-
if (state.textAlign & 24) {
|
|
1411
|
-
alignBaseline = "alphabetic";
|
|
1412
|
-
}
|
|
1413
1408
|
if (state.textAlign & 6) {
|
|
1414
1409
|
alignHoriz = "center";
|
|
1415
1410
|
}
|
|
@@ -1437,17 +1432,29 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
|
|
|
1437
1432
|
}
|
|
1438
1433
|
return true;
|
|
1439
1434
|
}
|
|
1435
|
+
var ROP_PATCOPY = 15728673;
|
|
1436
|
+
var BS_NULL = 1;
|
|
1440
1437
|
function handleBitBlt(rCtx, offset, dataOff, recSize) {
|
|
1441
|
-
const { ctx, view } = rCtx;
|
|
1438
|
+
const { ctx, view, state } = rCtx;
|
|
1442
1439
|
if (recSize >= 96) {
|
|
1443
1440
|
const dstX = view.getInt32(dataOff + 16, true);
|
|
1444
1441
|
const dstY = view.getInt32(dataOff + 20, true);
|
|
1445
1442
|
const dstW = view.getInt32(dataOff + 24, true);
|
|
1446
1443
|
const dstH = view.getInt32(dataOff + 28, true);
|
|
1444
|
+
const rop = view.getUint32(dataOff + 32, true);
|
|
1447
1445
|
const offBmiSrc = view.getUint32(dataOff + 76, true);
|
|
1448
1446
|
const cbBmiSrc = view.getUint32(dataOff + 80, true);
|
|
1449
1447
|
const offBitsSrc = view.getUint32(dataOff + 84, true);
|
|
1450
1448
|
const cbBitsSrc = view.getUint32(dataOff + 88, true);
|
|
1449
|
+
if (offBmiSrc === 0 && rop === ROP_PATCOPY) {
|
|
1450
|
+
const prevFill = ctx.fillStyle;
|
|
1451
|
+
if (state.brushStyle !== BS_NULL) {
|
|
1452
|
+
ctx.fillStyle = state.brushColor;
|
|
1453
|
+
ctx.fillRect(gmx(rCtx, dstX), gmy(rCtx, dstY), gmw(rCtx, dstW), gmh(rCtx, dstH));
|
|
1454
|
+
}
|
|
1455
|
+
ctx.fillStyle = prevFill;
|
|
1456
|
+
return true;
|
|
1457
|
+
}
|
|
1451
1458
|
if (offBmiSrc > 0 && cbBmiSrc > 0 && offBitsSrc > 0 && cbBitsSrc > 0) {
|
|
1452
1459
|
const imageData = decodeDibToImageData(
|
|
1453
1460
|
view,
|
|
@@ -4857,19 +4864,7 @@ async function processDeferredImages(ctx, deferredImages, recursionDepth = 0) {
|
|
|
4857
4864
|
continue;
|
|
4858
4865
|
}
|
|
4859
4866
|
emfLog(` Deferred image [${idx}]: recursively converting embedded metafile...`);
|
|
4860
|
-
const metafileDataUrl = await convertEmfToDataUrl(
|
|
4861
|
-
plainBuffer,
|
|
4862
|
-
void 0,
|
|
4863
|
-
void 0,
|
|
4864
|
-
void 0,
|
|
4865
|
-
recursionDepth + 1
|
|
4866
|
-
) ?? await convertWmfToDataUrl(
|
|
4867
|
-
plainBuffer,
|
|
4868
|
-
void 0,
|
|
4869
|
-
void 0,
|
|
4870
|
-
void 0,
|
|
4871
|
-
recursionDepth + 1
|
|
4872
|
-
);
|
|
4867
|
+
const metafileDataUrl = await convertEmfToDataUrl(plainBuffer, void 0, recursionDepth + 1) ?? await convertWmfToDataUrl(plainBuffer, void 0, recursionDepth + 1);
|
|
4873
4868
|
if (metafileDataUrl) {
|
|
4874
4869
|
emfLog(
|
|
4875
4870
|
` Deferred image [${idx}]: metafile converted, dataUrl length=${metafileDataUrl.length}`
|
|
@@ -4914,14 +4909,14 @@ async function processDeferredImages(ctx, deferredImages, recursionDepth = 0) {
|
|
|
4914
4909
|
}
|
|
4915
4910
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
4916
4911
|
}
|
|
4917
|
-
async function convertEmfToDataUrl(buffer,
|
|
4912
|
+
async function convertEmfToDataUrl(buffer, options, recursionDepth = 0) {
|
|
4918
4913
|
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
4919
4914
|
return null;
|
|
4920
4915
|
}
|
|
4921
|
-
const opts =
|
|
4916
|
+
const opts = options ?? {};
|
|
4922
4917
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
4923
|
-
const effectiveMaxWidth =
|
|
4924
|
-
const effectiveMaxHeight =
|
|
4918
|
+
const effectiveMaxWidth = opts.maxWidth;
|
|
4919
|
+
const effectiveMaxHeight = opts.maxHeight;
|
|
4925
4920
|
const replayOptions = {
|
|
4926
4921
|
maxRecords: opts.maxRecords,
|
|
4927
4922
|
maxRecordsEmfPlus: opts.maxRecords,
|
|
@@ -4999,14 +4994,14 @@ async function convertEmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScal
|
|
|
4999
4994
|
return null;
|
|
5000
4995
|
}
|
|
5001
4996
|
}
|
|
5002
|
-
async function convertWmfToDataUrl(buffer,
|
|
4997
|
+
async function convertWmfToDataUrl(buffer, options, recursionDepth = 0) {
|
|
5003
4998
|
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
5004
4999
|
return null;
|
|
5005
5000
|
}
|
|
5006
|
-
const opts =
|
|
5001
|
+
const opts = options ?? {};
|
|
5007
5002
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
5008
|
-
const effectiveMaxWidth =
|
|
5009
|
-
const effectiveMaxHeight =
|
|
5003
|
+
const effectiveMaxWidth = opts.maxWidth;
|
|
5004
|
+
const effectiveMaxHeight = opts.maxHeight;
|
|
5010
5005
|
const replayOptions = {
|
|
5011
5006
|
maxRecords: opts.maxRecords,
|
|
5012
5007
|
fontFamilyMap: opts.fontFamilyMap
|
package/dist/index.mjs
CHANGED
|
@@ -1400,14 +1400,9 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
|
|
|
1400
1400
|
if (text.length > 0) {
|
|
1401
1401
|
applyFont(ctx, state);
|
|
1402
1402
|
ctx.fillStyle = state.textColor;
|
|
1403
|
-
|
|
1403
|
+
const vAlign = state.textAlign & 24;
|
|
1404
|
+
const alignBaseline = vAlign === 24 ? "alphabetic" : vAlign === 8 ? "bottom" : "top";
|
|
1404
1405
|
let alignHoriz = "left";
|
|
1405
|
-
if (state.textAlign & 8) {
|
|
1406
|
-
alignBaseline = "bottom";
|
|
1407
|
-
}
|
|
1408
|
-
if (state.textAlign & 24) {
|
|
1409
|
-
alignBaseline = "alphabetic";
|
|
1410
|
-
}
|
|
1411
1406
|
if (state.textAlign & 6) {
|
|
1412
1407
|
alignHoriz = "center";
|
|
1413
1408
|
}
|
|
@@ -1435,17 +1430,29 @@ function handleExtTextOutW(rCtx, offset, dataOff, recSize) {
|
|
|
1435
1430
|
}
|
|
1436
1431
|
return true;
|
|
1437
1432
|
}
|
|
1433
|
+
var ROP_PATCOPY = 15728673;
|
|
1434
|
+
var BS_NULL = 1;
|
|
1438
1435
|
function handleBitBlt(rCtx, offset, dataOff, recSize) {
|
|
1439
|
-
const { ctx, view } = rCtx;
|
|
1436
|
+
const { ctx, view, state } = rCtx;
|
|
1440
1437
|
if (recSize >= 96) {
|
|
1441
1438
|
const dstX = view.getInt32(dataOff + 16, true);
|
|
1442
1439
|
const dstY = view.getInt32(dataOff + 20, true);
|
|
1443
1440
|
const dstW = view.getInt32(dataOff + 24, true);
|
|
1444
1441
|
const dstH = view.getInt32(dataOff + 28, true);
|
|
1442
|
+
const rop = view.getUint32(dataOff + 32, true);
|
|
1445
1443
|
const offBmiSrc = view.getUint32(dataOff + 76, true);
|
|
1446
1444
|
const cbBmiSrc = view.getUint32(dataOff + 80, true);
|
|
1447
1445
|
const offBitsSrc = view.getUint32(dataOff + 84, true);
|
|
1448
1446
|
const cbBitsSrc = view.getUint32(dataOff + 88, true);
|
|
1447
|
+
if (offBmiSrc === 0 && rop === ROP_PATCOPY) {
|
|
1448
|
+
const prevFill = ctx.fillStyle;
|
|
1449
|
+
if (state.brushStyle !== BS_NULL) {
|
|
1450
|
+
ctx.fillStyle = state.brushColor;
|
|
1451
|
+
ctx.fillRect(gmx(rCtx, dstX), gmy(rCtx, dstY), gmw(rCtx, dstW), gmh(rCtx, dstH));
|
|
1452
|
+
}
|
|
1453
|
+
ctx.fillStyle = prevFill;
|
|
1454
|
+
return true;
|
|
1455
|
+
}
|
|
1449
1456
|
if (offBmiSrc > 0 && cbBmiSrc > 0 && offBitsSrc > 0 && cbBitsSrc > 0) {
|
|
1450
1457
|
const imageData = decodeDibToImageData(
|
|
1451
1458
|
view,
|
|
@@ -4855,19 +4862,7 @@ async function processDeferredImages(ctx, deferredImages, recursionDepth = 0) {
|
|
|
4855
4862
|
continue;
|
|
4856
4863
|
}
|
|
4857
4864
|
emfLog(` Deferred image [${idx}]: recursively converting embedded metafile...`);
|
|
4858
|
-
const metafileDataUrl = await convertEmfToDataUrl(
|
|
4859
|
-
plainBuffer,
|
|
4860
|
-
void 0,
|
|
4861
|
-
void 0,
|
|
4862
|
-
void 0,
|
|
4863
|
-
recursionDepth + 1
|
|
4864
|
-
) ?? await convertWmfToDataUrl(
|
|
4865
|
-
plainBuffer,
|
|
4866
|
-
void 0,
|
|
4867
|
-
void 0,
|
|
4868
|
-
void 0,
|
|
4869
|
-
recursionDepth + 1
|
|
4870
|
-
);
|
|
4865
|
+
const metafileDataUrl = await convertEmfToDataUrl(plainBuffer, void 0, recursionDepth + 1) ?? await convertWmfToDataUrl(plainBuffer, void 0, recursionDepth + 1);
|
|
4871
4866
|
if (metafileDataUrl) {
|
|
4872
4867
|
emfLog(
|
|
4873
4868
|
` Deferred image [${idx}]: metafile converted, dataUrl length=${metafileDataUrl.length}`
|
|
@@ -4912,14 +4907,14 @@ async function processDeferredImages(ctx, deferredImages, recursionDepth = 0) {
|
|
|
4912
4907
|
}
|
|
4913
4908
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
4914
4909
|
}
|
|
4915
|
-
async function convertEmfToDataUrl(buffer,
|
|
4910
|
+
async function convertEmfToDataUrl(buffer, options, recursionDepth = 0) {
|
|
4916
4911
|
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
4917
4912
|
return null;
|
|
4918
4913
|
}
|
|
4919
|
-
const opts =
|
|
4914
|
+
const opts = options ?? {};
|
|
4920
4915
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
4921
|
-
const effectiveMaxWidth =
|
|
4922
|
-
const effectiveMaxHeight =
|
|
4916
|
+
const effectiveMaxWidth = opts.maxWidth;
|
|
4917
|
+
const effectiveMaxHeight = opts.maxHeight;
|
|
4923
4918
|
const replayOptions = {
|
|
4924
4919
|
maxRecords: opts.maxRecords,
|
|
4925
4920
|
maxRecordsEmfPlus: opts.maxRecords,
|
|
@@ -4997,14 +4992,14 @@ async function convertEmfToDataUrl(buffer, maxWidth, maxHeight, optionsOrDpiScal
|
|
|
4997
4992
|
return null;
|
|
4998
4993
|
}
|
|
4999
4994
|
}
|
|
5000
|
-
async function convertWmfToDataUrl(buffer,
|
|
4995
|
+
async function convertWmfToDataUrl(buffer, options, recursionDepth = 0) {
|
|
5001
4996
|
if (recursionDepth > MAX_METAFILE_RECURSION) {
|
|
5002
4997
|
return null;
|
|
5003
4998
|
}
|
|
5004
|
-
const opts =
|
|
4999
|
+
const opts = options ?? {};
|
|
5005
5000
|
const dpiScale = opts.dpiScale ?? DEFAULT_DPI_SCALE;
|
|
5006
|
-
const effectiveMaxWidth =
|
|
5007
|
-
const effectiveMaxHeight =
|
|
5001
|
+
const effectiveMaxWidth = opts.maxWidth;
|
|
5002
|
+
const effectiveMaxHeight = opts.maxHeight;
|
|
5008
5003
|
const replayOptions = {
|
|
5009
5004
|
maxRecords: opts.maxRecords,
|
|
5010
5005
|
fontFamilyMap: opts.fontFamilyMap
|