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

import imagine

Reading, writing, drawing and transforming raster images.

imagine covers the whole path an image takes through a program: decoding it from a file or an upload, resizing and cropping it, adjusting its colour, drawing shapes and text onto it, compositing several together, and writing the result back out in whatever format suits.

import imagine { Image, Font, LANCZOS }

Image.open('photo.jpg')
  .thumbnail(600, 600, LANCZOS)
  .sharpen(0.6)
  .save('thumb.webp', { quality: 82 })

The shape of the API

Almost everything is a method on [[imagine.Image]], and almost everything returns an image, so operations chain. There is one rule worth learning up front:

  • Operations that change the image’s size return a new image. resize(), crop(), rotate(), flip() and pad() leave the original alone.
  • Everything else changes the image in place. Drawing, filters and compositing modify the image you called them on and hand it back for chaining.

Call clone() when you want to keep an image before filtering it.

Colours

Anywhere a colour is expected you can write a [[imagine.Color]], a hexadecimal string, a CSS colour name, a packed 0xRRGGBBAA number, or a list of channels. These are all the same red:

image.fill(Color(255, 0, 0))
image.fill('#ff0000')
image.fill('red')
image.fill(0xFF0000FF)
image.fill([255, 0, 0])

Alpha runs 0 (transparent) to 255 (opaque), as in CSS and PNG. The colour space conversions come from [[colors]], so hue is in degrees and saturation and lightness are in percentage points.

Pixels

An image is 8-bit RGBA with straight (not premultiplied) alpha, laid out row by row with no padding, so pixel (x, y) begins at byte (y * width + x) * 4. [[imagine.Canvas.pixels]] hands back that buffer live, which is the fastest way to write an operation this module does not provide:

var buffer = image.pixels()
var total = buffer.length()

iter var at = 0; at < total; at += 4 {
  buffer[at] = 255 - buffer[at]
}

Formats

Read: PNG, JPEG, GIF, BMP, TIFF, TGA, WebP, QOI, ICO, PNM, WBMP. Write: all of those plus AVIF.

AVIF is write-only, and TGA carries no signature of its own so it can only be identified by its file extension or by naming the format outright. [[imagine.capabilities]] reports what this build can actually do, so a program can check rather than guess.

Animated GIF and animated WebP are read through [[imagine.Animation]], and animated GIF can be written.

Drawing

Every filled shape becomes a polygon and goes through one anti-aliased scanline rasterizer, and every outline becomes the polygon around its stroke and goes through the same one. Shapes this module does not name can be drawn by handing [[imagine.Canvas.fill_polygon]] the points.

import imagine { Image, Color }

Image(300, 200, 'white')
  .fill_rounded_rect(20, 20, 260, 160, 16, '#4f46e5')
  .circle(150, 100, 50, 'white', { thickness: 4 })
  .save('card.png')

Text

Text needs a font, loaded from a file with [[imagine.Font.load]] or found on the machine with [[imagine.Font.system]]. Glyphs are placed by advance width with kerning; complex scripts that need shaping are not supported, and the Font documentation says exactly what that rules out.

Memory

Four bytes per pixel, so a 6000x4000 photograph occupies 96 MB however small its file was. For images whose size you do not control, [[imagine.probe]] reads the dimensions out of the header without decoding anything.

var header = imagine.probe(upload)

if header == nil or header.width * header.height > 40000000 {
  raise Exception('image is missing or too large')
}

The imagine API

Every public name in imagine, wherever it is declared. Each links to the page that documents it.

