WebP for WebAssembly
v1.6.0WebAssemblyWebP 1.6.0 for browsers, Node.js and edge runtimes, precompiled for wasm32, single-threaded and multi-threaded as @crossbind/port-webp-wasm.
Install
crossbind itself arrives with your bundler plugin, or with a new project from npm create crossbind@beta; Bundlers has Vite, Webpack, Rspack and Rollup.
Usage
Each example runs here, in this tab, and prints what the site build checked.
Each example also has a JavaScript only tab: the same task with no C++ file, calling WebP's own headers from @crossbind/port-webp directly. 2 of 4 work that way; the others say what stops them.
Encode pixels to WebP and decode them back
The simple API most code starts with: WebPEncodeRGBA at a quality, WebPEncodeLosslessRGBA, WebPGetInfo for the size in the header and WebPDecodeRGBA for the pixels. The input is a generated 256×256 landscape with a little noise, standing in for a photo.
The same four calls on the headers libwebp ships; what the C++ did for you is now yours. Pixels go in through allocBuffer and writeBytes, the encoders hand their bytes back through a uint8_t ** (an allocPointer(1) slot read with readPointerAt), WebPGetInfo writes the size into two allocBuffer(4) ints, and everything libwebp allocated goes back through WebPFree from types.h. WebPGetEncoderVersion packs the version into one integer, 0xMMmmpp.
Tune the encoder and measure what it gave away
The advanced API: WebPConfigPreset picks settings for the kind of image, then method, sharp YUV and a target size adjust them before WebPEncode. WebPPlaneDistortion measures PSNR and SSIM against the original, so a quality can be chosen by numbers.
WebPConfig (the photo preset fills it; method, use_sharp_yuv and target_size are its fields), and the config itself works from JavaScript: crossbind binds its number fields, WebPConfigPreset with WEBP_PRESET_PHOTO reads back sns_strength 80, and method 99 makes WebPValidateConfig return 0. The only function that encodes with it, WebPEncode, also needs a WebPPicture with a width, a height and a writer for the bytes, and crossbind binds WebPPicture without a single field: what JavaScript assigns stays on the JavaScript object (WebPPictureImportRGBA still returns 0, writer reads back undefined), and an allocBuffer block in its place is refused with "Expected null or instance of WebPPicture, got an instance of NativePointer". From JavaScript only the quality changes, through WebPEncodeRGBA with the default preset; measuring works (WebPPlaneDistortion gives PSNR 34.71 dB and SSIM 0.9074 at quality 80).Keep transparency, and decide what happens under it
A lossy WebP stores alpha in a plane of its own: alpha_quality 100 keeps it exact, lower values trade it for bytes. Lossless keeps every visible pixel, but may change the colour under fully transparent pixels to compress better unless exact is set.
alpha_quality and exact are WebPConfig fields, which JavaScript can set, but only WebPEncode encodes with them, and it needs a WebPPicture that crossbind binds without fields: the width and height JavaScript assigns never reach C (WebPPictureImportRGBA returns 0) and writer reads back undefined. The simple encoders run with fixed choices instead: WebPEncodeRGBA at quality 80 keeps alpha exact (1890 B, alpha unchanged, as in the first line of the C++ version), and WebPEncodeLosslessRGBA always encodes at quality 70 with exact off, giving 1706 B with the colour under transparent pixels changed. Neither choice can be changed from JavaScript.Inspect a WebP, then decode only what you need
WebPGetFeatures reads size, alpha, animation and lossy or lossless from the header. WebPDecode with a WebPDecoderConfig scales to a thumbnail or crops a region while it decodes. The file comes from the first example's encoder.
WebPGetFeatures fills a WebPBitstreamFeatures, and its fields read back from JavaScript (format is 1 for lossy, 2 for lossless, 0 for mixed). The thumbnail and the region are missing: WebPDecode scales and crops by config.options, and crossbind binds WebPDecoderConfig without fields (options reads back undefined, and an allocBuffer block in its place is refused). The WebPDecoderOptions class it does bind has use_scaling but no scaled_width or crop_left, because libwebp declares those two to a line (int crop_left, crop_top;).
What is different on WebAssembly
- In a browser the module runs in a Worker by default (
useWorker), so every call returns a promise:awaitcalls and constructors alike. - The module has its own filesystem:
m.FSwrites files,m.getFileBytesreads them back andm.autoMountFilesmountsFileobjects from an<input type=file>./memfslives in memory;/opfspersists across reloads and needs the Worker. See Filesystem. - In Node.js,
m.FSis the real disk, so use real paths there. - Multi-threaded builds (
runtime: 'mt') need COOP and COEP headers in production. See Threading.
Other platforms
- WebP overview: the apps, every platform's setup and the packages.
- WebP for Android: React Native apps on Android.
- WebP for iOS: React Native apps on iOS.
- WebP for WASI: command-line programs under wasmtime.
Facts on this page come from the port manifests in the repository and from what npm served on beta when the site was built. See the Libraries guide for the full consumer flow.