Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

imagine.filters

import imagine

imagine exposes this as imagine.filters, so import imagine is enough and the names are called as imagine.filters.*. import imagine.filters reaches the same definitions directly.

The maths behind the filters: colour matrices, lookup tables and convolution kernels.

Image exposes these as named methods, and this is where the numbers those methods pass come from. Building a matrix, a LUT or a kernel here and applying it yourself is how to get a filter the module does not already name.

Constants

LUMA

imagine.filters.LUMA: list = [...]

Rec. 601 luma weights.

These are what “grayscale” means to an image editor, and what [[imagine.Color.to_grayscale]] uses, so a grey produced by Image.grayscale() and one produced by Color.to_grayscale() agree. They are deliberately not the WCAG linear-light weights that [[colors.relative_luminance]] uses; those answer a different question, about contrast rather than appearance.

MATRIX_LUMA

imagine.filters.MATRIX_LUMA: list = [...]

The luma weights the colour-matrix filters use, from the SVG and CSS filter specifications.

Saturation and hue rotation are defined against these, so a saturate() here matches what a browser does to the same image.

Functions

identity_matrix()

imagine.filters.identity_matrix() -> list

The identity colour matrix: applying it changes nothing.

A useful starting point for building one by hand.

Returns list

grayscale_matrix()

imagine.filters.grayscale_matrix() -> list

A colour matrix that collapses every colour to its grey of equal perceived brightness.

Returns list

sepia_matrix()

imagine.filters.sepia_matrix() -> list

A colour matrix approximating the warm brown cast of a sepia photograph.

The coefficients are the widely used Microsoft ones, which are what most software means by “sepia”.

Returns list

saturation_matrix()

imagine.filters.saturation_matrix(amount: number) -> list

A colour matrix that scales saturation.

An amount of 0 removes all colour, 1 leaves the image alone, and values above 1 push saturation past its original level. Amounts below 0 pass through the grey point and out the other side, which inverts hues; that is well defined but rarely what anyone wants.

Parameters

  • amount (number)

Returns list

hue_rotate_matrix()

imagine.filters.hue_rotate_matrix(degrees: number) -> list

A colour matrix that rotates every hue around the colour wheel by an angle in degrees, leaving brightness and saturation alone.

This is the rotation from the SVG filter specification, which approximates a true rotation in a luma-preserving space closely enough that the difference is not visible.

Parameters

  • degrees (number) — Positive rotates toward red, negative away from it.

Returns list

duotone_matrix()

imagine.filters.duotone_matrix(shadow, highlight) -> list

A colour matrix that replaces every pixel’s colour with a blend between two colours chosen by its brightness, a duotone.

Dark pixels take shadow, light ones take highlight, and everything between is interpolated. Alpha is untouched.

Parameters

  • shadow (Color|string|number) — The colour black maps to.
  • highlight (Color|string|number) — The colour white maps to.

Returns list

combine_matrices()

imagine.filters.combine_matrices(first: list, second: list) -> list

Multiplies two colour matrices, giving one matrix with the effect of applying first and then second.

Combining matrices this way and applying the result once is both faster and more accurate than applying each in turn, because the intermediate result is never rounded back to 8 bits.

Parameters

  • first (list)
  • second (list)

Returns list

build_lut()

imagine.filters.build_lut(fn: function) -> bytes

Builds a 256-entry lookup table from a function.

The function is called once per possible input value, 0 through 255, and whatever it returns is clamped to a byte. This is the general way to write a tone curve: build the table once, and the image is then rewritten at memory speed no matter how large it is.

import imagine { filters }

# A steep S-curve, for contrast that keeps its highlights.
var curve = filters.build_lut(@(value) {
  var t = value / 255
  return 255 * t * t * (3 - 2 * t)
})

Parameters

  • fn (function(1)) — Called with an input value, returns the output.

Returns bytes

identity_lut()

imagine.filters.identity_lut() -> bytes

A lookup table that leaves every value alone.

Returns bytes

brightness_lut()

imagine.filters.brightness_lut(delta: number) -> bytes

A lookup table that adds a fixed amount to every value.

