Skip to main content

Img2Num JavaScript

A high-performance raster-to-vector conversion library that transforms images into SVGs. It is powered by WebAssembly (WASM) for speed, while providing easy-to-use JavaScript wrappers for integration into web or Node.js projects.

Features

  • Fast raster vectorization with WASM backend.
  • Typed array support: Works with Uint8Array, Uint8ClampedArray, and Int32Array.
  • String outputs: Converts results directly into SVG strings.
  • Worker-friendly: Supports offloading heavy computations to Web Workers.
  • Zero dependencies: Pure WASM + JS with no external libraries required.

Requirements

Node.js (server-side)

  • Node ≥ 14 is required for ESM support ("type": "module" in package.json).
  • Node ≥ 16 is recommended if you want top-level await and best WASM performance.

Browser (client-side)

  • A modern browser with ES module support (<script type="module">) and WebAssembly support.
  • Most browsers from 2020+ are compatible.
  • Not supported: Internet Explorer 11 or older browsers.

Files and Bundlers

  • When using bundlers (Webpack, Vite, Rollup), ensure that .wasm files (like Img2Num's build-wasm/index.wasm) are properly served or imported.
  • No external JS dependencies are required - the package is pure JS + WASM.

Installation

Using a package manager

Run this in your terminal
npm install img2num

Using a CDN (Content Delivery Network)

CDN: jsDelivr

Paste this into your HTML file
<!-- IMPORTANT: this is browser-only -->
<script src="https://cdn.jsdelivr.net/npm/img2num@0.2.0/dist/browser/img2num.js"></script>

Usage

Img2Num runs in both the browser and Node.js. The conversion functions (e.g., imageToSvg, bilateralFilter, kmeans, findContours, and others) are identical across environments - the only difference is how you obtain the RGBA pixel buffer they operate on. The package automatically resolves the right WASM build for your environment via its exports map, so the img2num import is the same in both cases.

Browser

In the browser, use imageToUint8ClampedArray to decode a File or Blob (e.g. from an <input type="file"> element) into RGBA pixels.

This example mirrors that of the React example app.

Convert an image to an SVG (browser)
import {
imageToUint8ClampedArray,
bilateralFilter,
kmeans,
findContours
} from "img2num";

// Get your image from somewhere, e.g. a File from an <input> element:
const imageFile = /* File object, e.g., input.files[0] */;

// Convert image to a Uint8ClampedArray
const { pixels, width, height } = await imageToUint8ClampedArray(imageFile);

// Reduce noise with a bilateral filter
const filtered = await bilateralFilter({
pixels,
width,
height,
});

// Label the image using K-Means (labels needed for next step)
const { labels } = await kmeans({
pixels: filtered,
width,
height,
num_colors: 16,
});

// Convert image to SVG
const { svg } = await findContours({
pixels: filtered,
labels,
width,
height,
});

Node.js

Node has no DOM, so imageToUint8ClampedArray (which relies on <canvas>) is not available. Instead, decode the image to a raw RGBA buffer with a library such as sharp, then hand the pixels to imageToSvg (or the individual stages). Reading the file with fs.readFile alone is not enough - the bytes must be decoded into raw RGBA.

sharp

This example mirrors the Node console example app.

Convert an image to an SVG (Node.js)
import { writeFileSync } from "fs";
import { imageToSvg } from "img2num";
import sharp from "sharp";

const imagePath = process.argv[2];

// Decode the image into a flat RGBA Uint8ClampedArray
const { data, info } = await sharp(imagePath).ensureAlpha().raw().toBuffer({ resolveWithObject: true });

const pixels = new Uint8ClampedArray(data.buffer);
const { width, height } = info;

// One-shot conversion (bilateral filter → k-means → contour tracing)
const { svg } = await imageToSvg({ pixels, width, height });

writeFileSync("output.svg", svg);

Resources

License

The JavaScript package is licensed under the following:

  • MIT © Ryan Millard