@wasmedia/wlensfun
v0.3.0
Published
lensfun compiled to WebAssembly for browsers
Maintainers
Readme
wlensfun
lensfun compiled to WebAssembly — lens distortion, transverse chromatic aberration and vignetting correction in the browser, driven by lensfun's database of measured lens profiles.
Try it: lensfun.wasmedia.org — load a photo, pick the camera and lens, and correct it entirely in the browser.
Part of the wasmedia family of single-threaded + SIMD WASM ports that work
on any site without COOP/COEP headers.
Install
npm install @wasmedia/wlensfun
npx wlensfun-fetch-db --out public # download the lens profile databaseThe profile database is not bundled in the package. It is licensed
CC BY-SA 3.0 rather than LGPL, upstream releases it independently of the
library, and it is larger than the rest of the package combined. The CLI
fetches it and repackages it for browsers as lensfun-db-v2.json.gz, written
to --out <dir> (the current directory if omitted). Serve it alongside your
app.
Usage
import { initWLensfun } from '@wasmedia/wlensfun';
const lf = await initWLensfun();
const db = await lf.loadDatabase('/lensfun-db-v2.json.gz');
const cam = db.findCamera('Canon', 'Canon EOS 5D Mark III');
const lens = db.findLens(cam, null, 'Canon EF 24-70mm f/2.8L II USM');
const mod = db.modifier(cam, lens, {
focal: 35, aperture: 5.6, distance: 3,
width: image.width, height: image.height,
});
const corrected = mod.apply(pixels); // reusable across frames
mod.dispose();
db.dispose();Both handles wrap raw pointers into WASM memory, so dispose() is not
optional — nothing else frees them.
The database can also be loaded straight from lensfun's XML files — an OPFS
directory in a worker, or a host directory under Node — with
lf.loadDatabaseFiles(). It uses wopfs
to read the files in place rather than copying them into memory.
Cameras match on their EXIF spelling first, then fuzzily, so both
('Canon', 'Canon EOS 5D Mark III') and wlibraw's ('Canon', 'EOS 5D Mark III')
work. Lenses always match fuzzily.
From a raw file
examples/node/correct-raw.mjs decodes a camera
raw with wlibraw, takes the
camera, lens, focal length and aperture from its metadata, and corrects it in
linear light:
npm run fetch-db
node examples/node/correct-raw.mjs photo.cr2 # add --lens "…" if the file records noneIt writes photo.original.png and photo.corrected.png for comparison. Raw
data is linear, so it corrects with colorSpace: 'linear'. wlibraw's decode()
can't produce linear output yet
(wlibraw#1), so the example
gets it from LibRaw's dcraw_emu -4 through execute().
Frames shot in a crop mode (Nikon DX, 1:1, video crops) need --crop: the
camera's crop factor describes its full sensor, and wlibraw doesn't yet report
the 35 mm-equivalent focal length that would reveal the smaller frame
(wlibraw#2). Pass the
equivalent focal length over the real one, e.g. --crop 1.5 for DX on a
full-frame body.
What it does
apply() runs every correction the lens has calibration data for, in
lensfun's documented order: vignetting first, then distortion and TCA fused
into a single resampling pass so the image is interpolated once rather than
twice. Perspective correction and projection conversion are available through
the corrections argument.
If you would rather resample yourself — on the GPU, say —
coordinatesForRow() hands back the raw coordinate map instead.
Correction is CPU-bound and synchronous; @wasmedia/wlensfun/worker runs it
off the main thread.
Documentation
Scope
wlensfun corrects; it does not decode. Raw handling belongs to wlibraw, format conversion to wvips and wimagemagick. This library takes and returns raw pixel buffers — 8-bit, 16-bit or 32-bit float, 3 or 4 channels.
License
LGPL-3.0-or-later, matching upstream lensfun. See LICENSE.
The lens profile database is separately licensed CC BY-SA 3.0 and carries its own attribution and share-alike obligations. It is fetched at build time rather than bundled, which keeps the two licenses distinct.