NameKindSummary
imagine.ALIGN_CENTERconstantLines of a multi-line string are centred against each other.
imagine.ALIGN_LEFTconstantLines of a multi-line string start at the same left edge.
imagine.ALIGN_RIGHTconstantLines of a multi-line string end at the same right edge.
imagine.AVIFconstantAVIF.
imagine.AnimationclassA sequence of images with a delay between each, read from or written to an animated format.
imagine.BICUBICconstantBicubic (Catmull-Rom).
imagine.BILINEARconstantBilinear.
imagine.BLACKconstantOpaque black.
imagine.BLEND_ADDconstantAdds the channels, clamped at white.
imagine.BLEND_COLOR_BURNconstantDarkens the backdrop toward the source.
imagine.BLEND_COLOR_DODGEconstantBrightens the backdrop toward the source.
imagine.BLEND_DARKENconstantKeeps whichever channel is darker.
imagine.BLEND_DIFFERENCEconstantThe absolute difference between the two colours.
imagine.BLEND_EXCLUSIONconstantLike difference, but lower contrast in the midtones.
imagine.BLEND_HARD_LIGHTconstantOverlay with the roles of source and backdrop swapped.
imagine.BLEND_LIGHTENconstantKeeps whichever channel is lighter.
imagine.BLEND_MULTIPLYconstantMultiplies the two colours.
imagine.BLEND_NORMALconstantOrdinary alpha compositing: the source is painted over the destination according to its alpha.
imagine.BLEND_OVERLAYconstantMultiply where the backdrop is dark, screen where it is light.
imagine.BLEND_SCREENconstantThe inverse of multiply.
imagine.BLEND_SOFT_LIGHTconstantA gentler hard light, as if the source were a diffuse spotlight.
imagine.BLEND_SUBTRACTconstantSubtracts the source from the backdrop, clamped at black.
imagine.BLUEconstantOpaque pure blue.
imagine.BMPconstantBMP.
imagine.BOTTOMconstant
imagine.BOTTOM_LEFTconstant
imagine.BOTTOM_RIGHTconstant
imagine.BoundsErrorclassRaised when a rectangle, crop or resize falls outside the image, or when a dimension is zero or negative.
imagine.CAP_BUTTconstantThe stroke stops dead at its endpoint.
imagine.CAP_ROUNDconstantThe stroke ends in a half-disc, so it reaches half its width past the endpoint.
imagine.CAP_SQUAREconstantThe stroke ends in a square, so it reaches half its width past the endpoint, the same distance a round cap…
imagine.CENTERconstant
imagine.CYANconstantOpaque cyan.
imagine.CanvasclassA mutable RGBA pixel surface and everything that draws onto one.
imagine.ColorclassAn 8-bit RGBA colour.
imagine.DecodeErrorclassRaised when image data cannot be read: the bytes are not an image at all, the format is one this build cannot…
imagine.EDGE_CLAMPconstantPixels off the edge take the value of the nearest edge pixel.
imagine.EDGE_TRANSPARENTconstantPixels off the edge are treated as transparent black.
imagine.EDGE_WRAPconstantPixels off the edge wrap to the opposite side.
imagine.EncodeErrorclassRaised when an image cannot be written in the requested format, either because this build has no encoder for…
imagine.FLIP_BOTHconstantMirror both ways at once, which is the same as rotating 180 degrees.
imagine.FLIP_HORIZONTALconstantMirror left to right.
imagine.FLIP_VERTICALconstantMirror top to bottom.
imagine.FontclassA typeface at a particular size, ready to draw with.
imagine.FontErrorclassRaised when a font cannot be parsed, cannot be found on the system, or does not carry the horizontal metrics…
imagine.FormatErrorclassRaised when a format name is not one imagine knows, or when a file extension cannot be mapped to a format.
imagine.GAUSSIANconstantGaussian.
imagine.GIFconstantGIF.
imagine.GRAYconstantOpaque mid grey.
imagine.GREENconstantOpaque pure green.
imagine.ICOconstantWindows ICO.
imagine.ImageclassA raster image: a rectangle of 8-bit RGBA pixels, everything that draws onto one, and everything that…
imagine.ImageErrorclassBase class for every error the imagine module raises.
imagine.JPEGconstantJPEG.
imagine.LANCZOSconstantLanczos with a 3-lobe window.
imagine.LEFTconstant
imagine.MAGENTAconstantOpaque magenta.
imagine.NEARESTconstantNearest-neighbour.
imagine.PNGconstantPNG.
imagine.PNMconstantNetpbm (PBM, PGM, PPM).
imagine.QOIconstantQOI, the Quite OK Image format.
imagine.REDconstantOpaque pure red.
imagine.RIGHTconstant
imagine.StrokeFontclassThe built-in font: a sans-serif drawn from centre-line strokes rather than loaded from a file.
imagine.TGAconstantTruevision TGA.
imagine.TIFFconstantTIFF.
imagine.TOPconstant
imagine.TOP_LEFTconstantWhere a smaller image or a piece of text sits inside a larger box, used by Image.cover(), Image.contain()…
imagine.TOP_RIGHTconstant
imagine.TRANSPARENTconstant
imagine.WBMPconstantWireless Bitmap.
imagine.WEBPconstantWebP.
imagine.WHITEconstantOpaque white.
imagine.YELLOWconstantOpaque yellow.
imagine.capabilitiesfunctionWhat this build can do, as a dictionary holding decode, encode and animated, each a list of format…
imagine.createfunctionCreates a new image.
imagine.decodefunctionDecodes image data held in memory.
imagine.detectfunctionIdentifies image data by its contents, returning a format name or nil.
imagine.filters.LUMAconstantRec.
imagine.filters.MATRIX_LUMAconstantThe luma weights the colour-matrix filters use, from the SVG and CSS filter specifications.
imagine.filters.box_blur_kernelfunctionA 3x3 box blur kernel; every neighbour counts equally.
imagine.filters.brightness_lutfunctionA lookup table that adds a fixed amount to every value.
imagine.filters.build_lutfunctionBuilds a 256-entry lookup table from a function.
imagine.filters.combine_matricesfunctionMultiplies two colour matrices, giving one matrix with the effect of applying first and then second.
imagine.filters.contrast_lutfunctionA lookup table that pushes values away from or toward mid-grey.
imagine.filters.duotone_matrixfunctionA colour matrix that replaces every pixel’s colour with a blend between two colours chosen by its brightness,…
imagine.filters.edge_kernelfunctionA 3x3 Laplacian kernel that leaves only the edges.
imagine.filters.emboss_kernelfunctionA 3x3 kernel that lifts edges into a grey relief.
imagine.filters.gamma_lutfunctionA lookup table applying a gamma curve.
imagine.filters.gaussian_kernelfunctionA square Gaussian kernel with the given standard deviation.
imagine.filters.grayscale_matrixfunctionA colour matrix that collapses every colour to its grey of equal perceived brightness.
imagine.filters.hue_rotate_matrixfunctionA colour matrix that rotates every hue around the colour wheel by an angle in degrees, leaving brightness and…
imagine.filters.identity_lutfunctionA lookup table that leaves every value alone.
imagine.filters.identity_matrixfunctionThe identity colour matrix: applying it changes nothing.
imagine.filters.invert_lutfunctionA lookup table that inverts every value.
imagine.filters.levels_lutfunctionA lookup table implementing a levels adjustment.
imagine.filters.mean_removal_kernelfunctionA 3x3 kernel that removes local mean, exaggerating detail.
imagine.filters.posterize_lutfunctionA lookup table that reduces each channel to a fixed number of evenly spaced steps.
imagine.filters.saturation_matrixfunctionA colour matrix that scales saturation.
imagine.filters.scale_lutfunctionA lookup table that scales every value by a factor.
imagine.filters.sepia_matrixfunctionA colour matrix approximating the warm brown cast of a sepia photograph.
imagine.filters.sharpen_kernelfunctionA 3x3 sharpening kernel.
imagine.filters.smooth_kernelfunctionA 3x3 smoothing kernel weighted toward the centre pixel.
imagine.filters.threshold_lutfunctionA lookup table that forces every value to black or white.
imagine.formats.animatablefunctionEvery format this build can read as an animation.
imagine.formats.decode_wbmpfunctionDecodes a WBMP into straight RGBA pixels.
imagine.formats.detectfunctionIdentifies image data by its content rather than its name, or returns nil when the bytes are not a…
imagine.formats.encode_wbmpfunctionEncodes straight RGBA pixels as a WBMP.
imagine.formats.extension_forfunctionThe file extension a format is normally written with, without a leading dot.
imagine.formats.from_extensionfunctionThe format name a file extension implies, or nil when the extension is not one this module knows.
imagine.formats.mime_forfunctionThe IANA media type for a format, suitable for a Content-Type header.
imagine.formats.normalizefunctionNormalises a format name, accepting the common aliases.
imagine.formats.probefunctionReads an image’s format and dimensions without decoding its pixels.
imagine.formats.readablefunctionEvery format this build can read.
imagine.formats.writablefunctionEvery format this build can write.
imagine.openfunctionOpens an image file.
imagine.probefunctionReads an image’s format and dimensions from its header, without decoding any pixels.
imagine.strokefont.ASCENDERconstantHow far the tallest glyphs rise above the baseline.
imagine.strokefont.CAP_HEIGHTconstantThe height of a capital letter.
imagine.strokefont.DESCENDERconstantHow far descenders fall below the baseline, as a negative number.
imagine.strokefont.EMconstantThe em square’s height in design units.
imagine.strokefont.GLYPHSconstantEvery glyph, keyed by character.
imagine.strokefont.NOTDEFconstantWhat an unmapped character draws: an empty box, the same convention a font uses for a glyph it does not have.
imagine.strokefont.WEIGHTconstantThe default stroke width in design units, a little under a tenth of the em, which is the usual weight for a…
imagine.strokefont.X_HEIGHTconstantThe height of a lowercase letter with no ascender.

