Image API — `ImageHandle` · `Engine`

Auto-generated from bridge/src/js/prelude/src/ on 2026-05-21. Run task gen:api-reference to refresh.

All pixel-processing operations live on ImageHandle (the value you get back from Engine.loadImage() / Engine.createImage()). The Engine global is the entry point for loading, creating, and saving images, plus the canvas / path / animation / tool / timer factories.

← Back to API Reference index


Classes

ImageHandle

A handle to an image stored in the Rust image registry.

Most methods return this for fluent chaining:

const img = Engine.loadImage("input.png");
img.brightness(1.2).gaussianBlur(1.5).save("out.png");

Size-changing operations (crop, resize, pad, rotateExpand, warpPolar, warpPerspective) update width and height automatically.

Accessors

height
Get Signature
get height(): number;

Current image height in pixels. Updated automatically by size-changing ops.

Returns

number

Set Signature
set height(v): void;
Parameters
Parameter Type
v number
Returns

void

id
Get Signature
get id(): number;

Internal handle id (read-only). Needed for cross-image ops like blend/applyMask.

Returns

number

width
Get Signature
get width(): number;

Current image width in pixels. Updated automatically by size-changing ops.

Returns

number

Set Signature
set width(v): void;
Parameters
Parameter Type
v number
Returns

void

Methods

_setHeightAndWidthUnsafe()
_setHeightAndWidthUnsafe(h, w): void;
Parameters
Parameter Type
h number
w number
Returns

void

addNoise()
addNoise(opts?, region?): this;

Add synthetic sensor noise — the core degradation primitive for building model-training data (Real-ESRGAN / GFPGAN style: take a clean image, degrade it, train the network to invert it).

Unlike filmGrain (uniform mono grain only), this exposes the distribution shapes a degradation pipeline actually needs:

  • "gaussian" — normal noise, constant standard deviation sigma. The classic additive read-noise.
  • "uniform" — flat noise in ±sigma (same as filmGrain).
  • "poisson" — shot noise whose strength scales with √pixel: bright regions get noisier, shadows stay clean. Modelled as the standard Gaussian approximation of Poisson statistics; sigma is the overall gain.
Parameters
Parameter Type Description
opts? { color?: boolean; sigma?: number; type?: "gaussian" | "uniform" | "poisson"; } -
opts.color? boolean false (default) shares one sample across RGB (luminance grain); true perturbs each channel independently (chroma noise). Alpha is never touched.
opts.sigma? number Noise strength (≈ [0..1]). Default 0.05.
opts.type? "gaussian" | "uniform" | "poisson" Distribution. Default "gaussian".
region? Rect | RegionOpts Optional region to limit the effect to.
Returns

this

this

Note

Non-deterministic — result varies between runs.

Example
// Real-ESRGAN-style degradation step
img.gaussianBlur(1.5)
   .resize(img.width / 2, img.height / 2)
   .addNoise({ type: "poisson", sigma: 0.08, color: true });
adjustAlpha()
adjustAlpha(
   value, 
   mode?, 
   region?): this;

Adjust the alpha (transparency) channel.

Parameters
Parameter Type Description
value number Target value; meaning depends on mode.
mode AlphaMode AlphaMode.Set = set directly; Mul = multiply; Add = add (clamped). Default: Set.
region? Rect | RegionOpts -
Returns

this

this

anisotropicBlur()
anisotropicBlur(sigmaX, sigmaY): this;

Anisotropic Gaussian blur — independent sigmas on the X and Y axes. Useful for lens-style streak effects, fake shallow depth of field, or just a "stretched lights" look. When sigmaX === sigmaY this matches gaussianBlur(sigmaX). Either sigma ≤ 0 disables that axis (so a horizontal-only or vertical-only smear is just anisotropicBlur(8, 0) / anisotropicBlur(0, 8)).

Parameters
Parameter Type Description
sigmaX number Horizontal Gaussian sigma in pixels.
sigmaY number Vertical Gaussian sigma in pixels.
Returns

this

this

Example
// Horizontal motion-streak hint — vertical detail intact.
img.anisotropicBlur(12, 1);
// Camera-shake-style stretch in both axes, more horizontal.
img.anisotropicBlur(8, 3);
anisotropicKuwahara()
anisotropicKuwahara(radius, region?): this;

Anisotropic Kuwahara filter (Kyprianidis 2009) — the state-of-the-art painterly stylisation. Where kuwahara uses four axis-aligned quadrants, this version drives the kernel geometry from the local image structure: brush strokes follow the dominant edge direction (hair runs along hair, ridges along ridges) and stretch into long, thin shapes in highly-directional regions. Result: noticeably closer to a real painting than the classical version, especially around faces, fabric and natural texture.

Cost is ~3-5× the classical Kuwahara at the same radius — we additionally compute a structure tensor (smoothed gradient outer product) before the per-pixel sector accumulation. radius 6-12 is typical; larger looks more "broad-stroke".

Parameters
Parameter Type Description
radius number Maximum kernel half-extent in pixels (≥ 1).
region? Rect | RegionOpts -
Returns

this

this

Example
img.anisotropicKuwahara(8);          // painterly portrait
img.bilateralBlur(5, 0.25, 8)
   .anisotropicKuwahara(10)
   .saturation(1.10);                // pre-smooth for cleaner strokes
applyMask()
applyMask(mask): this;

Apply a luminance mask — the mask image's greyscale value sets this image's alpha.

Parameters
Parameter Type Description
mask ImageHandle Mask image (must have the same dimensions).
Returns

this

this

artisticBold()
artisticBold(size?): this;

Ink-drawing effect — black-on-white outline silhouette built from canny(0.1, 0.2) → dilate(size) → invert. Kept as a convenience alias.

