npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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/emf2svg

Usage

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
  • ThrowsError if 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.