Files
vtracer/nodejs/test.js
T
Chris Tsang 749f0df0bd Add nodejs: WebAssembly Node package with no native dependency
New nodejs/ package: a wasm-bindgen crate (vtracer-wasm) built with wasm-pack
that wraps the vtracer framework, plus a thin JS layer for file I/O. Image
decoding (png/jpeg/gif/bmp via the image crate) runs in wasm too, so the
package has zero native dependencies — no sharp, no node-gyp.

No separate general-purpose wasm crate: the Node package directly owns and
wraps the wasm. Excluded from the cargo workspace (wasm-bindgen cdylib), built
with wasm-pack.

JS API (camelCase options): convertBuffer, convertPixels, convertFile,
convertFileSync — each taking an Options object (preset, colorMode,
hierarchical/cutout mosaic, mode, palette, maxColors, optimize, ...). Ships
index.d.ts types and a node smoke test. README updated.

Verified: builds to wasm32-unknown-unknown; `node test.js` passes; output
matches the CLI/Python bindings (253 paths on the tank sample).
2026-07-24 13:08:53 +01:00

53 lines
2.2 KiB
JavaScript

'use strict';
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const vtracer = require('./index.js');
const SAMPLE = path.join(__dirname, '..', 'docs', 'assets', 'samples', 'tank-unit-preview.png');
const data = fs.readFileSync(SAMPLE);
// encoded bytes, default options
let svg = vtracer.convertBuffer(data);
assert(svg.includes('<svg') && svg.includes('<path'), 'default convertBuffer');
console.log('convertBuffer default:', (svg.match(/<path/g) || []).length, 'paths');
// options: bw preset -> all black
svg = vtracer.convertBuffer(data, { colorMode: 'bw' });
assert(svg.includes('fill="#000000"'), 'bw produces black');
console.log('convertBuffer bw:', (svg.match(/<path/g) || []).length, 'paths');
// options: mosaic + polygon + palette
svg = vtracer.convertBuffer(data, { hierarchical: 'cutout', mode: 'polygon', palette: ['#000000', '#ffffff'], optimize: 2 });
assert(svg.includes('<svg'), 'mosaic+palette');
console.log('convertBuffer cutout/polygon/palette:', (svg.match(/<path/g) || []).length, 'paths');
// preset
svg = vtracer.convertBuffer(data, { preset: 'poster' });
console.log('convertBuffer poster:', (svg.match(/<path/g) || []).length, 'paths');
// raw pixels: 20x20, left red / right blue
const w = 20, h = 20;
const rgba = Buffer.alloc(w * h * 4);
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
const i = (y * w + x) * 4;
const [r, g, b] = x < w / 2 ? [220, 40, 40] : [40, 40, 220];
rgba[i] = r; rgba[i + 1] = g; rgba[i + 2] = b; rgba[i + 3] = 255;
}
svg = vtracer.convertPixels(rgba, w, h);
assert(svg.includes('<svg'), 'convertPixels');
console.log('convertPixels:', (svg.match(/<path/g) || []).length, 'paths');
// file I/O
const out = path.join(require('os').tmpdir(), 'vtracer_node_out.svg');
vtracer.convertFileSync(SAMPLE, out, { mode: 'spline' });
assert(fs.statSync(out).size > 0, 'convertFileSync wrote file');
console.log('convertFileSync wrote:', fs.statSync(out).size, 'bytes');
// error handling
assert.throws(() => vtracer.convertBuffer(data, { palette: ['nope'] }), /rrggbb/, 'bad palette rejected');
assert.throws(() => vtracer.convertPixels(Buffer.alloc(8), 10, 10), /rgba length/, 'bad pixel length rejected');
console.log('errors rejected OK');
console.log('ALL OK');