emf-converter 3.4.0 → 3.5.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 +96 -77
- package/dist/index.d.mts +134 -19
- package/dist/index.d.ts +134 -19
- package/dist/index.js +25732 -8350
- package/dist/index.mjs +25732 -8351
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
[](https://github.com/ChristopherVR/emf-converter/actions/workflows/ci.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
A zero-dependency TypeScript library that converts **EMF** (Enhanced Metafile) and **WMF** (Windows Metafile)
|
|
7
|
+
A zero-dependency TypeScript library that converts **EMF** (Enhanced Metafile, including embedded **EMF+** / GDI+ records) and **WMF** (Windows Metafile) files into **PNG** or **SVG** (markup, a base64 data URL, React elements, or a generated JSX/TSX component).
|
|
8
8
|
|
|
9
|
-
Windows
|
|
9
|
+
Windows metafiles are recorded GDI and GDI+ drawing calls, commonly embedded in Office documents and on the Windows clipboard. This library replays those calls the way Windows does: the PNG output is checked pixel for pixel against images painted by Windows itself (hundreds of ground-truth fixtures under `src/__fixtures__/gdi`, generated by `scripts/gdi-fixtures`), and the SVG output keeps vectors, text and gradients resolution-independent.
|
|
10
10
|
|
|
11
11
|
| Format | Description | Coordinate system |
|
|
12
12
|
| -------- | ------------------------------ | ----------------------- |
|
|
@@ -18,24 +18,18 @@ Windows Metafiles store a sequence of GDI drawing commands and are commonly embe
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## What's new in 4.0
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
+import { convertMetafileToDataUrl } from 'emf-converter';
|
|
30
|
-
+const emfPng = await convertMetafileToDataUrl(emfBuffer);
|
|
31
|
-
+const wmfPng = await convertMetafileToDataUrl(wmfBuffer);
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
`convertMetafileToDataUrl` detects the format from the buffer itself, so the same call works for either. See "Quick start" below.
|
|
23
|
+
- **SVG output**: `convertMetafileToSvg`, `convertMetafileToSvgDataUrl`, `convertMetafileToSvgTree` + `svgTreeToReact` / `svgTreeToJsx` for JSX/TSX.
|
|
24
|
+
- **Windows-exact PNG by default**: GDI shapes are drawn by a rasteriser fitted to Windows GDI (28.4 fixed-point geometry, GDI's fill rule, line algorithm, ellipse and Bezier construction, wide pens, dash styles), and EMF+ drawing follows the file's recorded GDI+ `SmoothingMode` with GDI+'s own rasteriser. **Breaking:** default PNG output is no longer Canvas-antialiased; pass `gdiAntialias: true` for the previous smooth edges.
|
|
25
|
+
- **Exact text with the `fonts` option**: a built-in TrueType engine (hinting interpreter, dropout control, GDI font mapping and metrics, grayscale and ClearType) plus Windows raster `.fon` fonts. `loadSystemFonts()` reads the installed fonts in Node.js.
|
|
26
|
+
- **No canvas required**: a built-in pure-JavaScript rasteriser renders SVG anywhere and PNG for drawings without text; `@napi-rs/canvas` is only needed for PNG output with text in plain Node.js.
|
|
27
|
+
- **Complete WMF playback**: bitmaps, clipping, regions, mapping modes, palettes, flood fills, and embedded EMF comments, played as Windows' `PlayMetaFile` plays them.
|
|
28
|
+
- Many correctness fixes found by the new fixtures (see the changelog).
|
|
35
29
|
|
|
36
30
|
## Demo
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
Drop an `.emf` or `.wmf` file into the browser demo to see the PNG or SVG output, download it, or copy it as a TSX component:
|
|
39
33
|
|
|
40
34
|
**https://christophervr.github.io/emf-converter/**
|
|
41
35
|
|
|
@@ -45,34 +39,35 @@ Try it right in your browser: drop in an `.emf` or `.wmf` file and see the rende
|
|
|
45
39
|
npm install emf-converter
|
|
46
40
|
```
|
|
47
41
|
|
|
48
|
-
No required dependencies
|
|
42
|
+
No required dependencies:
|
|
49
43
|
|
|
50
|
-
- **Browser / Web Worker**:
|
|
51
|
-
- **Node.js
|
|
44
|
+
- **Browser / Web Worker**: `OffscreenCanvas` or `HTMLCanvasElement` is used automatically.
|
|
45
|
+
- **Node.js**: SVG output, and PNG output for drawings without text, work out of the box through the built-in rasteriser. For PNG output of drawings with text, either pass `fonts` (see [Exact text](#exact-text)) or install the optional [`@napi-rs/canvas`](https://www.npmjs.com/package/@napi-rs/canvas) (prebuilt, no `node-gyp`):
|
|
52
46
|
|
|
53
47
|
```bash
|
|
54
48
|
npm install @napi-rs/canvas
|
|
55
49
|
```
|
|
56
50
|
|
|
57
|
-
|
|
51
|
+
Without either, PNG conversion of a drawing that contains text returns `null` rather than an image missing its text.
|
|
58
52
|
|
|
59
53
|
## Quick start
|
|
60
54
|
|
|
61
55
|
```typescript
|
|
62
56
|
import { convertMetafileToDataUrl } from 'emf-converter';
|
|
63
57
|
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
// => "data:image/png;base64,iVBORw0KGgo..."
|
|
58
|
+
const buffer: ArrayBuffer = /* an .emf or .wmf file */;
|
|
59
|
+
const png = await convertMetafileToDataUrl(buffer);
|
|
60
|
+
// => "data:image/png;base64,iVBORw0KGgo..." (the format is auto-detected)
|
|
67
61
|
|
|
68
|
-
//
|
|
69
|
-
const
|
|
62
|
+
// Limit the output size (aspect ratio preserved), or render at 2x.
|
|
63
|
+
const thumb = await convertMetafileToDataUrl(buffer, { maxWidth: 1024, maxHeight: 768 });
|
|
64
|
+
const hiDpi = await convertMetafileToDataUrl(buffer, { dpiScale: 2 });
|
|
70
65
|
|
|
71
|
-
//
|
|
72
|
-
const
|
|
66
|
+
// Smooth (Canvas-antialiased) edges instead of Windows' own rasterisation.
|
|
67
|
+
const smooth = await convertMetafileToDataUrl(buffer, { gdiAntialias: true });
|
|
73
68
|
```
|
|
74
69
|
|
|
75
|
-
Returns `Promise<string | null
|
|
70
|
+
Returns `Promise<string | null>`; `null` when the buffer is not a valid metafile (or, in plain Node.js, when it has text and neither `fonts` nor `@napi-rs/canvas` is available).
|
|
76
71
|
|
|
77
72
|
### SVG output
|
|
78
73
|
|
|
@@ -86,11 +81,11 @@ const svgUrl = await convertMetafileToSvgDataUrl(buffer);
|
|
|
86
81
|
// => "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i..." (drop straight into <img src>)
|
|
87
82
|
```
|
|
88
83
|
|
|
89
|
-
|
|
84
|
+
Paths, text, gradients, clipping and pattern brushes stay vectors; bitmaps are embedded as `<image>` elements (PNG/JPEG/GIF/WebP bytes verbatim, never re-encoded). Raster operations that read the destination (all 256 ROP3 codes, bitwise ROP2, pattern brushes through ROP2) are evaluated exactly against a hidden raster mirror and embedded as image patches holding only the pixels they change, so the SVG is the same with or without a canvas backend.
|
|
90
85
|
|
|
91
86
|
### Rendering in React (JSX / TSX)
|
|
92
87
|
|
|
93
|
-
`convertMetafileToSvgTree` returns a plain `SvgNode` tree. Turn it into live elements with any `createElement`-style factory (React, Preact, ...), so the SVG is part of your component tree and can be styled, sized
|
|
88
|
+
`convertMetafileToSvgTree` returns a plain `SvgNode` tree. Turn it into live elements with any `createElement`-style factory (React, Preact, ...), so the SVG is part of your component tree and can be styled, sized and given props like any other element:
|
|
94
89
|
|
|
95
90
|
```tsx
|
|
96
91
|
import { createElement, useEffect, useState, type ReactNode } from 'react';
|
|
@@ -114,7 +109,7 @@ export function Metafile({ buffer }: { buffer: ArrayBuffer }) {
|
|
|
114
109
|
}
|
|
115
110
|
```
|
|
116
111
|
|
|
117
|
-
Or generate a component at build time (the SVGR approach)
|
|
112
|
+
Or generate a component at build time (the SVGR approach):
|
|
118
113
|
|
|
119
114
|
```typescript
|
|
120
115
|
import { writeFileSync } from 'node:fs';
|
|
@@ -125,36 +120,50 @@ writeFileSync('Logo.tsx', svgTreeToJsx(tree!, { componentName: 'Logo' }));
|
|
|
125
120
|
// export function Logo(props: SVGProps<SVGSVGElement>) { return (<svg ... {...props}> ... </svg>); }
|
|
126
121
|
```
|
|
127
122
|
|
|
128
|
-
Attribute names are converted to React's spelling (`stroke-width` → `strokeWidth`, `clip-path` → `clipPath`, `style` strings → style objects). Strings that come from the metafile (font names, text) are always emitted as escaped JavaScript string literals in generated source, never spliced into JSX raw. When several converted SVGs are inlined in
|
|
123
|
+
Attribute names are converted to React's spelling (`stroke-width` → `strokeWidth`, `clip-path` → `clipPath`, `style` strings → style objects). Strings that come from the metafile (font names, text) are always emitted as escaped JavaScript string literals in generated source, never spliced into JSX raw. When several converted SVGs are inlined in one page, give each its own `idPrefix` so their clip-path and gradient ids cannot collide (a unique prefix per conversion is the default).
|
|
124
|
+
|
|
125
|
+
### Exact text
|
|
126
|
+
|
|
127
|
+
Text is only as exact as the fonts it is drawn with. Pass the font files the metafile uses as `fonts` (TrueType `.ttf`/`.ttc` and Windows raster `.fon`/`.fnt`), and text is drawn the way Windows GDI draws it:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { convertMetafileToDataUrl, loadSystemFonts } from 'emf-converter';
|
|
131
|
+
|
|
132
|
+
const fonts = await loadSystemFonts(); // Node.js only; reuse the array across conversions
|
|
133
|
+
const png = await convertMetafileToDataUrl(buffer, { fonts });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- Fonts are realised the way GDI's font mapper does it (face substitutes, pitch/family fallback, weight choice, cell vs em height, `lfWidth` stretching), with GDI's metrics, advances, underline and strike-out.
|
|
137
|
+
- Glyphs are grid-fitted by the font's own TrueType instructions (including Windows' ClearType rules), scan-converted with dropout control, and placed on GDI's integer grid honouring Dx arrays, `ETO_*` flags and every `TA_*` alignment.
|
|
138
|
+
- Non-antialiased, grayscale or ClearType rendering is chosen from the font's quality; `fontSmoothing` sets what `DEFAULT_QUALITY` means (Windows' default is ClearType).
|
|
139
|
+
- Raster faces (MS Sans Serif, MS Serif, Courier, Small Fonts, System, Terminal, Fixedsys, Helv, Tms Rmn) are drawn from their bitmaps with GDI's size choice and stretching.
|
|
140
|
+
- Rotated text uses GDI's rounded font matrix; EMF+ `DrawString` honours the text rendering hint, string-format tracking and margins, and texture/gradient brushes.
|
|
141
|
+
|
|
142
|
+
Without `fonts`, text is drawn by the host's canvas font engine (supply `fontFamilyMap` to remap Windows face names). SVG output always keeps text as `<text>`; with `fonts` it carries GDI's exact per-glyph positions.
|
|
129
143
|
|
|
130
144
|
## API
|
|
131
145
|
|
|
132
146
|
### `convertMetafileToDataUrl(buffer, options?)`
|
|
133
147
|
|
|
134
|
-
| Parameter | Type
|
|
135
|
-
| ----------- |
|
|
136
|
-
| `buffer` | `ArrayBuffer`
|
|
137
|
-
| `options` | `EmfConvertOptions` (optional)|
|
|
138
|
-
| **Returns** | `Promise<string \| null>`
|
|
148
|
+
| Parameter | Type | Description |
|
|
149
|
+
| ----------- | ------------------------------ | --------------------------------------------------- |
|
|
150
|
+
| `buffer` | `ArrayBuffer` | Raw EMF or WMF file bytes (format is auto-detected) |
|
|
151
|
+
| `options` | `EmfConvertOptions` (optional) | See below |
|
|
152
|
+
| **Returns** | `Promise<string \| null>` | PNG data URL, or `null` on failure |
|
|
139
153
|
|
|
140
154
|
#### `EmfConvertOptions`
|
|
141
155
|
|
|
142
|
-
| Field | Type
|
|
143
|
-
| -------------------- |
|
|
144
|
-
| `maxWidth` | `number`
|
|
145
|
-
| `maxHeight` | `number`
|
|
146
|
-
| `dpiScale` | `number`
|
|
147
|
-
| `maxCanvasDimension` | `number`
|
|
148
|
-
| `maxRecords` | `number`
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const png = await convertMetafileToDataUrl(buffer, {
|
|
154
|
-
dpiScale: 2,
|
|
155
|
-
fontFamilyMap: { calibri: 'Carlito', 'ms shell dlg': 'Tahoma' },
|
|
156
|
-
});
|
|
157
|
-
```
|
|
156
|
+
| Field | Type | Default | Description |
|
|
157
|
+
| -------------------- | ------------------------------------- | ----------------- | ----------- |
|
|
158
|
+
| `maxWidth` | `number` | None | Maximum output width in pixels (aspect ratio preserved) |
|
|
159
|
+
| `maxHeight` | `number` | None | Maximum output height in pixels |
|
|
160
|
+
| `dpiScale` | `number` | `1` | Resolution multiplier; clamped to `4` |
|
|
161
|
+
| `maxCanvasDimension` | `number` | `8192` | Hard cap on output width/height in pixels |
|
|
162
|
+
| `maxRecords` | `number` | `200000`/`500000` | Records processed per stream before replay stops (EMF+ uses the higher default unless overridden) |
|
|
163
|
+
| `gdiAntialias` | `boolean` | `false` (PNG) | `true` smooths every shape edge with Canvas antialiasing instead of reproducing Windows' own GDI/GDI+ rasterisation |
|
|
164
|
+
| `fonts` | `Array<ArrayBuffer \| ArrayBufferView>` | None | TrueType (`.ttf`/`.ttc`) and raster (`.fon`/`.fnt`) font files for exact GDI text |
|
|
165
|
+
| `fontSmoothing` | `'cleartype' \| 'gray' \| 'mono'` | `'cleartype'` | What `DEFAULT_QUALITY` / `DRAFT_QUALITY` / `PROOF_QUALITY` fonts render as (Windows' system setting) |
|
|
166
|
+
| `fontFamilyMap` | `Record<string, string>` | None | Without `fonts`: maps Windows face names (case-insensitive) to locally available fonts, e.g. `{ calibri: 'Carlito' }` |
|
|
158
167
|
|
|
159
168
|
### SVG functions
|
|
160
169
|
|
|
@@ -171,41 +180,51 @@ const png = await convertMetafileToDataUrl(buffer, {
|
|
|
171
180
|
|
|
172
181
|
| Field | Type | Default | Description |
|
|
173
182
|
| --- | --- | --- | --- |
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
183
|
+
| `gdiAntialias` | `boolean` | `true` (SVG) | `false` embeds Windows' aliased GDI shape pixels as image patches instead of smooth vector edges |
|
|
184
|
+
| `exactRasterOps` | `boolean` | `true` | `false` skips the raster mirror and expresses destination-reading raster ops with SVG `mix-blend-mode` equivalents |
|
|
185
|
+
| `imageResampling` | `'renderer' \| 'exact'` | `'renderer'` | `'exact'` bakes EMF+ `DrawImage` at device resolution with GDI+'s resampling kernel instead of letting the SVG renderer scale the original image |
|
|
186
|
+
| `includeSize` | `boolean` | `true` | Emit `width`/`height` on the root `<svg>` (`viewBox` is always emitted); `false` gives a fluid SVG |
|
|
176
187
|
| `idPrefix` | `string` | `emf1-`, `emf2-`, ... | Prefix for generated element ids; keep it unique per inlined SVG |
|
|
177
188
|
|
|
178
|
-
`
|
|
189
|
+
### `loadSystemFonts(options?)`
|
|
190
|
+
|
|
191
|
+
Node.js only (returns `[]` elsewhere; the package stays browser-safe). Reads the installed `.ttf`, `.ttc`, `.fon` and `.fnt` files from the platform font folders (Windows, Linux, macOS, and per-user folders) for the `fonts` option. Options: `dirs` (scan these instead), `filter(path, name)`, `maxDepth`.
|
|
179
192
|
|
|
180
193
|
## How it works
|
|
181
194
|
|
|
182
|
-
A three-phase pipeline: **parse → replay → export**. The header parser
|
|
195
|
+
A three-phase pipeline: **parse → replay → export**. The header parser reads the drawing bounds (a placeable WMF is sized from its header's units per inch), the output surface is created (clamped to `maxCanvasDimension`), and the records are replayed in order by the GDI, EMF+ or WMF handlers. PNG output draws onto a Canvas (OffscreenCanvas, HTMLCanvasElement, `@napi-rs/canvas`, or the built-in pure-JavaScript rasteriser); SVG output draws onto `SvgContext`, a recorder implementing the part of the Canvas 2D API the replay uses, mirrored onto a hidden raster wherever a raster operation must read the destination.
|
|
196
|
+
|
|
197
|
+
Everything below is verified against output painted by Windows itself; `src/gdi-parity.fixture.test.ts` holds the per-fixture bounds.
|
|
183
198
|
|
|
184
|
-
|
|
199
|
+
- **GDI shapes** (`gdi-raster.ts`, `gdi-raster-widen.ts`): 28.4 fixed-point geometry; GDI's fill rule (ALTERNATE/WINDING); one-pixel lines by GDI's diamond rule with its tie-breaks; GDI's own Bezier flattener, ellipse, rounded-rectangle, arc (GDI's trigonometry table and `SetArcDirection`), chord and pie construction; cosmetic dash styles (dash 18/6, dot 3/3, ...) and geometric dashes; wide pens widened from GDI's own pen polygons with every cap and join and the miter limit; rotated and skewed world transforms. Pixel-exact on the shape fixtures.
|
|
200
|
+
- **Raster operations**: all 256 ROP3 codes for `BitBlt`/`StretchBlt`/`StretchDIBits`/`PatBlt`, exact per bit against the destination, brush and source, with GDI's stretch modes, mirrored rectangles and rotated destinations (each device pixel mapped back to one source texel). Every `SetROP2` mode, including the bitwise AND/OR/XOR family, for shapes, paths and pattern-brush fills.
|
|
201
|
+
- **Brushes**: hatch, monochrome and DIB pattern brushes anchored to the brush origin, with the background mode; GDI+ solid, hatch, texture (bilinear, WrapMode-aware, as GDI+ samples them), linear gradients (GDI+'s own interpolation table: preset colours, blend shapes, gamma correction, every WrapMode) and path gradients (true boundary-shaped falloff, every WrapMode).
|
|
202
|
+
- **Clipping**: every GDI and GDI+ region combine mode exact for every clip (vector where possible, otherwise scan-converted to pixel regions, which is how GDI stores them), path clips with their fill mode, and region offsets.
|
|
203
|
+
- **EMF+**: fills, pens and clips follow the recorded `SmoothingMode` with GDI+'s own fill rasteriser (8 x 4-sample antialiasing, blend arithmetic) and pen widener (joins, caps, dash caps, compound lines, inset alignment); `DrawImage` with every InterpolationMode/PixelOffsetMode kernel, ImageAttributes wrap modes, drawn in record order under the live clip; embedded metafiles replayed as vectors; continuation records reassembled; compressed textures and images decoded before replay.
|
|
204
|
+
- **Text**: see [Exact text](#exact-text).
|
|
205
|
+
- **WMF**: played as `PlayMetaFile` plays it (GM_COMPATIBLE whole-pixel rules, mapping modes, bitmaps, pattern brushes, clipping and regions, palettes, flood fills, text spacing and justification, right-to-left layout); an EMF embedded in `MFCOMMENT` escapes is played instead, as Windows does.
|
|
185
206
|
|
|
186
|
-
|
|
207
|
+
### Supported records
|
|
187
208
|
|
|
188
|
-
- **
|
|
189
|
-
- **
|
|
190
|
-
- **
|
|
191
|
-
- **Raster operations (ROP2)**: every `SetROP2` mode is mapped. `R2_BLACK`, `R2_WHITE`, `R2_NOP`, `R2_COPYPEN`, `R2_NOTCOPYPEN`, and `R2_NOT` are emulated exactly via colour inversion and `difference` compositing. The bitwise AND/OR/XOR family (`R2_MASKPEN`, `R2_MERGEPEN`, `R2_XORPEN`, `R2_NOTXORPEN`, `R2_MASKPENNOT`, `R2_MERGEPENNOT`, `R2_MASKNOTPEN`, `R2_MERGENOTPEN`, `R2_NOTMASKPEN`, `R2_NOTMERGEPEN`) is evaluated exactly too, bit-for-bit against the true destination pixel, for a filled and/or stroked Rectangle, RoundRect, Ellipse, Arc/Chord/Pie, Polygon, Polyline, or PolyPolygon, whether drawn immediately or built up across an `EMR_BEGINPATH`/`EMR_ENDPATH` bracket: the shape's coverage is computed on/off per pixel (GDI does not antialias) within the shape's bounding box, combined with the exact pen/brush colour by the same truth-table evaluator the ROP3 blit path uses, and composited through the active clip region. A pattern (hatch, monochrome, or DIB) brush fill combines exactly with every `SetROP2` mode, bitwise ones included.
|
|
192
|
-
- **GDI world transforms**: `EMR_SETWORLDTRANSFORM` / `EMR_MODIFYWORLDTRANSFORM`'s full affine, including rotation and skew, is applied to Rectangle, RoundRect, Ellipse, Arc/Chord/Pie, Polygon, Polyline, PolyPolygon, path (`BeginPath`/`MoveTo`/`LineTo`/`Poly*To`/`EndPath`) drawing, bitmap blits (`EMR_BITBLT`/`EMR_STRETCHBLT`/`EMR_STRETCHDIBITS`, including the exact ROP3 path), and raster text (`EMR_EXTTEXTOUTW`). A rotated/skewed Ellipse (and Arc/Chord/Pie) is rendered from the mapped shape's exact semi-axes and rotation angle (the eigendecomposition of the linear part). RoundRect corners are exact elliptical arcs honouring unequal corner width and height, built as Beziers in logical space and mapped through the transform, so they rotate and skew exactly. Text under a skewed transform is sheared as well as rotated, matching GDI. Bitmap blits under a rotated or skewed transform are evaluated exactly (ROP3 truth table, brush pattern, source stretch-mode sampling) on a local raster whose axes are the exact transformed basis vectors, sampled at least once per device pixel, and then placed; real GDI does rotate a `BitBlt`/`TextOut` destination (`src/__fixtures__/gdi/rotate-bitblt-25deg`, `rotate-text-25deg`). This full-affine handling is also required for GDI+-exported EMF files even without rotation, since they record coordinates at 16× sub-pixel precision with a compensating world-transform scale.
|
|
193
|
-
- **GDI pattern-brush fills**: a hatch, monochrome (`EMR_CREATEMONOBRUSH`), or DIB (`EMR_CREATEDIBPATTERNBRUSHPT`) pattern brush selected for a Rectangle/RoundRect/Ellipse/Arc/Polygon/Polyline/PolyPolygon fill (or a bracketed path's `EMR_FILLPATH`/`EMR_STROKEANDFILLPATH`) paints the real tiled pattern, anchored to the brush origin (`EMR_SETBRUSHORGEX`), instead of a flat placeholder colour. This is filled per pixel (via the shape's already-built path and the same `sampleTile` sampler the exact ROP3 blit evaluator uses) rather than through a Canvas `CanvasPattern`: every canvas backend this package targets was measured to filter a `CanvasPattern` regardless of `imageSmoothingEnabled` (which only ever affects `drawImage`), smearing a hard-edged pattern tile's texels across several device pixels even at a 1:1 pattern transform. `EMR_CREATEDIBPATTERNBRUSHPT`/`EMR_CREATEMONOBRUSH` pattern brushes used as the *source* of a `BitBlt`/`StretchBlt`/`PatBlt` ROP3 blit were already exact before this (see Raster operations (ROP3) above); this closes the same brushes used for a vector shape fill.
|
|
194
|
-
- **GDI pixel grid**: thin (odd-width) pens paint the pixels their coordinates name, as GDI does, rather than two half-intensity rows straddling a pixel boundary. The `gdiAntialias: false` option goes further and rasterises every GDI vector fill and stroke without antialiasing on GDI's own pixel grid, matching Windows output to within 0.25% of pixels on the real-GDI shape fixtures, at a 3-4x cost on shape-heavy files.
|
|
195
|
-
- **EMF+ TextureFill brushes**: a TextureFill brush (brush type 2) paints its real image, tiled per `WrapMode` and placed by the brush and world transforms. Shape fills (FillRects, FillEllipse, FillPie, FillPolygon, FillPath) are computed one device pixel at a time and match a real GDI+ fixture pixel-exactly. Compressed (PNG/JPEG) embedded images, the common real-world case, are decoded by an async pre-decode pass (`emf-plus-texture-predecode.ts`) before the synchronous replay starts. EMF+ objects split across `EMFPLUS_OBJECT` continuation records, including ones spread over several `EMR_COMMENT` records, are reassembled by one routine shared by the replay and the pre-decode pass (`emf-plus-continuation.ts`), so a large split texture brush decodes like any other.
|
|
196
|
-
- **EMF+ Image objects and DrawImage**: `BitmapDataType` ([MS-EMFPLUS] 2.1.1.2: `Pixel = 0`, `Compressed = 1`) is read correctly for a standalone Image object. `DrawImage` / `DrawImagePoints` honour the source rectangle and the full destination parallelogram (so rotation and shear are kept), and resample the way GDI+ does for `InterpolationMode` Default / LowQuality / Bilinear / NearestNeighbor under `PixelOffsetMode` None or Half (`emf-plus-image-resample.ts`), matching a real GDI+ `DrawImage` fixture (`src/__fixtures__/gdi/image-draw-png`) within 8 levels per channel on every pixel.
|
|
209
|
+
- **EMF**: 115 of the 119 record types defined in MS-EMF, including logical palettes (`PALETTEINDEX`, `DIBPALETTEINDEX`, `PALETTERGB`, `DIB_PAL_COLORS`), `EMR_ALPHABLEND` (Windows' exact integer blend), `EMR_TRANSPARENTBLT`, `EMR_MASKBLT`, `EMR_PLGBLT`, `EMR_SETDIBITSTODEVICE`, `EMR_GRADIENTFILL` (rectangles and triangles), `EMR_FILLRGN` / `EMR_FRAMERGN` / `EMR_INVERTRGN` / `EMR_PAINTRGN`, `EMR_EXTFLOODFILL`, `EMR_ANGLEARC`, `EMR_POLYDRAW(16)`, `EMR_FLATTENPATH` / `EMR_WIDENPATH` / `EMR_ABORTPATH`, alongside shapes, paths, `EMR_EXTTEXTOUTW`, blits, clipping and transforms. Colour space, ICM, OpenGL, escape and font-driver records are consumed without effect, as on a Windows display.
|
|
210
|
+
- **EMF+**: every record in MS-EMFPLUS (Beziers, cardinal curves, regions, containers, save/restore, compositing mode, rendering origin, text contrast, `StrokeFillPath`, the terminal-server `SetTSGraphics` / `SetTSClip`, `MultiFormat*` played as GDI+ plays them), with 32-bit, compressed 16-bit and relative point data, and every object type (solid, hatch, texture and gradient brushes; pens with caps, joins, dash styles, dash caps, compound lines and custom line caps; paths, regions, bitmap and metafile images, fonts, string formats, image attributes). Several encodings follow what GDI+ actually does where it differs from MS-EMFPLUS (relative points, `StrokeFillPath`, `SetTSGraphics`, `SetTSClip`).
|
|
211
|
+
- **WMF**: META_ANIMATEPALETTE, META_ARC, META_BITBLT, META_CHORD, META_CREATEBITMAP, META_CREATEBITMAPINDIRECT, META_CREATEBRUSH, META_CREATEBRUSHINDIRECT, META_CREATEFONTINDIRECT, META_CREATEPALETTE, META_CREATEPATTERNBRUSH, META_CREATEPENINDIRECT, META_CREATEREGION, META_DELETEOBJECT, META_DIBBITBLT, META_DIBCREATEPATTERNBRUSH, META_DIBSTRETCHBLT, META_ELLIPSE, META_EOF, META_ESCAPE, META_EXCLUDECLIPRECT, META_EXTFLOODFILL, META_EXTTEXTOUT, META_FILLREGION, META_FLOODFILL, META_FRAMEREGION, META_INTERSECTCLIPRECT, META_INVERTREGION, META_LINETO, META_MOVETO, META_OFFSETCLIPRGN, META_OFFSETVIEWPORTORG, META_OFFSETWINDOWORG, META_PAINTREGION, META_PATBLT, META_PIE, META_POLYGON, META_POLYLINE, META_POLYPOLYGON, META_REALIZEPALETTE, META_RECTANGLE, META_RESIZEPALETTE, META_RESTOREDC, META_ROUNDRECT, META_SAVEDC, META_SCALEVIEWPORTEXT, META_SCALEWINDOWEXT, META_SELECTCLIPREGION, META_SELECTOBJECT, META_SELECTPALETTE, META_SETBKCOLOR, META_SETBKMODE, META_SETDIBTODEV, META_SETLAYOUT, META_SETMAPMODE, META_SETMAPPERFLAGS, META_SETPALENTRIES, META_SETPIXEL, META_SETPOLYFILLMODE, META_SETRELABS, META_SETROP2, META_SETSTRETCHBLTMODE, META_SETTEXTALIGN, META_SETTEXTCHAREXTRA, META_SETTEXTCOLOR, META_SETTEXTJUSTIFICATION, META_SETVIEWPORTEXT, META_SETVIEWPORTORG, META_SETWINDOWEXT, META_SETWINDOWORG, META_STRETCHBLT, META_STRETCHDIB, META_TEXTOUT. Where Windows no longer plays a record the way MS-WMF describes it (Win16 device bitmaps in META_BITBLT / META_STRETCHBLT, META_CREATEPATTERNBRUSH, banded META_SETDIBTODEV), the converter follows Windows.
|
|
197
212
|
|
|
198
213
|
## Limitations
|
|
199
214
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
- **
|
|
203
|
-
- **
|
|
204
|
-
- **
|
|
205
|
-
-
|
|
206
|
-
- **
|
|
207
|
-
- **
|
|
208
|
-
- **
|
|
215
|
+
Everything is measured against output painted by Windows itself; `src/gdi-parity.fixture.test.ts` holds the exact per-fixture bounds.
|
|
216
|
+
|
|
217
|
+
- **Unhandled records**: `EMR_EXTTEXTOUTA`, `EMR_POLYTEXTOUTA`, `EMR_POLYTEXTOUTW` and `EMR_SMALLTEXTOUT` (ANSI, multi-string and small-glyph text records, rarely written by modern recorders) are skipped with a console warning. `EMR_SETTEXTJUSTIFICATION` and `EMR_SETCOLORADJUSTMENT` are read but not yet applied (Windows' own recorder bakes justification into `EMR_EXTTEXTOUTW` spacing arrays, so only other writers emit the former), and the `HALFTONE` stretch mode is not bit-exact. EMF+ image effects (`SerializableObject`: blur, sharpen, colour matrix and the like) are not applied, so the image is drawn without the effect, and an EMF+ pen's own transform is ignored.
|
|
218
|
+
- **Text without fonts**: without the `fonts` option, glyphs come from the host font engine, so text differs from Windows on a few percent of pixels (and depends on which fonts the host has). SVG text is `<text>`, rendered with the viewer's fonts.
|
|
219
|
+
- **Text with fonts**: non-antialiased text is within 0.03% of Windows' pixels (about 93% of glyphs bit-exact; the rest differ by a pixel on some diagonal stems, where GDI's hinting arithmetic is undocumented) and grayscale text within 0.13%. ClearType text, which is what `DEFAULT_QUALITY` fonts get on a default Windows install, is within about 4-5% (compatible-width glyph placement is not fully reproduced). Non-grid-fitted GDI+ AntiAlias and ClearType text differ by 11-13% of text pixels (GDI+'s own glyph placement and blend), rotated right/centre-aligned text can start a pixel off, and a few unusual raster-font sizes pick a different bitmap size than Windows.
|
|
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 Bezier curves follow `WidenPath` (which Windows' direct drawing does not quite match); at most 0.2% of pixels on the fixtures. `EMR_WIDENPATH` does not reproduce the extra inner join triangles GDI's own `WidenPath` emits (visible only when the widened outline is itself stroked). EMF+ 1-pixel antialiased lines can differ by one antialiasing sample at their ends, some closed widened outlines by one sample along an edge, and Inset or compound pens on closed figures are approximate.
|
|
221
|
+
- **GM_COMPATIBLE recordings**: EMF files do not record the graphics mode, and Windows plays RoundRect, Arc, Chord, Pie and null-pen Ellipse records back differently from how a GM_COMPATIBLE application drew them on screen; the converter follows Windows' playback.
|
|
222
|
+
- **Small EMF+ residuals**: rotated `HighQualityBicubic` `DrawImage` edge pixels (0.14%), one-level differences at exact half-level `Blend` knots, and a few pixels of a metafile nested in `DrawImage` under a scale.
|
|
223
|
+
- **WMF**: `PS_INSIDEFRAME` boxes can come out a pixel short at non-integer scales, right-to-left (`LAYOUT_RTL`) layouts differ by single pixels on mirrored diagonals, and metric map modes assume a 96 dpi reference device (Windows derives them from the physical display, so its own output varies per machine).
|
|
224
|
+
- **Smooth mode** (`gdiAntialias: true`, and SVG's default vector edges): only shape edges differ from Windows, by design; a flood fill reads the antialiased pixels it is given.
|
|
225
|
+
- **SVG renderers**: output is renderer-dependent in the usual ways: angled hard-stop gradient seams fall within each renderer's own precision, and a raster operation that reads pixels under text is exact wherever its result does not depend on the glyphs, otherwise expressed as a blend layer the SVG renderer applies to its own text.
|
|
226
|
+
- **PNG in plain Node.js** without `@napi-rs/canvas` and without `fonts` returns `null` for drawings that contain text, rather than an image missing its text.
|
|
227
|
+
- **Safety limits**: output is clamped to 8192×8192 and replay stops after 200,000 records (EMF/WMF) or 500,000 (EMF+); both are overridable via `maxCanvasDimension` / `maxRecords`.
|
|
209
228
|
|
|
210
229
|
## License
|
|
211
230
|
|
package/dist/index.d.mts
CHANGED
|
@@ -136,15 +136,53 @@ interface EmfConvertOptions {
|
|
|
136
136
|
*/
|
|
137
137
|
fontFamilyMap?: Record<string, string>;
|
|
138
138
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
139
|
+
* Smooth shape edges instead of reproducing Windows' own rasterisation.
|
|
140
|
+
*
|
|
141
|
+
* PNG output defaults to `false`: plain-GDI vector shapes (Rectangle,
|
|
142
|
+
* Ellipse, RoundRect, Polygon, Polyline, arcs, bracketed paths, wide
|
|
143
|
+
* pens) are rasterised the way Windows GDI does, with its 28.4
|
|
144
|
+
* fixed-point geometry, fill rule, line algorithm and Bezier flattening,
|
|
145
|
+
* and EMF+ fills, strokes and clips follow the GDI+ `SmoothingMode` the
|
|
146
|
+
* file records (None, Default and HighSpeed aliased on GDI+'s pixel grid,
|
|
147
|
+
* AntiAlias and HighQuality with GDI+'s 8 x 4-sample antialiasing), so the
|
|
148
|
+
* PNG matches what Windows paints pixel for pixel.
|
|
149
|
+
*
|
|
150
|
+
* `true` draws every edge with Canvas's own antialiasing instead (still
|
|
151
|
+
* with GDI's geometry, pen widths, caps, joins and dash patterns), which
|
|
152
|
+
* looks smoother than Windows, especially for files recorded without
|
|
153
|
+
* GDI+ antialiasing.
|
|
154
|
+
*
|
|
155
|
+
* SVG output defaults to smooth vector edges (an SVG is meant to scale);
|
|
156
|
+
* `false` there embeds Windows' aliased shape pixels as image patches.
|
|
146
157
|
*/
|
|
147
158
|
gdiAntialias?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Font files to render GDI and WMF text with, exactly as Windows GDI
|
|
161
|
+
* does: TrueType `.ttf` / `.ttc` and raster `.fon` / `.fnt` bytes
|
|
162
|
+
* (`loadSystemFonts()` reads the installed ones in Node.js). The
|
|
163
|
+
* LOGFONT is realised against these files (face, weight, slant,
|
|
164
|
+
* `lfHeight`/`lfWidth`, charset fallback), each TrueType glyph is grid-fitted by the font's own TrueType
|
|
165
|
+
* instructions and scan-converted with TrueType dropout control
|
|
166
|
+
* (non-antialiased, 4x4 grayscale or ClearType per the LOGFONT's
|
|
167
|
+
* `lfQuality`), and glyphs are placed on GDI's integer device grid with
|
|
168
|
+
* GDI's own advance widths, cell metrics, underline and strike-out.
|
|
169
|
+
* Raster faces (MS Sans Serif, Helv, System, Terminal, ...) are drawn
|
|
170
|
+
* from their bitmaps at the size and whole-number stretch GDI picks.
|
|
171
|
+
* Supply the fonts the metafile names (for Windows-authored files, the
|
|
172
|
+
* matching files from `C:\Windows\Fonts`); a face that is missing is
|
|
173
|
+
* substituted the way GDI's font mapper would (by pitch and family),
|
|
174
|
+
* and without this option text is drawn with the canvas font engine.
|
|
175
|
+
* Ignored by SVG output, which keeps text as `<text>` but takes its
|
|
176
|
+
* per-glyph positions and metrics from these fonts.
|
|
177
|
+
*/
|
|
178
|
+
fonts?: Array<ArrayBuffer | ArrayBufferView>;
|
|
179
|
+
/**
|
|
180
|
+
* Windows' system-wide font smoothing, which GDI applies to fonts that
|
|
181
|
+
* ask for `DEFAULT_QUALITY`, `DRAFT_QUALITY` or `PROOF_QUALITY` (most
|
|
182
|
+
* metafiles): `'cleartype'` (Windows' default), `'gray'` (standard
|
|
183
|
+
* antialiasing) or `'mono'` (smoothing off). Only used with `fonts`.
|
|
184
|
+
*/
|
|
185
|
+
fontSmoothing?: 'cleartype' | 'gray' | 'mono';
|
|
148
186
|
}
|
|
149
187
|
/**
|
|
150
188
|
* Options for the SVG outputs ({@link convertMetafileToSvg} and friends).
|
|
@@ -156,14 +194,34 @@ interface EmfConvertOptions {
|
|
|
156
194
|
interface SvgConvertOptions extends EmfConvertOptions {
|
|
157
195
|
/**
|
|
158
196
|
* Evaluate raster operations that read the destination (exact ROP3 blits,
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
197
|
+
* bitwise ROP2, pattern-brush fills combined through ROP2, and
|
|
198
|
+
* `gdiAntialias: false` shapes) against a hidden raster mirror of the
|
|
199
|
+
* drawing, and embed the pixels they change as image patches. The mirror
|
|
200
|
+
* is the canvas backend when one exists (browser/worker canvas, or
|
|
201
|
+
* `@napi-rs/canvas` in Node.js) and the built-in pure-JavaScript
|
|
202
|
+
* rasteriser otherwise, so this needs no canvas. The built-in mirror
|
|
203
|
+
* cannot draw glyphs: where a raster operation reads pixels under text,
|
|
204
|
+
* every pixel whose result does not depend on the glyphs stays exact and
|
|
205
|
+
* the rest is handed to the SVG renderer as a blend-mode layer (exact for
|
|
206
|
+
* inversion and for masks whose channels are all 0 or 255). With `false`,
|
|
207
|
+
* no mirror is kept and those operations fall back to SVG blend modes
|
|
163
208
|
* (`mix-blend-mode`), which are exact for the common mask ROPs on
|
|
164
209
|
* black/white masks and approximate otherwise. Default `true`.
|
|
165
210
|
*/
|
|
166
211
|
exactRasterOps?: boolean;
|
|
212
|
+
/**
|
|
213
|
+
* How EMF+ `DrawImage` bitmaps are scaled. `'renderer'` (the default)
|
|
214
|
+
* embeds the original image and lets the SVG renderer scale it with its
|
|
215
|
+
* own smoothing, which stays sharp at any display size. `'exact'` bakes
|
|
216
|
+
* each draw at device resolution with the GDI+-matching resampler (the
|
|
217
|
+
* PNG output's `InterpolationMode`/`PixelOffsetMode` model), so the SVG
|
|
218
|
+
* shows what GDI+ painted pixel for pixel at its nominal size. PNG and
|
|
219
|
+
* BMP images are decoded in pure JavaScript; JPEG, GIF and other formats
|
|
220
|
+
* need a canvas backend to decode and otherwise keep `'renderer'`
|
|
221
|
+
* scaling, as do draws GDI+ scales with a filter the resampler does not
|
|
222
|
+
* model (bicubic, high-quality).
|
|
223
|
+
*/
|
|
224
|
+
imageResampling?: 'renderer' | 'exact';
|
|
167
225
|
/**
|
|
168
226
|
* Emit `width`/`height` attributes on the root `<svg>` (the `viewBox` is
|
|
169
227
|
* always emitted). Set `false` for a fluid SVG that fills its container.
|
|
@@ -191,8 +249,13 @@ interface SvgConvertOptions extends EmfConvertOptions {
|
|
|
191
249
|
* - The buffer matches neither a valid EMF header nor a valid WMF header.
|
|
192
250
|
* - The logical bounds are zero-sized or negative.
|
|
193
251
|
* - No canvas API is available (browser/worker canvas, or the optional
|
|
194
|
-
* `@napi-rs/canvas` package in plain Node.js)
|
|
195
|
-
*
|
|
252
|
+
* `@napi-rs/canvas` package in plain Node.js) AND the drawing contains
|
|
253
|
+
* text or an image format only a canvas can decode (JPEG, GIF, ...).
|
|
254
|
+
* Without a canvas the built-in pure-JavaScript rasteriser renders
|
|
255
|
+
* everything else (vectors, clipping, gradients, bitmaps, PNG/BMP
|
|
256
|
+
* images, every raster operation), but it has no font engine, so rather
|
|
257
|
+
* than return an image silently missing its text it returns `null`. SVG
|
|
258
|
+
* output ({@link convertMetafileToSvg}) needs no canvas at all.
|
|
196
259
|
*
|
|
197
260
|
* @param buffer - The raw EMF or WMF file bytes.
|
|
198
261
|
* @param options - Optional {@link EmfConvertOptions} controlling output size,
|
|
@@ -201,6 +264,7 @@ interface SvgConvertOptions extends EmfConvertOptions {
|
|
|
201
264
|
* @returns A `data:image/png;base64,...` string, or `null` on failure.
|
|
202
265
|
*/
|
|
203
266
|
declare function convertMetafileToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
|
|
267
|
+
|
|
204
268
|
/**
|
|
205
269
|
* Converts an EMF or WMF buffer (format auto-detected) into an SVG document
|
|
206
270
|
* tree, the common source for every SVG output form: serialise it with
|
|
@@ -208,11 +272,12 @@ declare function convertMetafileToDataUrl(buffer: ArrayBuffer, options?: EmfConv
|
|
|
208
272
|
* with {@link svgTreeToReact}, or generate component source with
|
|
209
273
|
* {@link svgTreeToJsx}.
|
|
210
274
|
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
275
|
+
* This needs no canvas implementation: vectors, text, gradients, clipping,
|
|
276
|
+
* and bitmaps are all recorded in pure JavaScript, and destination-reading
|
|
277
|
+
* raster operations are evaluated exactly against a raster mirror of the
|
|
278
|
+
* drawing (see {@link SvgConvertOptions.exactRasterOps}), which is the
|
|
279
|
+
* canvas backend when one exists (it also measures text) and the built-in
|
|
280
|
+
* pure-JavaScript rasteriser otherwise.
|
|
216
281
|
*
|
|
217
282
|
* @returns The root `<svg>` node, or `null` for an invalid/empty metafile.
|
|
218
283
|
*/
|
|
@@ -239,4 +304,54 @@ declare function convertMetafileToSvgDataUrl(buffer: ArrayBuffer, options?: SvgC
|
|
|
239
304
|
*/
|
|
240
305
|
declare const DEFAULT_DPI_SCALE = 1;
|
|
241
306
|
|
|
242
|
-
|
|
307
|
+
/**
|
|
308
|
+
* `loadSystemFonts()`: reads the operating system's installed font files
|
|
309
|
+
* (Node.js only) into buffers for the converter's `fonts` option.
|
|
310
|
+
*
|
|
311
|
+
* The Node.js modules are loaded with dynamic `import()` (and bundler
|
|
312
|
+
* ignore comments) only when the function is called, so the package stays
|
|
313
|
+
* browser-safe: nothing here is resolved or bundled for a browser build.
|
|
314
|
+
*
|
|
315
|
+
* @module load-system-fonts
|
|
316
|
+
*/
|
|
317
|
+
/** Options for {@link loadSystemFonts}. */
|
|
318
|
+
interface LoadSystemFontsOptions {
|
|
319
|
+
/**
|
|
320
|
+
* Directories to scan instead of the platform defaults (Windows:
|
|
321
|
+
* `%WINDIR%\Fonts` and the per-user `%LOCALAPPDATA%\Microsoft\Windows\Fonts`;
|
|
322
|
+
* Linux: `/usr/share/fonts`, `/usr/local/share/fonts`, `~/.fonts`,
|
|
323
|
+
* `~/.local/share/fonts`; macOS: `/Library/Fonts`,
|
|
324
|
+
* `/System/Library/Fonts`, `~/Library/Fonts`). Missing directories are
|
|
325
|
+
* skipped.
|
|
326
|
+
*/
|
|
327
|
+
dirs?: string[];
|
|
328
|
+
/**
|
|
329
|
+
* Keeps only the files this returns true for, given the full path and
|
|
330
|
+
* the lower-case file name (for example to load just the faces a
|
|
331
|
+
* metafile names: `(p, n) => /^(arial|times|cour)/.test(n)`).
|
|
332
|
+
*/
|
|
333
|
+
filter?: (path: string, name: string) => boolean;
|
|
334
|
+
/** Subdirectory depth to descend (default 4; 0 scans only the directories themselves). */
|
|
335
|
+
maxDepth?: number;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Reads the installed TrueType (`.ttf`, `.ttc`) and raster (`.fon`,
|
|
339
|
+
* `.fnt`) font files, for `convertMetafileToDataUrl(data, { fonts })`
|
|
340
|
+
* and the SVG converters. Node.js only: in a browser (or any runtime
|
|
341
|
+
* without `process.versions.node`) it resolves to an empty array.
|
|
342
|
+
*
|
|
343
|
+
* Reading every installed font can take a few hundred megabytes on
|
|
344
|
+
* Windows; pass `filter` to load only what your metafiles use. Load once
|
|
345
|
+
* and reuse the array across conversions.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* import { convertMetafileToDataUrl, loadSystemFonts } from 'emf-converter';
|
|
350
|
+
*
|
|
351
|
+
* const fonts = await loadSystemFonts();
|
|
352
|
+
* const png = await convertMetafileToDataUrl(emfBytes, { fonts });
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
declare function loadSystemFonts(options?: LoadSystemFontsOptions): Promise<Uint8Array[]>;
|
|
356
|
+
|
|
357
|
+
export { type CreateElement, DEFAULT_DPI_SCALE, type EmfConvertOptions, type LoadSystemFontsOptions, type SvgConvertOptions, type SvgJsxOptions, type SvgNode, convertMetafileToDataUrl, convertMetafileToSvg, convertMetafileToSvgDataUrl, convertMetafileToSvgTree, loadSystemFonts, svgTreeToDataUrl, svgTreeToJsx, svgTreeToReact, svgTreeToString };
|