libvips compiled to standalone WASM for image thumbnailing. No native dependencies — runs in any WASI-compatible runtime.
Pre-built vips-thumbnail.wasm is available from GitHub Releases.
- Input: image bytes piped to stdin
- Output: thumbnail bytes written to stdout
- Errors: diagnostic messages on stderr
argv[0]: "thumbnail" (program name)
argv[1]: <width> (pixels, required)
argv[2]: <suffix> (".jpg", ".png", ".webp", ".avif")
argv[3]: <height> (pixels, 0 = preserve aspect ratio)
argv[4]: <quality> (1-100, 0 = encoder default; applies to JPEG/WebP/AVIF)
argv[5]: <strip> (1 = strip metadata, 0 = keep)
Aspect ratio is always preserved: the result is constrained within the
requested width/height box (or width-only when height=0). Images are always
scaled down (VIPS_SIZE_DOWN), so inputs smaller than the target box are
returned unchanged.
| Format | Read | Write | Suffix |
|---|---|---|---|
| JPEG | yes | yes | .jpg |
| PNG | yes | yes | .png |
| WebP | yes | yes | .webp |
| AVIF | yes | yes | .avif |
| HEIF/HEIC | yes | no (decode-only) | n/a |
The WASM module uses WASI preview1 syscalls plus Emscripten-specific imports for setjmp/longjmp error handling:
invoke_*trampolines (signatures auto-detected from the WASM import list)setThrew(threw, value)_emscripten_throw_longjmp()emscripten_stack_get_current() → i32_emscripten_stack_restore(sp)
Host runtimes must implement these. See the reference implementations below.
main.go — full wazero host with:
- Automatic
invoke_*trampoline registration from WASM imports - setjmp/longjmp via panic/recover with sentinel value
- Persistent compilation cache (
~/.cache/vips-thumb/) - Output format detection from file extension
Library package: govips
out, err := govips.Resize(ctx, inputBytes, govips.ResizeOptions{
Width: 300,
Height: 0,
Format: govips.FormatWebP, // required
Quality: 80,
KeepMetadata: false,
})go build -o vips-thumb .
./vips-thumb input.jpg output.jpg 300
./vips-thumb input.jpg output.webp 300 200
./vips-thumb -q 80 input.jpg output.webp 300
./vips-thumb -keep-metadata input.jpg output.jpg 300
deno/run.ts — WebAssembly.instantiate with:
- Custom minimal WASI preview1 shim
- Native JS try/catch for setjmp/longjmp
- Proxied late-binding for circular import dependencies
deno run -A deno/run.ts input.jpg output.jpg 300
deno run -A deno/run.ts input.jpg output.webp 300 200 80
deno run -A deno/run.ts input.jpg output.jpg 300 0 0 --keep-metadata
- Docker
./build.shOutput: vips-thumbnail.wasm (~9 MB)
go build -o vips-thumb .The following libraries are statically linked into the WASM binary:
| Library | Purpose |
|---|---|
| zlib-ng | Compression |
| libffi | Foreign function interface (for GLib) |
| GLib | Core utilities for libvips |
| Expat | XML parsing |
| libexif | EXIF metadata |
| Little-CMS 2 | ICC color management |
| MozJPEG | JPEG codec |
| libpng | PNG codec |
| libwebp | WebP codec |
| libde265 | H.265 decoder (for HEIF) |
| libaom | AV1 codec (for AVIF) |
| libheif | HEIF/AVIF container |
| libvips | Image processing |