Parameters

  • delta (number) — -255 to 255. Positive brightens.

Returns bytes

contrast_lut()

imagine.filters.contrast_lut(amount: number) -> bytes

A lookup table that pushes values away from or toward mid-grey.

The amount runs -100 (everything collapses to grey) through 0 (no change) to 100 (everything is forced to black or white). This is the contrast curve most image editors use.

Parameters

  • amount (number) — -100 to 100.

Returns bytes

gamma_lut()

imagine.filters.gamma_lut(gamma: number) -> bytes

A lookup table applying a gamma curve.

Values below 1 darken the midtones and values above 1 lighten them, while black and white stay put. Correcting an image encoded at one gamma for display at another is the usual reason to reach for this.

Parameters

  • gamma (number) — Greater than zero.

Returns bytes

invert_lut()

imagine.filters.invert_lut() -> bytes

A lookup table that inverts every value.

Returns bytes

threshold_lut()

imagine.filters.threshold_lut(level: number) -> bytes

A lookup table that forces every value to black or white.

Parameters

  • level (number) — Values below this become 0, the rest become 255.

Returns bytes

posterize_lut()

imagine.filters.posterize_lut(levels: number) -> bytes

A lookup table that reduces each channel to a fixed number of evenly spaced steps.

Parameters

  • levels (number) — 2 or more. Two gives a hard black and white split.

Returns bytes

scale_lut()

imagine.filters.scale_lut(factor: number) -> bytes

A lookup table that scales every value by a factor.

Applied to the alpha channel, this is what Image.opacity() does.

Parameters

  • factor (number) — 0 to 1, though larger values are allowed and clamp.

Returns bytes

levels_lut()

imagine.filters.levels_lut(black: number, white: number, gamma: ?number) -> bytes

A lookup table implementing a levels adjustment.

Everything at or below black becomes 0, everything at or above white becomes 255, and the range between is stretched to fill the whole scale with gamma applied along the way. This is the single most useful correction for a flat or washed-out photograph.

Parameters

  • black (number) — The input value that becomes black, 0-255.
  • white (number) — The input value that becomes white, 0-255.
  • gamma (?number) — The midtone curve - Default: 1 (linear).

Returns bytes

sharpen_kernel()

imagine.filters.sharpen_kernel(strength) -> list

A 3x3 sharpening kernel.

The strength is how much the centre pixel is emphasised over its neighbours; 1 is a moderate sharpen and values much above 3 start producing halos around edges.

Parameters

  • strength (?number) — Default: 1.

Returns list

box_blur_kernel()

imagine.filters.box_blur_kernel() -> list

A 3x3 box blur kernel; every neighbour counts equally.

Cheaper than a Gaussian and visibly boxier. Image.blur() uses a real Gaussian instead; this is here for the cases that want the harder look, or a single very cheap pass.

Returns list

emboss_kernel()

imagine.filters.emboss_kernel() -> list

A 3x3 kernel that lifts edges into a grey relief.

Used with an offset of 128, so flat areas come out mid-grey rather than black; Image.emboss() supplies that offset.

Returns list

edge_kernel()

imagine.filters.edge_kernel() -> list

A 3x3 Laplacian kernel that leaves only the edges.

Its weights sum to zero, so it needs an explicit divisor of 1 rather than the usual “divide by the sum”.

Returns list

mean_removal_kernel()

imagine.filters.mean_removal_kernel() -> list

A 3x3 kernel that removes local mean, exaggerating detail.

Returns list

smooth_kernel()

imagine.filters.smooth_kernel(weight) -> list

A 3x3 smoothing kernel weighted toward the centre pixel.

A larger weight keeps more of the original and smooths less.

Parameters

  • weight (?number) — The centre weight - Default: 8.

Returns list

gaussian_kernel()

imagine.filters.gaussian_kernel(sigma: number) -> list

A square Gaussian kernel with the given standard deviation.

Image.blur() uses a separable Gaussian instead, which is far faster for anything but the smallest radius; this exists for code that wants the kernel itself, to combine with another.

Parameters

  • sigma (number) — Greater than zero.

Returns list


2026, Richard Ore and Zuri contributors