Submodules

ModuleReached asSummary
imagine.animationimagine.animation.*Animation: an ordered set of frames with per-frame delays, which is what an animated GIF or WebP decodes to…
imagine.canvasimagine.canvas.*Canvas: the drawing surface.
imagine.colorimagine.*Color: one RGBA colour, and the conversions between the ways of naming one.
imagine.constantsimagine.*Every named constant the module takes as an argument: resampling filters, blend modes, line caps, edge…
imagine.errorsimagine.*Every error the module raises, under ImageError as their root.
imagine.filtersimagine.filters.*The maths behind the filters: colour matrices, lookup tables and convolution kernels.
imagine.fontimagine.font.*Font: a loaded TrueType or OpenType face, ready to measure and draw text with.
imagine.formatsimagine.formats.*What the build can actually read and write, and how to tell one format from another.
imagine.imageimagine.image.*Image: a raster image as an RGBA pixel buffer, and everything that transforms one.
imagine.strokefontimagine.strokefont.*StrokeFont: the font built into the module, defined as stroke geometry rather than glyph outlines.

Functions

open()

imagine.open(source, options) -> Image

Opens an image file.

A shorthand for [[imagine.Image.open]].

Parameters

  • source (string|file)
  • options (?dict)

Returns Image

decode()

imagine.decode(data, options) -> Image

Decodes image data held in memory.

A shorthand for [[imagine.Image.decode]].

Parameters

  • data (bytes)
  • options (?dict)

Returns Image

create()

imagine.create(width, height, fill) -> Image

Creates a new image.

A shorthand for the [[imagine.Image]] constructor.

Parameters

  • width (number)
  • height (number)
  • fill (?Color|string|number)

Returns Image

probe()

imagine.probe(data) -> ?dict

Reads an image’s format and dimensions from its header, without decoding any pixels.

Returns {format, width, height}, or nil when the data is not a recognisable image. Reading a large JPEG’s header costs microseconds where decoding it costs tens of milliseconds, which makes this the right way to size up an upload before committing to it.

Parameters

  • data (bytes)

Returns ?dict

detect()

imagine.detect(data) -> ?string

Identifies image data by its contents, returning a format name or nil.

Parameters

  • data (bytes)

Returns ?string

capabilities()

imagine.capabilities() -> dict

What this build can do, as a dictionary holding decode, encode and animated, each a list of format names.

Worth checking rather than assuming: AVIF appears under encode but not decode, and which formats are compiled in can differ between builds.

Returns dict


2021, Richard Ore and Zuri contributors