imagine.filters
import imagine
imagineexposes this asimagine.filters, soimport imagineis enough and the names are called asimagine.filters.*.import imagine.filtersreaches 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