@s8fy/emf2svg 1.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/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ PolyForm Noncommercial License 1.0.0
2
+ https://polyformproject.org/licenses/noncommercial/1.0.0
3
+
4
+ Required Notice: Copyright (c) 2025-PRESENT hustcer
5
+
6
+ This package is source-available, not open source. No commercial use is granted
7
+ to third parties under this package's default license unless separately
8
+ licensed.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @s8fy/emf2svg
2
+
3
+ Pure TypeScript EMF (Enhanced Metafile) and WMF (Windows Metafile) to SVG converter. It has zero runtime dependencies and runs in browsers and Node.js.
4
+
5
+ The package declares Node.js **22.12+**, provides ESM/CommonJS TypeScript declarations, and needs no DOM for conversion. All four exported functions are synchronous.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @s8fy/emf2svg
11
+ # or
12
+ pnpm add @s8fy/emf2svg
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Basic conversion
18
+
19
+ ```typescript
20
+ import { emf2svg, isEmf, isWmf, wmf2svg } from '@s8fy/emf2svg'
21
+
22
+ export function convertMetafile(buffer: ArrayBuffer | Uint8Array): string {
23
+ if (isEmf(buffer)) return emf2svg(buffer)
24
+ if (isWmf(buffer)) return wmf2svg(buffer)
25
+ throw new Error('Unsupported metafile header')
26
+ }
27
+ ```
28
+
29
+ ### Node.js
30
+
31
+ ```typescript
32
+ import { readFileSync, writeFileSync } from 'node:fs'
33
+ import { emf2svg } from '@s8fy/emf2svg'
34
+
35
+ const emfData = readFileSync('diagram.emf')
36
+ const svg = emf2svg(emfData)
37
+ writeFileSync('diagram.svg', svg)
38
+ ```
39
+
40
+ ### Browser (fetch)
41
+
42
+ ```typescript
43
+ import { emf2svg } from '@s8fy/emf2svg'
44
+
45
+ const res = await fetch('/assets/chart.emf')
46
+ if (!res.ok) throw new Error(`Metafile request failed: ${res.status}`)
47
+ const buffer = await res.arrayBuffer()
48
+ const svg = emf2svg(buffer)
49
+ const image = document.createElement('img')
50
+ image.alt = 'Converted chart'
51
+ const url = URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }))
52
+ image.onload = image.onerror = () => URL.revokeObjectURL(url)
53
+ image.src = url
54
+ document.body.append(image)
55
+ ```
56
+
57
+ ## API
58
+
59
+ ### `emf2svg(buffer: ArrayBuffer | Uint8Array): string`
60
+
61
+ Convert an EMF buffer to a complete SVG XML string.
62
+
63
+ - **buffer** — EMF file data
64
+ - **Returns** — SVG string with `xmlns`, `viewBox`, and all rendered elements
65
+ - **Throws** — `Error` if the buffer is not a valid EMF file or has zero-size bounds
66
+
67
+ ### `isEmf(buffer: ArrayBuffer | Uint8Array): boolean`
68
+
69
+ Check the minimum 88-byte header, magic number (`' EMF'` at offset 40), and record type. This is a format probe, not validation of every record; conversion may still fail or return partial output.
70
+
71
+ ### `wmf2svg(buffer: ArrayBuffer | Uint8Array): string`
72
+
73
+ Convert a standard or Aldus placeable WMF buffer to SVG. The WMF path covers the common vector records used by legacy Office clipart and templates, including lines, rectangles, ellipses, polygons, text, pens, and brushes.
74
+
75
+ ### `isWmf(buffer: ArrayBuffer | Uint8Array): boolean`
76
+
77
+ Check whether a buffer has a supported standard or Aldus placeable WMF header.
78
+
79
+ Pass a Node `Buffer` directly: it is a `Uint8Array`, and its offset/length are respected. Do not pass `buffer.buffer` alone for a sliced Buffer, which may include unrelated bytes. Catch conversion errors for invalid/truncated input; format detection does not guarantee complete rendering.
80
+
81
+ ## Supported EMF Records
82
+
83
+ | Category | Records |
84
+ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
85
+ | Control | `HEADER`, `EOF`, `COMMENT` |
86
+ | State | `SAVEDC`, `RESTOREDC`, `SETWINDOWEXTEX`, `SETWINDOWORGEX`, `SETVIEWPORTEXTEX`, `SETVIEWPORTORGEX`, `SETTEXTCOLOR`, `SETTEXTALIGN`, `SETBKMODE`, `SETBKCOLOR`, `SETPOLYFILLMODE`, `SETMITERLIMIT`, `SETMAPMODE` |
87
+ | Object | `SELECTOBJECT`, `DELETEOBJECT`, `CREATEBRUSHINDIRECT`, `CREATEPEN`, `EXTCREATEPEN`, `EXTCREATEFONTINDIRECTW` |
88
+ | Transform | `SETWORLDTRANSFORM`, `MODIFYWORLDTRANSFORM` |
89
+ | Drawing | `MOVETOEX`, `LINETO`, `RECTANGLE`, `ELLIPSE`, `ROUNDRECT`, `POLYGON16`, `POLYLINE16`, `POLYBEZIER16`, `POLYBEZIERTO16`, `POLYLINETO16`, `POLYPOLYGON16`, `POLYGON`, `POLYLINE`, `POLYBEZIER`, `POLYBEZIERTO`, `POLYLINETO` |
90
+ | Path | `BEGINPATH`, `ENDPATH`, `CLOSEFIGURE`, `FILLPATH`, `STROKEPATH`, `STROKEANDFILLPATH`, `SELECTCLIPPATH` |
91
+ | Text | `EXTTEXTOUTW` |
92
+ | Bitmap | `STRETCHDIBITS`, `BITBLT`, `ALPHABLEND`, `TRANSPARENTBLT` |
93
+ | Arc | `ARC`, `ARCTO`, `ANGLEARC`, `PIE`, `CHORD`, `SETARCDIRECTION` |
94
+ | Gradient | `GRADIENTFILL` |
95
+
96
+ The table summarizes implemented record families, not full GDI compatibility. Path abort and rectangle clipping are also handled (`ABORTPATH`, `INTERSECTCLIPRECT`). Unrecognized/unimplemented records are skipped, so files with unsupported records can produce partial output.
97
+
98
+ ## Build Formats
99
+
100
+ | Format | File | Global |
101
+ | ------ | ------------------- | ---------------- |
102
+ | ESM | `dist/index.js` | — |
103
+ | CJS | `dist/index.cjs` | — |
104
+ | UMD | `dist/index.umd.js` | `window.emf2svg` |
105
+
106
+ Production packages do not include source maps.
107
+
108
+ ## Limitations
109
+
110
+ - **EMF+ records** are detected but not rendered (treated as comments)
111
+ - **WMF** support targets common legacy Office vector records; unsupported records are skipped and may produce partial output
112
+ - **GDI raster operations** (`dwRop`) are ignored; bitmaps are rendered as-is
113
+ - **Complex clipping** (region-based) is only partially supported
114
+ - Embedded **DIB bitmaps** are repacked as BMP data URIs; PNG/JPEG payloads are detected and passed through directly
115
+
116
+ ## License
117
+
118
+ The default license is `PolyForm-Noncommercial-1.0.0`. Commercial use requires a separate commercial license.