Parameters
Parameter Type Default value Description
size number 3 Dilation radius. Larger = thicker ink lines. Default 3.
Returns

this

this

Deprecated

Convenience alias. New code should compose the three primitives explicitly so the intent is visible: img.canny(0.1, 0.2).dilate(size).invert(). Or for a softer / shaded sketch look, use img.pencilSketch(strength).

autocrop()
autocrop(opts?): this;

Trim a uniform-colour or transparent border. Finds the smallest rectangle containing every non-background pixel and crops to it. Updates width and height. When the whole image is background, returns this unchanged.

Default behaviour (no opts): trim transparent margins (α ≤ 0.001).

Parameters
Parameter Type Description
opts? { color?: Color; padding?: number; tolerance?: number; } -
opts.color? Color If set, trim that solid colour instead of transparency (Pixel or hex string). α=0 pixels are also treated as background so mixed transparent + flat-colour borders work without a second pass.
opts.padding? number Pixels of margin to keep around the detected box. Default 0. Clamped to image bounds.
opts.tolerance? number How close to the background a pixel can be before it counts as content. In [0, 1]. Default 0.001 (alpha) / 0.05 (color).
Returns

this

this

Example
// Drop transparent edges
Engine.loadImage("logo.png").autocrop().save("logo_tight.png");

// Drop a white frame around a scan
Engine.loadImage("scan.jpg")
      .autocrop({ color: "#ffffff", tolerance: 0.04, padding: 8 })
      .save("trimmed.jpg");
bilateralBlur()
bilateralBlur(
   d, 
   sigmaColor, 
   sigmaSpace, 
   region?): this;

Bilateral blur — edge-preserving smoothing.

Parameters
Parameter Type Description
d number Diameter of pixel neighbourhood.
sigmaColor number Color sigma (larger = smoother colors).
sigmaSpace number Space sigma (larger = wider area).
region? Rect | RegionOpts -
Returns

this

this

blend()
blend(
   other, 
   factor, 
   mode?): this;

Blend another image onto this one. Both images must have the same dimensions.

Parameters
Parameter Type Description
other ImageHandle The image to blend in.
factor number Blend weight ∈ [0..1]: 0 = only self, 1 = only other.
mode? BlendMode Blend mode (default: Normal = 0).
Returns

this

this

blendAt()
blendAt(
   other, 
   at, 
   factor, 
   mode?): this;

Blend another image onto this one at a specific pixel position. The other image may be smaller — it is composited at at.

Parameters
Parameter Type Description
other ImageHandle The image to composite.
at Px Pixel-space offset, e.g. px(100, 50) or px(0, 0).
factor number Blend weight ∈ [0..1].
mode? BlendMode Blend mode (default: Normal = 0).
Returns

this

this

boxBlur()
boxBlur(size, region?): this;

Box blur (average filter).

Parameters
Parameter Type Description
size number Kernel half-size in pixels.
region? Rect | RegionOpts -
Returns

this

this

brightness()
brightness(factor, region?): this;

Adjust brightness.

Parameters
Parameter Type Description
factor number Multiplier: 1.0 = unchanged, > 1.0 = brighter, < 1.0 = darker.
region? Rect | RegionOpts -
Returns

this

this

canny()
canny(
   low, 
   high, 
   region?): this;

Canny edge detection (two-threshold).

Parameters
Parameter Type Description
low number Low hysteresis threshold ∈ [0..1].
high number High hysteresis threshold ∈ [0..1].
region? Rect | RegionOpts -
Returns

this

this

clone()
clone(): ImageHandle;

Create a deep copy of this handle. The clone is independent — operations on it do not affect the original.

Returns

ImageHandle

A new ImageHandle with its own pixel data.

Throws

If the clone fails.

colorJitter()
colorJitter(
   brightness, 
   contrast, 
   saturation, 
   hue, 
   region?): this;

Randomized color jitter for data augmentation. Each parameter applies random variation in the given range.

Parameters
Parameter Type Description
brightness number Brightness jitter magnitude.
contrast number Contrast jitter magnitude.
saturation number Saturation jitter magnitude.
hue number Hue jitter magnitude (degrees).
region? Rect | RegionOpts -
Returns

this

this

Note

Non-deterministic — result varies between runs.

colorMatch()
colorMatch(reference): this;

Reinhard per-channel mean/std colour transfer — shifts this image's tone to match reference. Per channel:

new = (old - mean_self) * std_ref / std_self + mean_ref

Alpha-weighted, so transparent borders (e.g. from warpPerspective outside-source areas) don't skew the source mean toward zero. Useful for blending AI-restored faces (GFPGAN, CodeFormer) back into a photo's skin-tone neighbourhood: pass the original aligned face crop before warping the restored version back. Dimensions must match.

Parameters
Parameter Type
reference ImageHandle
Returns

this

Example
const aligned  = orig.clone().warpPerspective(512, 512, fwd);
const restored = Engine.tool('gfpgan-restore').apply(aligned);
restored.colorMatch(aligned);  // match orig face's tone
aligned.free();
colorTransfer()
colorTransfer(reference): this;

Reinhard color transfer — match this image's per-channel mean and standard deviation in log-LMS space to a reference image's. Useful for harmonising photos shot under different lighting, matching screenshot tones across OS themes, or warming/cooling a target to fit a hero shot.

Pixels with α = 0 are skipped (left untouched).

If you transfer the same reference onto many targets, prefer Engine.colorStats(ref) once → target.colorTransfer(stats) per target, so the reference stats aren't recomputed every time.

Parameters
Parameter Type Description
reference LmsStats | ImageHandle Either an ImageHandle (stats computed on the spot) or a precomputed LmsStats object from Engine.colorStats().
Returns

this

this

Example
const warm = Engine.loadImage("hero_warm.jpg");
Engine.loadImage("cold_screenshot.png")
      .colorTransfer(warm)
      .save("harmonised.png");
