Node.js library to convert raster images to svg using VTracer, with time complexity of O(n).
Tip
Browser example: See twlite/vectorizer-playground for a complete browser example. Due to current WASI limitations in browsers, the async APIs may not work. The synchronous APIs work correctly when executed inside a Web Worker, which is covered by the example.
npx @neplex/vectorizer ./raster.png ./vector.svgOptimize while vectorizing:
npx @neplex/vectorizer ./raster.png ./vector.svg --optimize --multipass --multipass-iterations 5Optimize an existing SVG:
npx @neplex/vectorizer optimize ./vector.svg ./vector.optimized.svg --plugin preset-defaultUse --help to see all available options.
npm install @neplex/vectorizerimport{vectorize,ColorMode,Hierarchical,PathSimplifyMode}from'@neplex/vectorizer';import{readFile,writeFile}from'node:fs/promises';constsrc=awaitreadFile('./raster.png');constsvg=awaitvectorize(src,{colorMode: ColorMode.Color,colorPrecision: 6,filterSpeckle: 4,spliceThreshold: 45,cornerThreshold: 60,hierarchical: Hierarchical.Stacked,mode: PathSimplifyMode.Spline,layerDifference: 5,lengthThreshold: 5,maxIterations: 2,pathPrecision: 5,});console.log(svg);// <svg>...</svg>awaitwriteFile('./vector.svg',svg);The generated SVG string is generally quite large, so it's recommended to optimize it before use. See the SVG Optimization section for more details. If you want to use a synchronous API, you can use vectorizeSync instead. See the API section for more details on available functions and options.
yarnbench
clk: ~5.32GHz
cpu: Intel(R)Core(TM)i7-14700K
runtime: node24.14.1(x64-win32)benchmarkavg(min…max)p75/p99(min…top1%)---------------------------------------------------------------------------------
@neplex/vectorizerrawsync529.82µs/iter533.70µs▅█▅(517.00µs…607.00µs)552.90µs▅██▆▇████▄(1.65kb…168.67kb)1.94kb▃███████████▆▄▃▂▁▂▂▂▁
@neplex/vectorizerencodedsync549.19µs/iter552.70µs▃█▆▇(534.80µs…597.10µs)573.50µs▃▆▆████▆▄(1.60kb…74.57kb)1.70kb▂▆██████████▆▄▂▂▂▂▂▁▁
@neplex/vectorizerencodedasync585.94µs/iter586.00µs▇█(561.70µs…745.10µs)691.10µs██(2.27kb…76.16kb)2.34kb▂▅███▅▃▂▂▁▁▁▁▁▁▂▁▁▁▁▁
@neplex/vectorizerencodedcallback684.02µs/iter698.80µs▃▅▃▃█▂(632.30µs…844.90µs)770.60µs▂▅██████▇▃(4.27kb…44.40kb)4.48kb▂████████████▇▅▆▆▅▃▃▂
@neplex/vectorizerrawasync565.45µs/iter565.20µs▂█(548.70µs…706.00µs)646.00µs██▃(2.33kb…186.42kb)2.58kb▂███▅▃▃▂▂▁▂▁▂▁▁▂▁▁▁▁▁
@neplex/vectorizerrawcallback625.91µs/iter636.20µs▃█▇(591.60µs…779.20µs)704.80µs███▇(3.98kb…374.13kb)4.62kb▂████████▄▅▆▅▆▄▄▃▁▂▁▂imagetracerjs2.41ms/iter2.42ms█▇▂(2.33ms…2.93ms)2.73ms████▂(1.14mb…6.92mb)4.52mb▂█████▃▃▃▃▂▂▂▂▁▂▁▁▁▁▁potracetrace3.59ms/iter4.45ms█▅(1.70ms…7.43ms)6.36ms▆▃█▂██▃▃▅▂▄(736.00b…11.91mb)2.27mb▃██████████████▇▃█▁▆▃summary
@neplex/vectorizerrawsync1.04xfasterthan @neplex/vectorizerencodedsync1.07xfasterthan @neplex/vectorizerrawasync1.11xfasterthan @neplex/vectorizerencodedasync1.18xfasterthan @neplex/vectorizerrawcallback1.29xfasterthan @neplex/vectorizerencodedcallback4.54xfasterthanimagetracerjs6.78xfasterthanpotracetraceSee benchmark for more details.
Takes an image buffer and returns a promise that resolves to an SVG string.
Takes an image buffer and returns an SVG string synchronously.
vectorizeRaw(data: Buffer, args: RawDataConfig, config?: Config | Preset, signal?: AbortSignal): Promise<string>
Takes a raw pixel data buffer and returns a promise that resolves to an SVG string.
Takes a raw pixel data buffer and returns an SVG string synchronously.
vectorizeToCallback(data: Buffer, config: Config | Preset | null | undefined, callback: (chunk: string, progress: number) => void): void
Vectorizes an image buffer and emits SVG chunks to the callback. progress is a number from 0 to 100 indicating how much of the vectorization has been written.
vectorizeRawToCallback(data: Buffer, args: RawDataConfig, config: Config | Preset | null | undefined, callback: (chunk: string, progress: number) => void): void
Vectorizes raw pixel data and emits SVG chunks to the callback. progress is a number from 0 to 100.
Decodes an encoded image buffer, or a raw RGBA buffer when args is provided, and resolves image width, height, and pixels.
Decodes an encoded image buffer, or a raw RGBA buffer when args is provided, synchronously.
Checks asynchronously whether a decoded image contains the given RGB color.
Checks synchronously whether a decoded image contains the given RGB color.
findUnusedColorInImage(image: ImageData, options?: InternalOptions, signal?: AbortSignal): Promise<Color>
Finds asynchronously a color that does not exist in decoded image data.
Finds synchronously a color that does not exist in decoded image data.
Optimizes an SVG string asynchronously. Supports the same options as optimizeSync.
Optimizes an SVG string synchronously.
OptimizeOptions supports:
preset?: OptimizePreset:Default,Safe, orNone.plugins?: Array<string | { name: string, params?: unknown }>: SVGOConfig["plugins"]compatible job config. When provided, this defines the optimizer job set.omit?: string[]: optimizer job names to skip.multipass?: boolean: run optimization until output stops changing or the iteration limit is reached.multipassIterations?: number: maximum multipass iterations. Defaults to10.
Determines if the given chunk data indicates the end of the SVG output. Useful for callback-based vectorization to know when the final chunk has been received. Note that EOF here refers to the final chunk of svg, which is </svg>\n.
const{ promise, resolve }=Promise.withResolvers<void>();vectorizeToCallback(src,config,(chunk,progress)=>{if(isEOF(chunk,progress)){resolve();}});awaitpromise;// block until all the SVG chunks have been receivedconsole.log('SVG output complete!');The raw output from vectorize can be significantly reduced in size using the built-in optimizer powered by oxvg_optimiser:
import{optimize,vectorize}from'@neplex/vectorizer';import{readFile,writeFile}from'node:fs/promises';constsrc=awaitreadFile('./input.png');constsvg=awaitvectorize(src);constoptimized=awaitoptimize(svg,/* optional config */{plugins: ['preset-default',{name: 'removeTitle'}],// supports svgo plugin configmultipass: true,// enable multipass optimizationmultipassIterations: 5,// limit multipass iterations to 5},);awaitwriteFile('./output.svg',optimized);Note that the optimizer included in this library is a thin wrapper around
oxvg_optimiserand does not intend to provide all the features ofoxvg. For advanced needs, consider using@oxvg/napidirectly.
Generated under the following configuration:
{colorMode: ColorMode.Color,colorPrecision: 8,filterSpeckle: 4,spliceThreshold: 45,cornerThreshold: 60,hierarchical: Hierarchical.Stacked,mode: PathSimplifyMode.Spline,layerDifference: 6,lengthThreshold: 4,maxIterations: 2}| Raster Image (PNG Input) | Vector Image (Generated SVG) |
|---|---|
![]() CC-BY-SA 3.0 by Niabot | CC-BY-SA 3.0 by Niabot |
