emf-converter 3.3.0 → 3.4.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/dist/index.d.ts CHANGED
@@ -1,20 +1,109 @@
1
1
  /**
2
- * Public API, a single auto-detecting entry point consumed by the rest of
3
- * the application.
2
+ * A tiny, framework-agnostic SVG document model plus its serialisers.
4
3
  *
5
- * The conversion pipeline for both formats follows the same high-level steps:
6
- * 1. Parse the file header to determine logical bounds and canvas dimensions
4
+ * The SVG backend (`svg-context.ts`) records a metafile's drawing into an
5
+ * {@link SvgNode} tree rather than straight into markup, so the same result
6
+ * can be handed to whichever consumer needs it:
7
+ *
8
+ * - {@link svgTreeToString}: standalone SVG markup (`<svg xmlns=...>...</svg>`)
9
+ * - {@link svgTreeToDataUrl}: a `data:image/svg+xml;base64,...` URL, usable
10
+ * anywhere an image URL is (`<img src>`, CSS `background-image`, ...)
11
+ * - {@link svgTreeToReact}: live elements for React (or Preact, Solid's
12
+ * `h`, Vue's `h`, ...), built through a caller-supplied `createElement`,
13
+ * so this package never depends on a UI framework
14
+ * - {@link svgTreeToJsx}: JSX/TSX component source code, for build-time code
15
+ * generation in the style of SVGR
16
+ *
17
+ * Attribute names are stored in their SVG (kebab-case) spelling; the React
18
+ * and JSX serialisers convert them to the camelCase property names React
19
+ * expects (`stroke-width` → `strokeWidth`, `clip-path` → `clipPath`, and a
20
+ * `style` string becomes a style object).
21
+ *
22
+ * @module svg-tree
23
+ */
24
+ /** One SVG element. Text content (for `<text>`) lives in {@link SvgNode.text}. */
25
+ interface SvgNode {
26
+ /** Element name, e.g. `path`, `g`, `linearGradient`. */
27
+ tag: string;
28
+ /** Attributes in SVG spelling (`stroke-width`, `clip-path`, `style`). */
29
+ attrs: Record<string, string | number>;
30
+ /** Child elements, in paint order. */
31
+ children?: SvgNode[];
32
+ /** Character data for text-bearing elements. Mutually exclusive with children. */
33
+ text?: string;
34
+ }
35
+ /** Serialises a tree to SVG markup. The root should be an `<svg>` element. */
36
+ declare function svgTreeToString(node: SvgNode): string;
37
+ /** Serialises a tree to a base64 `data:image/svg+xml` URL. */
38
+ declare function svgTreeToDataUrl(node: SvgNode): string;
39
+ /**
40
+ * A `createElement`-compatible factory: `React.createElement`, Preact's `h`,
41
+ * and most hyperscript-style factories fit this shape.
42
+ */
43
+ type CreateElement<E> = (type: string, props: Record<string, unknown> | null, ...children: unknown[]) => E;
44
+ /**
45
+ * Builds live framework elements from a tree via `createElement`.
46
+ *
47
+ * ```tsx
48
+ * import { createElement } from 'react';
49
+ * const tree = await convertMetafileToSvgTree(buffer);
50
+ * return tree ? svgTreeToReact(tree, createElement, { className: 'figure', width: '100%' }) : null;
51
+ * ```
52
+ *
53
+ * @param node - The tree (normally the root `<svg>`).
54
+ * @param createElement - `React.createElement` or a compatible factory.
55
+ * @param rootProps - Extra props merged onto the root element (override
56
+ * `width`/`height`, add `className`, `role`, ...).
57
+ */
58
+ declare function svgTreeToReact<E>(node: SvgNode, createElement: CreateElement<E>, rootProps?: Record<string, unknown>): E;
59
+ /** Options for {@link svgTreeToJsx}. */
60
+ interface SvgJsxOptions {
61
+ /** Component name. Default `Metafile`. */
62
+ componentName?: string;
63
+ /** Emit TypeScript (`SVGProps<SVGSVGElement>` typing). Default `true`. */
64
+ typescript?: boolean;
65
+ /**
66
+ * Spread the component's props onto the root `<svg>` (after the recorded
67
+ * attributes, so callers can override `width`/`height`). Default `true`.
68
+ */
69
+ spreadProps?: boolean;
70
+ }
71
+ /**
72
+ * Generates JSX/TSX source for a React component rendering the tree, for
73
+ * build-time code generation (write it to a `.tsx` file and import it).
74
+ *
75
+ * ```ts
76
+ * const tree = await convertMetafileToSvgTree(buffer, { idPrefix: 'logo-' });
77
+ * writeFileSync('Logo.tsx', svgTreeToJsx(tree!, { componentName: 'Logo' }));
78
+ * ```
79
+ *
80
+ * The output uses the automatic JSX runtime (no `import React` needed); with
81
+ * `typescript: true` it imports only the `SVGProps` type from `react`.
82
+ */
83
+ declare function svgTreeToJsx(node: SvgNode, options?: SvgJsxOptions): string;
84
+
85
+ /**
86
+ * Public API: auto-detecting EMF/WMF conversion to PNG or SVG.
87
+ *
88
+ * The conversion pipeline for both formats and both outputs follows the same
89
+ * high-level steps:
90
+ * 1. Parse the file header to determine logical bounds and output dimensions
7
91
  * (tried as EMF first, then WMF, to auto-detect the format).
8
- * 2. Create an in-memory canvas (OffscreenCanvas preferred, HTMLCanvasElement
9
- * fallback, or the optional `@napi-rs/canvas` Node.js backend).
10
- * 3. Replay every metafile record onto the canvas context in order.
92
+ * 2. Create a drawing surface: an in-memory canvas (OffscreenCanvas
93
+ * preferred, HTMLCanvasElement fallback, or the optional `@napi-rs/canvas`
94
+ * Node.js backend) for PNG output, or an {@link SvgContext} recorder for
95
+ * SVG output.
96
+ * 3. Replay every metafile record onto the surface in order.
11
97
  * 4. Resolve "deferred images", bitmap / embedded-metafile draws that require
12
98
  * async image decoding (via {@link createImageBitmap} or, in Node.js, the
13
- * `@napi-rs/canvas` `loadImage` helper).
14
- * 5. Export the canvas contents as a `data:image/png;base64,...` URL.
99
+ * `@napi-rs/canvas` `loadImage` helper). SVG output embeds PNG/JPEG/GIF/
100
+ * WebP bytes verbatim and nested metafiles as nested SVG, with no decode.
101
+ * 5. Export: a `data:image/png;base64,...` URL, or an SVG tree that can be
102
+ * serialised to markup, a data URL, React elements, or JSX source.
15
103
  *
16
104
  * @module emf-converter
17
105
  */