contrast()
contrast(factor, region?): this;

Adjust contrast.

Parameters
Parameter Type Description
factor number 1.0 = unchanged, > 1.0 = higher contrast, 0.0 = flat grey.
region? Rect | RegionOpts -
Returns

this

this

convolve()
convolve(
   kernel, 
   kw?, 
   kh?): this;

Apply a custom 2-D convolution kernel.

The kernel is a flat row-major array applied to the RGB channels. Alpha is preserved. Output is clamped to [0..1].

If kw and kh are omitted the kernel is assumed to be square (sqrt(kernel.length) × sqrt(kernel.length)).

Parameters
Parameter Type Description
kernel number[] Flat row-major kernel values.
kw? number Kernel width (default: Math.sqrt(kernel.length)).
kh? number Kernel height (default: same as kw).
Returns

this

this

Examples
img.convolve([0, -1, 0,  -1, 5, -1,  0, -1, 0]);
img.emboss();
img.convolve(new Array(9).fill(1/9), 9, 1);
crop()
crop(
   x, 
   y, 
   w, 
   h): this;

Crop a rectangular region. Updates width and height.

Parameters
Parameter Type Description
x number Left edge in pixels.
y number Top edge in pixels.
w number Crop width in pixels.
h number Crop height in pixels.
Returns

this

this

differenceMap()
differenceMap(reference): this;

Per-pixel L2 RGB difference between this image and reference — replaces this image with a grayscale heatmap of the distance. Output: R = G = B = min(1, sqrt(dr² + dg² + db²) / sqrt(3)), A = 1.0 (the /√3 normalisation maps black-vs-white to 1.0).

Both images must have the same dimensions; mismatched sizes leave the image untouched.

Phase 1a of the Hertzmann painterly pipeline (the "where does the canvas disagree with the reference" target for stroke placement). Independently useful for:

  • Before/after diff visualisations.
  • Quality-metric heatmaps (where MSE concentrates).
  • Motion-detection gates ("did anything change?").
Parameters
Parameter Type Description
reference ImageHandle Image to compare against.
Returns

this

this

Example
const before = Engine.loadImage(INPUT);
const after  = before.clone().bilateralBlur(9, 0.1, 8);
const diff   = before.clone().differenceMap(after);
diff.save(OUTPUT);  // bright = the blur changed something
dilate()
dilate(size, region?): this;

Morphological dilation — expands bright regions.

Parameters
Parameter Type Description
size number Structuring element radius in pixels.
region? Rect | RegionOpts -
Returns

this

this

dither()
dither(region?): this;

Floyd–Steinberg error-diffusion dithering (reduces to 1-bit per channel).

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

drawText()
drawText(
   text, 
   x, 
   y, 
   opts?): this;

Draw a single line of text onto the image at pixel (x, y). The y-coordinate is the text baseline (SVG default), not the top of the type. Two open-source variable fonts are embedded with the engine and always available:

  • "Inter" (also responds to "sans-serif")
  • "JetBrains Mono" (also "monospace") Custom fonts can be loaded with Engine.loadFont(path).
Parameters
Parameter Type Description
text string The string to draw. < > & are auto-escaped.
x number X coordinate in pixels.
y number Y baseline coordinate in pixels.
opts? | MlcFont | { anchor?: "start" | "middle" | "end"; color?: Color; font?: string; lineHeight?: number; maxWidth?: number; size?: number; textAlign?: TextAlign; } -
Returns

this

this

dropShadow()
dropShadow(
   dx?, 
   dy?, 
   blur?, 
   color?, 
   strength?): this;

Drop shadow — a coloured, blurred, offset silhouette behind the image. Composes tint → blur → blendAt at offset → blendAt sharp on top in one call.

Note: the image stays the same size — pixels of the shadow that fall outside the original frame are clipped. If you need a wider canvas, pad() first then call dropShadow.

Parameters
Parameter Type Default value Description
dx number 5 Horizontal offset in pixels (positive → shadow to the right). Default 5.
dy number 5 Vertical offset in pixels (positive → down). Default 5.
blur number 5 Gaussian sigma of the shadow softness. Default 5.
color Color '#000000' Shadow colour. Hex / Pixel / tuple. Default "#000000".
strength number 1.0 Shadow opacity, ∈ [0..1]. Default 1.0.
Returns

this

this

Example
img.dropShadow(4, 4, 6, "#000000", 0.6);
img.pad(20, 20, 20, 20).dropShadow(8, 12, 10, "#000", 0.5);
emboss()
emboss(): this;

Emboss effect — classic relief kernel that makes the image look carved.

Applies the kernel [-2,-1,0, -1,1,1, 0,1,2], producing a grey midpoint image that highlights directional edges.

Returns

this

this

erode()
erode(size, region?): this;

Morphological erosion — shrinks bright regions.

Parameters
Parameter Type Description
size number Structuring element radius in pixels.
region? Rect | RegionOpts -
Returns

this

this

fillRectangle()
fillRectangle(
   x, 
   y, 
   w, 
   h, 
   color): this;

Fill a rectangular region with a single colour, in-place. The rect is clipped to the image bounds; a fully off-screen rect is a silent no-op.

Accepts the same Color shapes as Engine.createColoredImage: Pixel, hex string, or [r,g,b,(a)] array (0..1 floats).

Parameters
Parameter Type
x number
y number
w number
h number
color Color
Returns

this

Example
img.fillRectangle(10, 10, 100, 80, [1, 0, 0, 1]);   // red box
img.fillRectangle(0, 0, img.width, img.height, "#ffffff"); // whiteout
filmGrain()
filmGrain(amount, region?): this;

Film grain — adds random noise for analog look.

Parameters
Parameter Type Description
amount number Noise intensity ∈ [0..1].
region? Rect | RegionOpts -
Returns

this

this

Note

Non-deterministic — result varies between runs.

fisheye()
fisheye(
   center, 
   radius, 
   amount): this;

Fisheye lens distortion.

Parameters
Parameter Type Description
center Px Center of the distortion in pixel space, e.g. px(img.width/2, img.height/2).
radius number Effect radius in pixels.
amount number Distortion strength (positive = barrel, negative = pincushion).
Returns

this

this

flipH()
flipH(): this;

Flip horizontally (mirror left↔right).

Returns

this

this

flipV()
flipV(): this;

Flip vertically (mirror top↔bottom).

Returns

this

this

forEachPixel()
forEachPixel(fn): this;

Iterate every pixel, calling fn(pixel, x, y). If fn returns a Pixel, that value is written back. ⚠ Very slow for large images — intended for algorithmic / creative use.

Parameters
Parameter Type Description
fn (pixel, x, y) => void | Pixel `(pixel: Pixel, x: number, y: number) => Pixel
Returns

this

this

free()
free(): void;

Release the underlying Rust image buffer. After calling free(), do not use this handle.

Calling free() explicitly is the deterministic option (memory released immediately). When omitted, the FinalizationRegistry in handle-registry.ts releases the buffer on the next GC pass — fine for one-shot scripts, but for tight loops call .free() (or Engine.gc() once per iteration) to keep peak RSS bounded.

Returns

void

gaussianBlur()
gaussianBlur(sigma, region?): this;

Gaussian blur.

Parameters
Parameter Type Description
sigma number Standard deviation in pixels. Higher = more blur.
region? Rect | RegionOpts -
Returns

this

this

getMeta()
getMeta(key): unknown;

Read a single top-level metadata key. Returns the parsed value (any JSON type) or null if the key is unset.

Parameters
Parameter Type
key string
Returns

unknown

Example
img.getMeta("opticscript").width;     // sub-access via JS chaining
img.getMeta("dataset");                // user-set free-form value
getPixel()
getPixel(at): Pixel;

Read a single pixel. Returns a Pixel with r/g/b/a in [0..1].

Parameters
Parameter Type Description
at Px Pixel position, e.g. px(100, 50).
Returns

Pixel

glow()
glow(
   blur?, 
   color?, 
   strength?): this;

Outer glow — soft luminous halo BEHIND the silhouette, extending past the alpha edges. Builds a tinted, blurred, alpha-faded copy of this image and stacks the sharp original on top so the body keeps its original colours and only the region outside the silhouette is coloured.

Implemented as a JS composition of existing primitives: tint → blur → adjustAlpha(strength, Mul) → blendAt halo behind → blendAt sharp on top. Best on inputs with alpha edges (post-rmbg, isolated subjects, rendered SVG, text). On a fully opaque source the sharp top layer covers the halo entirely — the call is effectively a no-op.

Parameters
Parameter Type Default value Description
blur number 15 Gaussian sigma of the halo in pixels. Default 15. Larger = softer / wider halo.
color Color '#ffffff' Halo tint colour. Hex string, Pixel, or [r,g,b,a] tuple. Default "#ffffff".
strength number 1.0 Halo opacity, ∈ [0..1]. Default 1.0.
Returns

this

this

Example
img.glow(15, "#ffffff");          // classic white halo
img.glow(8, "#ff80ff", 0.6);      // soft magenta border
grayscale()
grayscale(region?): this;

Convert to greyscale using luminance weights.

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

hue()
hue(delta, region?): this;

Rotate hue by delta degrees.

Parameters
Parameter Type Description
delta number Degrees to shift hue, e.g. 180 inverts hue.
region? Rect | RegionOpts -
Returns

this

this

invert()
invert(region?): this;

Invert all color channels (negative effect). Alpha is preserved.

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

kaleidoscope()
kaleidoscope(
   center, 
   segments, 
   rotation): this;

Kaleidoscope — mirror-slice symmetry.

Parameters
Parameter Type Description
center Px Center of symmetry in pixel space, e.g. px(img.width/2, img.height/2).
segments number Number of mirror segments.
rotation number Initial rotation offset in degrees.
Returns

this

this

kuwahara()
kuwahara(radius, region?): this;

Classical Kuwahara filter — the modern "oil-painting" / painterly effect. For each pixel the surrounding (2·radius+1)² window is split into four overlapping quadrants; the quadrant with the lowest luminance variance wins and its mean RGB becomes the output. Result: flat regions stay flat, edges snap, and the image gets that characteristic "brush-zone" look without the cubist colour-flattening that the older oilPaint (histogram- based) introduces.

Recommended for new uses. radius 4–8 is a soft sketch, 10–20 a clear painting. Cost is O(W·H·radius²).

Parameters
Parameter Type Description
radius number Window half-extent in pixels (≥ 1).
region? Rect | RegionOpts -
Returns

this

this

Example
img.kuwahara(8);                  // soft painterly look
img.bilateralBlur(7, 0.3, 12)
   .kuwahara(12)
   .saturation(1.15);             // pre-smooth then paint
medianBlur()
medianBlur(radius): this;

Median filter — replaces each pixel's R/G/B channels with the median of the channel values in a (2·radius+1)² window. The classic salt-and-pepper denoiser: a single rogue bright/dark pixel is gone after one pass because the median ignores outliers that the mean would smear into neighbours. For Gaussian-style sensor noise prefer bilateralBlur or nonLocalMeans — those preserve fine texture better.

radius 1-2 typical for impulse cleanup; larger values lose detail quickly. Cost O(W·H·radius²·log(radius)). Alpha preserved.

Parameters
Parameter Type Description
radius number Window half-extent in pixels (≥ 1).
Returns

this

this

mergeMeta()
mergeMeta(key, partial): this;

Shallow-merge a partial object into an existing metadata key. If the key was unset or held a non-object, partial becomes the new value. Convenience for the common setMeta(k, { ...getMeta(k), ...partial }) pattern.

Parameters
Parameter Type
key string
partial Record<string, unknown>
Returns

this

this

Example
img.mergeMeta("exif", { iso: 400, aperture: 2.8 });
meta()
meta(): Record<string, unknown>;

Return the full metadata blob attached to this image as a fresh JS object. Auto-populated entries live under the opticscript.* namespace (fileSize, mime, format, width, height, sourcePath, …); EXIF / DICOM / TIFF parsers add their own siblings; user-set data lives wherever you put it via setMeta.

The returned object is a snapshot — mutating it does not affect storage. Use setMeta(key, value) to write back.

Returns

Record<string, unknown>

Example
const img = Engine.loadImage("photo.jpg");
const m = img.meta();
console.log(m.opticscript.mime);           // "image/jpeg"
console.log(m.opticscript.fileSize);       // 845231
montageH()
montageH(...others): ImageHandle;

Stack this image and one or more others side-by-side horizontally. The result height equals the tallest image; shorter images are top-aligned.

Parameters
Parameter Type Description
...others ImageHandle[] One or more ImageHandles to place to the right.
Returns

ImageHandle

New ImageHandle containing all images concatenated horizontally.

montageV()
montageV(...others): ImageHandle;

Stack this image and one or more others vertically. The result width equals the widest image; narrower images are left-aligned.

Parameters
Parameter Type Description
...others ImageHandle[] One or more ImageHandles to place below.
Returns

ImageHandle

New ImageHandle containing all images concatenated vertically.

motionBlur()
motionBlur(angleDeg, length): this;

Motion blur — directional linear blur along angleDeg for length pixels. Simulates camera or subject motion. Single pass; cost scales with the pixel length of the trail.

angleDeg is measured counter-clockwise from the +x axis: 0 blurs horizontally, 90 vertically, 45 along the diagonal.

Parameters
Parameter Type Description
angleDeg number Direction of motion in degrees.
length number Trail length in pixels (0 = no-op).
Returns

this

this

Example
// 30° camera shake, 24 px trail.
img.motionBlur(30, 24);
// Pure horizontal motion (race car).
img.motionBlur(0, 40);
nonLocalMeans()
nonLocalMeans(
   searchRadius, 
   patchRadius, 
   h): this;

Non-Local Means denoiser — the gold-standard for natural-photo Gaussian noise. For each pixel the filter searches a window of nearby pixels and averages them, weighting each neighbour by patch similarity (small patch around centre vs. small patch around candidate). Similar patches occur naturally throughout a clean image but noise differs sample-to-sample, so the weighted average preserves real structure (edges, texture) while cancelling the noise. Markedly cleaner output than bilateralBlur for sensor noise.

Integral-image accelerated — cost is O(W·H·search²) regardless of patch size; ~2-5 s for a 1500×1000 image at default params (search=7 / patch=3 / h=0.08).

Parameters
Parameter Type Description
searchRadius number Outer search-window half-extent (typical 5-10).
patchRadius number Patch half-extent for similarity (typical 2-3).
h number Filtering parameter; larger = more aggressive smoothing (typical 0.05-0.15 for [0..1] data).
Returns

this

this

Example
img.nonLocalMeans(7, 3, 0.08);          // strong denoise
img.nonLocalMeans(5, 2, 0.05);          // gentle, fast
oilPaint()
oilPaint(
   radius, 
   levels, 
   region?): this;

Oil paint effect (legacy histogram-based) — quantizes to dominant colors in local windows. Kept for backward compatibility; new code should prefer kuwahara(radius) which produces a softer, more painterly look without the cubist colour-flattening this method introduces.

Parameters
Parameter Type Description
radius number Local window radius in pixels.
levels number Number of intensity levels (e.g. 8).
region? Rect | RegionOpts -
Returns

this

this

Deprecated

Prefer kuwahara(radius) for new code.

orientationField()
orientationField(smoothSigma?): this;

Replace this image with an HSV-encoded visualisation of its local edge orientation, derived from the smoothed structure tensor on luminance:

  • Hue = edge direction φ (mapped from [0, π] to a full colour wheel — same physical edge in either direction maps to the same hue).
  • Saturation = coherence ((λ₁ − λ₂) / (λ₁ + λ₂)) — high in clearly oriented regions, low in flat or noisy regions.
  • Value = 1.0 throughout, so flat regions read as bright grayscale and oriented regions burst into colour.

Phase 1b of the Hertzmann painterly pipeline. Same tensor math as anisotropicKuwahara but exposed as a standalone op for any flow-based effect. Visualisation is intentionally lossy — a raw-vector variant will follow when stroke generation needs precise vectors.

Parameters
Parameter Type Default value Description
smoothSigma number 2.0 Gaussian sigma for tensor smoothing (typical 1.0–4.0). Larger = blockier, more coherent fields. Default 2.0.
Returns

this

this

Example
const flow = Engine.loadImage(INPUT).orientationField(2.0);
flow.save(OUTPUT);  // colour wheel = local edge direction
pad()
pad(
   top, 
   bottom, 
   left, 
   right, 
   color?, 
   border?): this;

Pad the image with a border. Updates width and height.

Parameters
Parameter Type Description
top number Top padding in pixels.
bottom number Bottom padding in pixels.
left number Left padding in pixels.
right number Right padding in pixels.
color? PadColor Border color: a Pixel, a CSS hex string ("#rrggbb" / "#rrggbbaa"), or a BorderMode number for non-constant modes (Reflect/Wrap/Replicate). Omit for transparent padding (default).
border? BorderMode BorderMode override when color is a Pixel or string (default: Constant).
Returns

this

this

padBottom()
padBottom(size, color?): this;

Pad bottom only. Shorthand for pad(0, size, 0, 0, color). Updates height.

Parameters
Parameter Type
size number
color? PadColor
Returns

this

padLeft()
padLeft(size, color?): this;

Pad left side only. Shorthand for pad(0, 0, size, 0, color). Updates width.

Parameters
Parameter Type
size number
color? PadColor
Returns

this

padRight()
padRight(size, color?): this;

Pad right side only. Shorthand for pad(0, 0, 0, size, color). Updates width.

Parameters
Parameter Type
size number
color? PadColor
Returns

this

padTop()
padTop(size, color?): this;

Pad top only. Shorthand for pad(size, 0, 0, 0, color). Updates height.

Parameters
Parameter Type
size number
color? PadColor
Returns

this

pencilSketch()
pencilSketch(strength): this;

Pencil-sketch effect — the classic "colour dodge" trick from Photoshop / GIMP tutorials: convert to greyscale, invert, blur, then divide the original grey by 1 - blurred_inverted. Soft natural pencil strokes with the smooth tonal shading graphite gives, no edge-detection harshness. Output is greyscale; alpha preserved.

strength is the Gaussian sigma applied to the inverted copy:

  • 5–10 → tight, fine pencil hatching feel
  • 15–30 → broader graphite shading
  • < 1 → almost identical to plain greyscale
Parameters
Parameter Type Description
strength number Gaussian sigma for the inverted-blur step.
Returns

this

this

Example
img.pencilSketch(20);                    // soft graphite
img.gaussianBlur(0.5)
   .pencilSketch(15)
   .brightness(1.05);                    // pre-soften then sketch
pixelate()
pixelate(size, region?): this;

Pixelate — mosaic effect.

Parameters
Parameter Type Description
size number Block size in pixels.
region? Rect | RegionOpts -
Returns

this

this

posterize()
posterize(levels, region?): this;

Posterize — reduce to N discrete color levels per channel.

Parameters
Parameter Type Description
levels number Number of levels (e.g. 4 = retro poster look).
region? Rect | RegionOpts -
Returns

this

this

premultiplyAlpha()
premultiplyAlpha(region?): this;

Pre-multiply RGB by alpha in-place. Rewrites (R, G, B, A) as (R*A, G*A, B*A, A) so fully-transparent pixels carry RGB=0 and partially-transparent pixels are scaled correspondingly.

Use after rmbg/autocrop and before any geometry op that uses bilinear interpolation (warpPerspective, stampAt, resize, …) to stop background-colour bleed at silhouette edges. The original RGB on transparent pixels (where rmbg only flipped α to 0) would otherwise leak in at every soft edge.

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

Example
Engine.loadImage(INPUT)
  .rmbg()
  .premultiplyAlpha()
  .stampAt(bg, quad, 0.85);
rectFromCenter()
rectFromCenter(
   at, 
   w, 
   h): Rect;

Build a normalized rect centered at a pixel position.

Parameters
Parameter Type Description
at Px Center position in pixel space.
w number Width in pixels.
h number Height in pixels.
Returns

Rect

[x, y, w, h] all ∈ [0..1]

rectFromPixels()
rectFromPixels(
   at, 
   w, 
   h): Rect;

Build a normalized [x, y, w, h] rect from a pixel origin and pixel dimensions.

Parameters
Parameter Type Description
at Px Top-left corner in pixel space.
w number Width in pixels.
h number Height in pixels.
Returns

Rect

[x, y, w, h] all ∈ [0..1]

rectFull()
rectFull(): Rect;

Return a normalized rect covering the full image: [0, 0, 1, 1].

Returns

Rect

removeWhiteBackground()
removeWhiteBackground(opts?): this;

Knock out the bright background of a sketch / lineart by driving alpha from luminance: pixels brighter than threshold become transparent, darker pixels keep their colour and alpha. RGB is preserved — only alpha changes.

Use this for black-on-white sketches where U²-Net (rmbg tool) struggles. Deterministic, no model — just luminance maths.

Parameters
Parameter Type Description
opts? { feather?: number; threshold?: number; } -
opts.feather? number Width of the soft edge in luminance units. 0 = hard binary cut, 0.05 = ~13/255 ramp. Default 0.05.
opts.threshold? number Luminance cut-off ∈ [0..1]. Default 0.95 (≈ 242/255). Anything brighter goes transparent.
Returns

this

this

resize()
resize(
   w, 
   h, 
   interp?): this;

Resize to exact dimensions. Updates width and height.

Parameters
Parameter Type Description
w number Target width in pixels.
h number Target height in pixels.
interp? Interp Interpolation method (default: Bilinear = 1). Use Interp.Nearest, Interp.Bilinear, or Interp.Bicubic.
Returns

this

this

rotate()
rotate(angle): this;

Rotate in-place. Canvas stays the same size — corners are clipped. Use rotateExpand() to expand the canvas instead.

Parameters
Parameter Type Description
angle number Angle in degrees (counter-clockwise).
Returns

this

this

rotateExpand()
rotateExpand(angle): this;

Rotate and expand the canvas so the full image fits without clipping. Updates width and height.

Parameters
Parameter Type Description
angle number Rotation angle in degrees (counter-clockwise).
Returns

this

this

saturation()
saturation(factor, region?): this;

Adjust color saturation.

Parameters
Parameter Type Description
factor number 0.0 = greyscale, 1.0 = unchanged, > 1.0 = vivid.
region? Rect | RegionOpts -
Returns

this

this

save()
save(path, opts?): this;

Save the image to a file on disk (or to a registered output slot).

Parameters
Parameter Type Description
path string Absolute / relative filesystem path (e.g. "out.png", "result.jpg") OR a //!OUTPUT: slot name in CLI mode.
opts? { format?: "png" | "jpeg" | "webp" | "avif"; lossy?: boolean; quality?: number; } Optional encoder hints. Quality is in [0..100] and applies to lossy encoders (JPEG, lossy WebP, AVIF). lossy flips WebP between lossless (default) and lossy. format ("png"
opts.format? "png" | "jpeg" | "webp" | "avif" -
opts.lossy? boolean -
opts.quality? number -
Returns

this

this for chaining.

Throws

If the write fails.

img.save("out.png");                                       // PNG, lossless
img.save("out.webp");                                      // WebP, lossless (default)
img.save("out.webp", { quality: 82 });                     // WebP, lossy q=82
img.save("out.webp", { lossy: true, quality: 90 });
img.save("out.jpg",  { quality: 95 });                     // JPEG q=95
img.save(OUTPUT, { format: "webp", quality: 82 });         // playground: override UI select
saveTIFF()
saveTIFF(keyOrPath): this;

Save this image as a one-page TIFF. Distinct from save() because TIFF goes through a separate code path (the tiff crate, not the image crate's TIFF feature) so we can share the encoder with AnimationHandle.saveTIFF() and offer multi-page TIFF later from the same call shape.

RGBA8, uncompressed — preserves alpha exactly, no quality loss. Use this when you need a single-page TIFF for a workflow that expects them (scientific imaging, archival, certain printers). For animation-style multi-page TIFFs see AnimationHandle.saveTIFF.

Parameters
Parameter Type Description
keyOrPath string Output slot or filesystem path.
Returns

this

sepia()
sepia(region?): this;

Apply sepia tone (warm brownish tint).

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

setMeta()
setMeta(key, value): this;

Set a top-level metadata key. Value can be any JSON-serialisable type: primitive, array, or nested object. Overwrites whatever was there before.

To update only some fields of a nested object, use mergeMeta or do the JS spread yourself: img.setMeta("exif", { ...img.getMeta("exif"), iso: 200 }).

Parameters
Parameter Type
key string
value unknown
Returns

this

this

Example
img.setMeta("dataset", "ct-batch-1");
img.setMeta("anon", { patientId: "OPAQUE-7F3A" });
setPixel()
setPixel(at, pixel): this;

Write a single pixel. Values are clamped to [0..1].

Parameters
Parameter Type Description
at Px Pixel position, e.g. px(100, 50).
pixel Pixel A Pixel object.
Returns

this

this for chaining.

shadowsHighlights()
shadowsHighlights(opts, region?): this;

Shadow / highlight recovery — tonal adjustment for photo editing.

Separates the image into dark and bright regions using luminance weighting and applies independent lift/suppression to each tonal range:

  • shadows > 0 — lifts dark areas (opens under-exposed shadows).
  • shadows < 0 — crushes shadows (deepens blacks).
  • highlights < 0 — recovers blown highlights (pulls back bright areas).
  • highlights > 0 — brightens already-bright areas.

Both values are additive lifts ∈ [−1..1] weighted by (1 − L)² and respectively, so the midtones are barely touched.

Parameters
Parameter Type Description
opts { highlights?: number; shadows?: number; } -
opts.highlights? number Highlight lift ∈ [−1..1]. Default 0 (no change).
opts.shadows? number Shadow lift ∈ [−1..1]. Default 0 (no change).
region? Rect | RegionOpts -
Returns

this

this

Example
img.shadowsHighlights({ shadows: 0.25, highlights: -0.15 });
sharpen()
sharpen(amount, region?): this;

Unsharp-mask sharpening.

Parameters
Parameter Type Description
amount number Sharpening strength. 1.0 = moderate, > 2.0 = strong.
region? Rect | RegionOpts -
Returns

this

this

sobel()
sobel(region?): this;

Sobel edge detection. Outputs edge magnitudes as greyscale.

Parameters
Parameter Type
region? Rect | RegionOpts
Returns

this

this

solarize()
solarize(threshold, region?): this;

Solarize — invert pixels above threshold (darkroom effect).

Parameters
Parameter Type Description
threshold number Inversion threshold ∈ [0..1].
region? Rect | RegionOpts -
Returns

this

this

stampAt()
stampAt(
   src, 
   dstPoints, 
   factor?, 
   mode?, 
   interp?, 
   border?): this;

Perspective-place src onto this image at four destination corners.

Edge anti-aliasing is automatic. The warp samples src per destination pixel; with the default WarpBorder.Transparent each out-of-bounds bilinear tap contributes transparent, so a tilted quad's silhouette interpolates opaque↔transparent and comes out smooth. Pass border = WarpBorder.Clamp for hard edges (edge- replicate); in that case pre-pad src with a 1-px transparent border (src.pad(1,1,1,1)) if you still want a soft rim.

Parameters
Parameter Type Description
src ImageHandle The image to stamp.
dstPoints [Px, Px, Px, Px] Four canvas-space corners [TL, TR, BR, BL] as Px values.
factor? number Blend weight ∈ [0..1] (default 1.0).
mode? BlendMode Blend mode (default BlendMode.Over).
interp? Interp Interpolation mode (default Bilinear).
border? WarpBorder Out-of-bounds mode (default WarpBorder.Transparent).
Returns

this

this

stampGrid()
stampGrid(
   content, 
   grid, 
   interp?, 
   factor?): this;

Forward complement of warpGrid: project content onto this image through an R×C forward mesh.

Whereas warpGrid treats the nodes as the source UV at each uniform destination grid point (inverse warp — useful for cylindrical/squeeze effects on a single image), stampGrid treats them as the destination position of each uniform source grid point — the intuitive interpretation when you place a grid on a target surface in the editor and want a second image to land inside it. Areas of the base canvas not covered by any mesh cell keep their original pixels.

Internally, each of the (rows-1)×(cols-1) cells is rasterised as a bilinear patch (inverse-bilinear per pixel inside the cell's bbox). Adjacent cells share boundary nodes so they abut without gaps.

Parameters
Parameter Type Default value Description
content ImageHandle undefined Image to stamp onto this canvas.
grid { cols: number; nodes: Record<string, number[]>; rows: number; } undefined WarpGrid object. nodes are normalised to this image's size (x = nodes[r][c*2] * this.width).
grid.cols number undefined -
grid.nodes Record<string, number[]> undefined -
grid.rows number undefined -
interp number 1 0 = nearest-neighbour, 1 = bilinear (default).
factor number 1.0 Global opacity multiplier ∈ [0..1] (default 1).
Returns

this

this

Example
// Project a poster onto a curved monitor in `scene`:
const scene = Engine.loadImage(REFERENCE);
const poster = Engine.loadImage(CONTENT);
scene.stampGrid(poster, { rows: ROWS, cols: COLS, nodes: NODES });
scene.save(OUTPUT);
swirl()
swirl(
   center, 
   radius, 
   angle): this;

Swirl / twirl distortion — pixels rotate around a center point.

Parameters
Parameter Type Description
center Px Center of the swirl in pixel space, e.g. px(img.width/2, img.height/2).
radius number Swirl radius in pixels. Pixels beyond this are unaffected.
angle number Maximum rotation angle in degrees at the center.
Returns

this

this

threshold()
threshold(value, region?): this;

Binary threshold — pixels above value become white, below become black.

Parameters
Parameter Type Description
value number Threshold ∈ [0..1].
region? Rect | RegionOpts -
Returns

this

this

tint()
tint(
   color, 
   strength, 
   region?): this;

Tint the image with a color.

Parameters
Parameter Type Description
color Color -
strength number Blend strength ∈ [0..1].
region? Rect | RegionOpts -
Returns

this

this

toSVG()
toSVG(optsOrKey?): string;

Trace the image to SVG using vtracer.

Parameters
Parameter Type Description
optsOrKey string | SVGOptions Either an SVGOptions config object, or a string output key (writes the SVG to that output slot and also returns it). All options are optional — omitted fields use the defaults from SVGOptions.
Returns

string

unsetMeta()
unsetMeta(key): this;

Delete a metadata key. No-op if the key was already absent. Useful for stripping individual fields before export (e.g. img.unsetMeta("exif.GPSInfo") to drop location).

Parameters
Parameter Type
key string
Returns

this

this

vignette()
vignette(strength, region?): this;

Apply vignette (edge darkening).

Parameters
Parameter Type Description
strength number 0.0 = none, 1.0 = strong dark border.
region? Rect | RegionOpts -
Returns

this

this

warpGrid()
warpGrid(grid, interp?): this;

Apply a Catmull-Rom mesh warp defined by a WarpGrid object.

The grid's sparse nodes map is expanded to a dense flat array before being passed to the Rust engine. Rows absent from nodes are filled with their identity (evenly-spaced) UV positions.

Parameters
Parameter Type Default value Description
grid { border?: WarpBorder; cols: number; nodes: Record<string, number[]>; rows: number; } undefined WarpGrid object (e.g. the WARPGRID global injected from the @warpgrid script block).
grid.border? WarpBorder undefined -
grid.cols number undefined -
grid.nodes Record<string, number[]> undefined -
grid.rows number undefined -
interp number 1 0 = nearest-neighbour, 1 = bilinear (default).
Returns

this

this

warpPerspective()
warpPerspective(
   dw, 
   dh, 
   matrix, 
   interp?, 
   border?): this;

Perspective (homography) warp. Updates width and height.

The transform is src→dst (forward): for each source pixel it says where that pixel lands in the destination grid.

matrix accepts either:

  • a Mat3 instance — the recommended path. Build one with Matrix.Mat3.estimateSimilarity/Affine/Homography(...), or any gl-matrix construction. It is column-major; this wrapper transposes it to the engine's row-major layout for you.
  • a raw 9-element number[] — treated as row-major [a,b,c, d,e,f, g,h,i] and passed straight through.

Out-of-bounds edges are anti-aliased by default: WarpBorder.Transparent lets each bilinear tap that lands outside the source contribute transparent, so a tilted quad's silhouette interpolates opaque↔transparent instead of staircasing. Pass WarpBorder.Clamp to replicate the edge texel instead (hard edges).

Parameters
Parameter Type Description
dw number Output width in pixels.
dh number Output height in pixels.
matrix number[] | Mat3 Mat3 or row-major number[9], src→dst forward.
interp? Interp Interpolation method (default: Bilinear = 1).
border? WarpBorder Out-of-bounds mode (default: WarpBorder.Transparent).
Returns

this

this

warpPolar()
warpPolar(innerR?, outSize?): this;

Polar coordinate warp — maps the image onto a ring/donut shape. The image's X axis maps to angle (0°→360°) and Y axis maps to radius. Creates a "film roll" or "planet" effect. Updates width and height.

Parameters
Parameter Type Description
innerR? number Inner ring radius as fraction of outer radius ∈ [0..1]. Default: 0.3.
outSize? number Output image side length in pixels. 0 = auto (max of input dims).
Returns

this

this

wave()
wave(
   amplitudeX, 
   amplitudeY, 
   freqX, 
   freqY): this;

Sinusoidal wave distortion.

Parameters
Parameter Type Description
amplitudeX number Horizontal wave amplitude in pixels.
amplitudeY number Vertical wave amplitude in pixels.
freqX number Horizontal wave frequency (cycles per image width).
freqY number Vertical wave frequency (cycles per image height).
Returns

this

this