@s8fy/emf2svg
v1.0.1
Published
Pure TypeScript EMF and WMF to SVG converter with zero dependencies
Readme
@s8fy/emf2svg
Pure TypeScript EMF (Enhanced Metafile) and WMF (Windows Metafile) to SVG converter. It has zero runtime dependencies and runs in browsers and Node.js.
The package declares Node.js 22.12+, provides ESM/CommonJS TypeScript declarations, and needs no DOM for conversion. All four exported functions are synchronous.
Install
npm install @s8fy/emf2svg
# or
pnpm add @s8fy/emf2svgUsage
Basic conversion
import { emf2svg, isEmf, isWmf, wmf2svg } from '@s8fy/emf2svg'
export function convertMetafile(buffer: ArrayBuffer | Uint8Array): string {
if (isEmf(buffer)) return emf2svg(buffer)
if (isWmf(buffer)) return wmf2svg(buffer)
throw new Error('Unsupported metafile header')
}Node.js
import { readFileSync, writeFileSync } from 'node:fs'
import { emf2svg } from '@s8fy/emf2svg'
const emfData = readFileSync('diagram.emf')
const svg = emf2svg(emfData)
writeFileSync('diagram.svg', svg)Browser (fetch)
import { emf2svg } from '@s8fy/emf2svg'
const res = await fetch('/assets/chart.emf')
if (!res.ok) throw new Error(`Metafile request failed: ${res.status}`)
const buffer = await res.arrayBuffer()
const svg = emf2svg(buffer)
const image = document.createElement('img')
image.alt = 'Converted chart'
const url = URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }))
image.onload = image.onerror = () => URL.revokeObjectURL(url)
image.src = url
document.body.append(image)API
emf2svg(buffer: ArrayBuffer | Uint8Array): string
Convert an EMF buffer to a complete SVG XML string.
- buffer — EMF file data
- Returns — SVG string with
xmlns,viewBox, and all rendered elements - Throws —
Errorif the buffer is not a valid EMF file or has zero-size bounds
isEmf(buffer: ArrayBuffer | Uint8Array): boolean
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.
wmf2svg(buffer: ArrayBuffer | Uint8Array): string
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.
isWmf(buffer: ArrayBuffer | Uint8Array): boolean
Check whether a buffer has a supported standard or Aldus placeable WMF header.
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.
Supported EMF Records
| Category | Records |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Control | HEADER, EOF, COMMENT |
| State | SAVEDC, RESTOREDC, SETWINDOWEXTEX, SETWINDOWORGEX, SETVIEWPORTEXTEX, SETVIEWPORTORGEX, SETTEXTCOLOR, SETTEXTALIGN, SETBKMODE, SETBKCOLOR, SETPOLYFILLMODE, SETMITERLIMIT, SETMAPMODE |
| Object | SELECTOBJECT, DELETEOBJECT, CREATEBRUSHINDIRECT, CREATEPEN, EXTCREATEPEN, EXTCREATEFONTINDIRECTW |
| Transform | SETWORLDTRANSFORM, MODIFYWORLDTRANSFORM |
| Drawing | MOVETOEX, LINETO, RECTANGLE, ELLIPSE, ROUNDRECT, POLYGON16, POLYLINE16, POLYBEZIER16, POLYBEZIERTO16, POLYLINETO16, POLYPOLYGON16, POLYGON, POLYLINE, POLYBEZIER, POLYBEZIERTO, POLYLINETO |
| Path | BEGINPATH, ENDPATH, CLOSEFIGURE, FILLPATH, STROKEPATH, STROKEANDFILLPATH, SELECTCLIPPATH |
| Text | EXTTEXTOUTW |
| Bitmap | STRETCHDIBITS, BITBLT, ALPHABLEND, TRANSPARENTBLT |
| Arc | ARC, ARCTO, ANGLEARC, PIE, CHORD, SETARCDIRECTION |
| Gradient | GRADIENTFILL |
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.
Build Formats
| Format | File | Global |
| ------ | ------------------- | ---------------- |
| ESM | dist/index.js | — |
| CJS | dist/index.cjs | — |
| UMD | dist/index.umd.js | window.emf2svg |
Production packages do not include source maps.
Limitations
- EMF+ records are detected but not rendered (treated as comments)
- WMF support targets common legacy Office vector records; unsupported records are skipped and may produce partial output
- GDI raster operations (
dwRop) are ignored; bitmaps are rendered as-is - Complex clipping (region-based) is only partially supported
- Embedded DIB bitmaps are repacked as BMP data URIs; PNG/JPEG payloads are detected and passed through directly
License
The default license is PolyForm-Noncommercial-1.0.0. Commercial use requires a separate commercial license.
