@walujanle/image-converter-wasm
v1.0.0
Published
Rust WebAssembly image converter for browser and Node.js runtimes.
Maintainers
Readme
image-converter-wasm
Rust WebAssembly image converter for browser and Node.js runtimes.
License: AGPL-3.0-only
This package converts images entirely in memory. Input and output are Uint8Array values; the host application owns file picking, downloads, uploads, caching, and any filesystem work.
Installation
npm install @walujanle/image-converter-wasmFeatures
- Format-split WASM modules: JPEG, PNG, WebP, and AVIF are separate WASM binaries. Only the selected output codec is loaded.
- ESM and CommonJS entries: Use
importorrequirefrom the package root. - Browser and Node.js support: Browser/bundler builds use adjacent WASM asset URLs. Node.js loads the packaged WASM bytes directly.
- Supported input:
jpg,jpeg,png,webp,heic,heif,avif. - Supported output: JPEG, PNG, WebP, AVIF.
- HEIC/HEIF decode-only support: HEIC/HEIF can be converted from, but not encoded to.
- Metadata extraction: EXIF, XMP, IPTC, and ICC extraction from in-memory bytes.
- Metadata preservation:
keepMetadataenables EXIF/XMP/IPTC preservation where the output container supports it. ICC color profiles may be retained for color fidelity when available. - Crop and resize: Percent crop, aspect-ratio-aware resize, and smart filter selection.
- Input hardening: Size, dimension, extension, and magic-byte validation run before decode.
- Progress callback:
convertImageWithInfocan report stage-based progress.
Quick Start
ESM
import { convertImage, init } from '@walujanle/image-converter-wasm';
await init({ preload: ['Jpeg'] });
const input = new Uint8Array(await file.arrayBuffer());
const output = await convertImage(input, '.PNG', {
format: 'Jpeg',
quality: 82,
resize: true,
targetWidth: 1600,
resizeLockAspectRatio: true,
keepMetadata: true,
});
const blob = new Blob([output], { type: 'image/jpeg' });CommonJS
const fs = require('fs');
const { convertImage, init } = require('@walujanle/image-converter-wasm');
(async () => {
await init();
const input = new Uint8Array(fs.readFileSync('photo.png'));
const output = await convertImage(input, 'png', {
format: 'Jpeg',
quality: 85,
});
fs.writeFileSync('photo.jpg', output);
})();API
init(options?)
Initializes wrapper configuration and optionally preloads format modules.
type OutputFormat = 'Jpeg' | 'Png' | 'WebP' | 'Avif';
type WasmSource = string | URL | Response | ArrayBuffer | ArrayBufferView | WebAssembly.Module;
interface InitOptions {
wasmSources?: Partial<Record<Lowercase<OutputFormat>, WasmSource>>;
preload?: OutputFormat[];
}wasmSources: Overrides the default WASM source per format. Use this when your framework requires WASM files to be served from a public/static directory.preload: Eagerly initializes selected output modules instead of waiting for first conversion.
You can also pass one direct WASM source to init(...); it becomes the default source for every format.
convertImage(fileBytes, ext, options)
Converts one image buffer and returns encoded bytes as Uint8Array.
interface ConvertOptions {
format: OutputFormat;
quality?: number;
pngCompressed?: boolean;
lossless?: boolean;
resize?: boolean;
targetWidth?: number;
targetHeight?: number;
resizeLockAspectRatio?: boolean;
crop?: boolean;
cropTop?: number;
cropBottom?: number;
cropLeft?: number;
cropRight?: number;
keepMetadata?: boolean;
}Notes:
qualitydefaults to75and applies to JPEG, lossy WebP, and AVIF.losslessapplies to WebP.pngCompressedenables higher PNG compression.- Crop values are percentages from
0to100. - Extensions are normalized, so
PNG,.png, andpngare accepted when the bytes match the format.
convertImageWithInfo(fileBytes, ext, options, onProgress?)
Converts one image buffer and returns bytes plus final dimensions.
interface ConversionResult {
bytes: Uint8Array;
width: number;
height: number;
}const result = await convertImageWithInfo(input, 'webp', {
format: 'Avif',
quality: 70,
}, (progress) => {
console.log(Math.round(progress * 100));
});The progress callback receives values from 0 to 1. Progress is stage-based, not a codec-internal byte counter.
getImageDimensions(fileBytes, ext, format?)
Returns image dimensions without running a conversion.
interface ImageDimensions {
width: number;
height: number;
}extractMetadata(fileBytes, ext, format?)
Extracts embedded metadata from an in-memory image buffer.
interface ImageMetadata {
exif?: number[] | null;
xmp?: number[] | null;
iptc?: number[] | null;
icc?: number[] | null;
}getProjectVersion(format?)
Returns the embedded project version string from the loaded WASM module.
const version = await getProjectVersion(); // "v1.0.0"Metadata Support Matrix
This matrix describes output preservation during conversion when keepMetadata: true.
| Output Format | EXIF | XMP | IPTC | ICC | | ------------- | ---- | --- | ---- | --- | | JPEG | Yes | Yes | Yes | Yes | | PNG | Yes | Yes | Yes | Yes | | WebP | Yes | Yes | No | Yes | | AVIF | Yes | Yes | No | No |
Additional details:
- ICC may be retained independently for color profile fidelity.
- AVIF input can expose ICC during metadata extraction when the source has an ISOBMFF
colrprofile box, but AVIF output does not currently embed ICC. - HEIC output is not supported.
Runtime And Bundler Notes
Browser And Bundlers
The ESM wrapper loads format modules dynamically and passes each generated index_bg.wasm URL to the wasm-bindgen initializer. In many bundlers this works without extra configuration.
If your framework does not serve WASM assets from dependencies, copy the needed files from the package formats/<format>/esm/index_bg.wasm paths into your app's public/static assets and pass explicit URLs:
await init({
wasmSources: {
jpeg: '/wasm/image-converter/jpeg/index_bg.wasm',
png: '/wasm/image-converter/png/index_bg.wasm',
webp: '/wasm/image-converter/webp/index_bg.wasm',
avif: '/wasm/image-converter/avif/index_bg.wasm',
},
});Browser conversions should run in browser-capable code paths. For SSR frameworks, call the browser ESM API from client-side components, client-only hooks, or a web worker.
Node.js ESM
No bundler configuration is required in Node.js. The wrapper reads packaged WASM bytes from disk.
import { init, convertImage } from '@walujanle/image-converter-wasm';
await init();
const output = await convertImage(input, 'png', { format: 'Jpeg' });Node.js CommonJS
const { init, convertImage } = require('@walujanle/image-converter-wasm');
(async () => {
await init();
const output = await convertImage(input, 'png', { format: 'Jpeg' });
})();Next.js, Nuxt, SvelteKit, Astro, React, Vue
Use the browser API only from client-side code when the conversion is meant to run in the browser. If the framework cannot resolve package WASM assets automatically, use wasmSources with public/static URLs as shown above.
Node runtime code can use the Node.js ESM or CommonJS examples. Edge runtimes are not a documented target for this package.
License
This package is licensed as AGPL-3.0-only.
The distributed WASM binaries include AGPL/commercial-licensed dependencies such as heic and zenwebp. Applications distributing this package or using it over a network must comply with AGPL-3.0-only obligations or have a separate compatible licensing path.