106
+
18
107
  /**
19
108
  * Configuration options for EMF/WMF conversion.
20
109
  */
@@ -25,8 +114,8 @@ interface EmfConvertOptions {
25
114
  maxHeight?: number;
26
115
  /**
27
116
  * DPI scale factor for higher-resolution output.
28
- * Default is 2 (HiDPI). Set to 1 for 1:1 pixel mapping.
29
- * Values above 4 are clamped to 4 to prevent excessive memory usage.
117
+ * Default is 1 (1:1 pixel mapping). Values above 4 are clamped to 4 to
118
+ * prevent excessive memory usage.
30
119
  */
31
120
  dpiScale?: number;
32
121
  /**
@@ -46,6 +135,48 @@ interface EmfConvertOptions {
46
135
  * 'ms shell dlg': 'Tahoma' }`. Applied to GDI, WMF, and EMF+ text.
47
136
  */
48
137
  fontFamilyMap?: Record<string, string>;
138
+ /**
139
+ * Antialias plain-GDI (EMF) vector shapes: Rectangle, Ellipse, RoundRect,
140
+ * Polygon, Polyline, arcs, and bracketed paths. Default `true`, Canvas's
141
+ * own smooth edges. `false` rasterises their fills and strokes the way
142
+ * Windows GDI does, without antialiasing and on GDI's own pixel grid, for
143
+ * output that matches what Windows paints pixel for pixel. It reads back
144
+ * and rewrites each shape's bounding box, so it is noticeably slower on
145
+ * shape-heavy files. EMF+ drawing and text are unaffected.
146
+ */
147
+ gdiAntialias?: boolean;
148
+ }
149
+ /**
150
+ * Options for the SVG outputs ({@link convertMetafileToSvg} and friends).
151
+ * `maxWidth`/`maxHeight`/`dpiScale`/`maxCanvasDimension` set the SVG's
152
+ * coordinate space (its `viewBox` and default `width`/`height`) and the
153
+ * resolution of any embedded raster content; vector content stays sharp at
154
+ * any display size.
155
+ */
156
+ interface SvgConvertOptions extends EmfConvertOptions {
157
+ /**
158
+ * Evaluate raster operations that read the destination (exact ROP3 blits,
159
+ * exact bitwise ROP2) against a hidden raster mirror of the drawing, and
160
+ * embed the pixels they change as image patches. Needs a canvas backend
161
+ * (browser/worker canvas, or `@napi-rs/canvas` in Node.js); without one,
162
+ * or when set to `false`, those operations fall back to SVG blend modes
163
+ * (`mix-blend-mode`), which are exact for the common mask ROPs on
164
+ * black/white masks and approximate otherwise. Default `true`.
165
+ */
166
+ exactRasterOps?: boolean;
167
+ /**
168
+ * Emit `width`/`height` attributes on the root `<svg>` (the `viewBox` is
169
+ * always emitted). Set `false` for a fluid SVG that fills its container.
170
+ * Default `true`.
171
+ */
172
+ includeSize?: boolean;
173
+ /**
174
+ * Prefix for every generated element id (clip paths, gradients,
175
+ * patterns). Ids must be unique within an HTML document, so give each
176
+ * inlined SVG its own prefix. Defaults to a per-process counter
177
+ * (`emf1-`, `emf2-`, ...).
178
+ */
179
+ idPrefix?: string;
49
180
  }
50
181
  /**
51
182
  * Converts an EMF (Enhanced Metafile) or WMF (Windows Metafile) binary buffer
@@ -56,23 +187,12 @@ interface EmfConvertOptions {
56
187
  * starts with a valid `EMR_HEADER` record, so it doubles as a safe format
57
188
  * sniff. When that probe fails, the buffer is parsed as WMF instead.
58
189
  *
59
- * For EMF: parses the EMF header, iterates over all EMR records, and replays
60
- * them onto an in-memory canvas. Embedded EMF+ (GDI+) records found inside
61
- * EMR_COMMENT payloads are handled transparently.
62
- *
63
- * For WMF: parses the optional Aldus placeable header and the standard WMF
64
- * header, then replays all META_* records onto a canvas.
65
- *
66
- * The canvas is rendered at a configurable DPI scale (default 1x, 1:1 pixel
67
- * mapping) via {@link EmfConvertOptions.dpiScale}. On the first call in a
68
- * given process, the optional Node.js canvas backend (`@napi-rs/canvas`) is
69
- * loaded once and cached; see {@link ensureNodeCanvasModule}.
70
- *
71
190
  * Returns `null` when:
72
191
  * - The buffer matches neither a valid EMF header nor a valid WMF header.
73
192
  * - The logical bounds are zero-sized or negative.
74
193
  * - No canvas API is available (browser/worker canvas, or the optional
75
- * `@napi-rs/canvas` package in plain Node.js).
194
+ * `@napi-rs/canvas` package in plain Node.js). SVG output
195
+ * ({@link convertMetafileToSvg}) needs no canvas at all.
76
196
  *
77
197
  * @param buffer - The raw EMF or WMF file bytes.
78
198
  * @param options - Optional {@link EmfConvertOptions} controlling output size,
@@ -81,6 +201,36 @@ interface EmfConvertOptions {
81
201
  * @returns A `data:image/png;base64,...` string, or `null` on failure.
82
202
  */
83
203
  declare function convertMetafileToDataUrl(buffer: ArrayBuffer, options?: EmfConvertOptions, recursionDepth?: number): Promise<string | null>;
204
+ /**
205
+ * Converts an EMF or WMF buffer (format auto-detected) into an SVG document
206
+ * tree, the common source for every SVG output form: serialise it with
207
+ * {@link svgTreeToString} / {@link svgTreeToDataUrl}, render it in React
208
+ * with {@link svgTreeToReact}, or generate component source with
209
+ * {@link svgTreeToJsx}.
210
+ *
211
+ * Unlike PNG output this needs no canvas implementation: vectors, text,
212
+ * gradients, clipping, and bitmaps are all recorded in pure JavaScript. A
213
+ * canvas backend, when present, is used only to evaluate destination-
214
+ * reading raster operations exactly (see {@link SvgConvertOptions.exactRasterOps})
215
+ * and to measure text.
216
+ *
217
+ * @returns The root `<svg>` node, or `null` for an invalid/empty metafile.
218
+ */
219
+ declare function convertMetafileToSvgTree(buffer: ArrayBuffer, options?: SvgConvertOptions, recursionDepth?: number): Promise<SvgNode | null>;
220
+ /**
221
+ * Converts an EMF or WMF buffer into standalone SVG markup
222
+ * (`<svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>`).
223
+ *
224
+ * @returns The SVG markup, or `null` for an invalid/empty metafile.
225
+ */
226
+ declare function convertMetafileToSvg(buffer: ArrayBuffer, options?: SvgConvertOptions): Promise<string | null>;
227
+ /**
228
+ * Converts an EMF or WMF buffer into a base64 SVG data URL
229
+ * (`data:image/svg+xml;base64,...`), usable directly as an `<img src>`.
230
+ *
231
+ * @returns The data URL, or `null` for an invalid/empty metafile.
232
+ */
233
+ declare function convertMetafileToSvgDataUrl(buffer: ArrayBuffer, options?: SvgConvertOptions): Promise<string | null>;
84
234
 
85
235
  /**
86
236
  * The default DPI scale factor used for EMF/WMF rendering.
@@ -89,4 +239,4 @@ declare function convertMetafileToDataUrl(buffer: ArrayBuffer, options?: EmfConv
89
239
  */
90
240
  declare const DEFAULT_DPI_SCALE = 1;
91
241
 
92
- export { DEFAULT_DPI_SCALE, type EmfConvertOptions, convertMetafileToDataUrl };
242
+ export { type CreateElement, DEFAULT_DPI_SCALE, type EmfConvertOptions, type SvgConvertOptions, type SvgJsxOptions, type SvgNode, convertMetafileToDataUrl, convertMetafileToSvg, convertMetafileToSvgDataUrl, convertMetafileToSvgTree, svgTreeToDataUrl, svgTreeToJsx, svgTreeToReact, svgTreeToString };