Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

33 Commits

Repository files navigation

@neplex/vectorizer

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.

CLI

npx @neplex/vectorizer ./raster.png ./vector.svg

Optimize while vectorizing:

npx @neplex/vectorizer ./raster.png ./vector.svg --optimize --multipass --multipass-iterations 5

Optimize an existing SVG:

npx @neplex/vectorizer optimize ./vector.svg ./vector.optimized.svg --plugin preset-default

Use --help to see all available options.

Installation

npm install @neplex/vectorizer

Usage

import{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.

Benchmark

yarnbench
clk: ~5.32GHz
cpu: Intel(R)Core(TM)i7-14700K
runtime: node24.14.1(x64-win32)benchmarkavg(minmax)p75/p99(mintop1%)---------------------------------------------------------------------------------
@neplex/vectorizerrawsync529.82µs/iter533.70µs▅█▅(517.00µs607.00µs)552.90µs▅██▆▇████▄(1.65kb168.67kb)1.94kb▃███████████▆▄▃▂▁▂▂▂▁
@neplex/vectorizerencodedsync549.19µs/iter552.70µs▃█▆▇(534.80µs597.10µs)573.50µs▃▆▆████▆▄(1.60kb74.57kb)1.70kb▂▆██████████▆▄▂▂▂▂▂▁▁
@neplex/vectorizerencodedasync585.94µs/iter586.00µs▇█(561.70µs745.10µs)691.10µs██(2.27kb76.16kb)2.34kb▂▅███▅▃▂▂▁▁▁▁▁▁▂▁▁▁▁▁
@neplex/vectorizerencodedcallback684.02µs/iter698.80µs▃▅▃▃█▂(632.30µs844.90µs)770.60µs▂▅██████▇▃(4.27kb44.40kb)4.48kb▂████████████▇▅▆▆▅▃▃▂
@neplex/vectorizerrawasync565.45µs/iter565.20µs▂█(548.70µs706.00µs)646.00µs██▃(2.33kb186.42kb)2.58kb▂███▅▃▃▂▂▁▂▁▂▁▁▂▁▁▁▁▁
@neplex/vectorizerrawcallback625.91µs/iter636.20µs▃█▇(591.60µs779.20µs)704.80µs███▇(3.98kb374.13kb)4.62kb▂████████▄▅▆▅▆▄▄▃▁▂▁▂imagetracerjs2.41ms/iter2.42ms█▇▂(2.33ms2.93ms)2.73ms████▂(1.14mb6.92mb)4.52mb▂█████▃▃▃▃▂▂▂▂▁▂▁▁▁▁▁potracetrace3.59ms/iter4.45ms█▅(1.70ms7.43ms)6.36ms▆▃█▂██▃▃▅▂(736.00b11.91mb)2.27mb▃██████████████▇▃█▁▆▃summary
@neplex/vectorizerrawsync1.04xfasterthan @neplex/vectorizerencodedsync1.07xfasterthan @neplex/vectorizerrawasync1.11xfasterthan @neplex/vectorizerencodedasync1.18xfasterthan @neplex/vectorizerrawcallback1.29xfasterthan @neplex/vectorizerencodedcallback4.54xfasterthanimagetracerjs6.78xfasterthanpotracetrace

See benchmark for more details.

API

vectorize(data: Buffer, config?: Config | Preset, signal?: AbortSignal): Promise<string>

Takes an image buffer and returns a promise that resolves to an SVG string.

vectorizeSync(data: Buffer, config?: Config | Preset): 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.

vectorizeRawSync(data: Buffer, args: RawDataConfig, config?: Config | Preset): 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.

readImage(data: Buffer, args?: RawDataConfig, signal?: AbortSignal): Promise<ImageData>

Decodes an encoded image buffer, or a raw RGBA buffer when args is provided, and resolves image width, height, and pixels.

readImageSync(data: Buffer, args?: RawDataConfig): ImageData

Decodes an encoded image buffer, or a raw RGBA buffer when args is provided, synchronously.

colorExistsInImage(image: ImageData, color: Color, signal?: AbortSignal): Promise<boolean>

Checks asynchronously whether a decoded image contains the given RGB color.

colorExistsInImageSync(image: ImageData, color: Color): boolean

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.

findUnusedColorInImageSync(image: ImageData, options?: InternalOptions): Color

Finds synchronously a color that does not exist in decoded image data.

optimize(svg: string, options?: OptimizeOptions, signal?: AbortSignal): Promise<string>

Optimizes an SVG string asynchronously. Supports the same options as optimizeSync.

optimizeSync(svg: string, options?: OptimizeOptions): string

Optimizes an SVG string synchronously.

OptimizeOptions supports:

  • preset?: OptimizePreset: Default, Safe, or None.
  • plugins?: Array<string | { name: string, params?: unknown }>: SVGO Config["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 to 10.

isEOF(chunk: string, progress: number): boolean

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!');

SVG Optimization

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_optimiser and does not intend to provide all the features of oxvg. For advanced needs, consider using @oxvg/napi directly.

Demo

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)
Raster Image
CC-BY-SA 3.0 by Niabot
Vector Image
CC-BY-SA 3.0 by Niabot

About

Fast JavaScript library to convert and optimize raster images to svg using vtracer

Topics

Resources

Code of conduct

Contributing

Stars

208 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages