lights FAQ Forum
This package

Portable 2D Graphics


Cairo graphics engine

local cairo = require'cairo'

A lightweight ffi binding of the cairo graphics library.


NOTE: In the table below, foo(val) /-> val is a shortcut for saying that foo(val) sets the value of foo and foo() -> val gets it.

NOTE: flags can be passed as lowercase strings without prefix eg. pass ‘argb32’ for C.CAIRO_FORMAT_ARGB32 in cairo.image_surface().

pixman surfaces
cairo.image_surface(fmt, w, h) -> sr create a pixman surface
cairo.image_surface(bmp) -> sr create a pixman surface given a bitmap (+)
sr:bitmap() -> bmp get the image surface as a bitmap
sr:data() -> data get the image surface pixel buffer
sr:format() -> fmt get the image surface format
sr:bitmap_format() -> fmt get the image surface bitmap format
sr:width() -> w get the image surface width
sr:height() -> h get the image surface height
sr:stride() -> stride get the image surface stride
sr:bpp() -> bpp get the image surface bits-per-pixel
recording surfaces
cairo.recording_surface(content[, x, y, w, h]) -> sr create a recording surface
sr:ink_extents() -> x, y, w, h get recording surface ink extents
sr:recording_extents() -> x, y, w, h | nil get recording surface extents
PDF surfaces
cairo.pdf_surface(filename, w, h) -> sr create a PDF surface for a filename
cairo.pdf_surface(write_func, arg, w, h) -> sr create a PDF surface with a write function
cairo.pdf_versions() -> {ver1, ...} get available spec versions
sr:pdf_version(ver) restrict to spec version
sr:pdf_size(w, h) set page size
PS surfaces
cairo.ps_surface(filename, w, h) -> sr create a PS surface for a filename
cairo.ps_surface(write_func, arg, w, h) -> sr create a PS surface with a write function
cairo.ps_levels() -> {level1, ...} get available levels
sr:ps_level(level) restrict to level
sr:ps_eps(t|f) /-> t|f get/set Encapsulated PostScript
sr:ps_size(w, h) set page size
sr:ps_dsc_comment(s) add comment
sr:ps_dsc_begin_setup() comments go to Setup section
sr:ps_dsc_begin_page_setup() comments go to PageSetup section
SVG surfaces
cairo.svg_surface(filename, w, h) -> sr create a SVG surface for a filename
cairo.svg_surface(write_func, arg, w, h) -> sr create a SVG surface with a write function
cairo.svg_versions() -> {ver1, ...} get available spec versions
sr:svg_version(ver) restrict to spec version
PNG support
cairo.load_png(filename) -> sr create a pixman surface from a png file
cairo.load_png(read_func, arg) -> sr create a pixman surface from a png stream
sr:save_png(filename) -> true | nil,err,status write surface to png file
sr:save_png(write_func, arg) -> true | nil,err,status write surface to png stream
all surfaces
sr:sub(x, y, w, h) -> sr create a sub-surface
sr:similar_surface(content, w, h) -> sr create a similar surface
sr:similar_image_surface(fmt, w, h) -> sr create a similar image surface
sr:type() -> type get surface type
sr:content() -> content get surface content type
sr:flush() perform any pending drawing commands
sr:mark_dirty([x, y, w, h]) re-read any cached areas of (parts of) the surface
sr:fallback_resolution(xppi, yppi) /-> xppi, yppi get/set fallback resolution
sr:mime_data(type, data, len[, destroy[, arg]]) set mime data
sr:mime_data(type) -> data, len get mime data
sr:supports_mime_type(type) -> t|f check if the surface supports a mime type
sr:map_to_image([x, y, w, h]) -> image_sr get an image surface for modifying the backing store
sr:unmap_image(image_sr) upload image to backing store and unmap
sr:finish() finish the surface
sr:apply_alpha(a) make the surface transparent
drawing contexts
sr:context() -> cr create a drawing context on a surface
cr:save() push context state to stack
cr:restore() pop context state from stack
cr:rgb(r, g, b) set a RGB color as source
cr:rgba(r, g, b, a) set a RGBA color as source
cr:source(patt | sr, [x, y]) /-> patt get/set a pattern or surface as source
cr:operator(operator) /-> operator get/set the compositing operator
cr:mask(patt | sr[, x, y]) draw using a pattern’s (or surface’s) alpha as mask
cr:paint() paint the current source
cr:paint_with_alpha(alpha) paint the current source with transparency
cr:push_group([content]) redirect drawing to an intermediate surface
cr:pop_group() -> patt terminate the redirection and return it as pattern
cr:pop_group_to_source() terminate the redirection and install it as pattern
cr:target() -> sr get the ultimate destination surface
cr:group_target() -> sr get the current destination surface
cr:translate(x, y) -> cr translate the user-space origin
cr:scale(sx[, sy]) -> cr scale the user-space
cr:scale_around(cx, cy, sx[, sy]) -> cr scale the user-space arount a point
cr:rotate(angle) -> cr rotate the user-space
cr:rotate_around(cx, cy, angle) -> cr rotate the user-space around a point
cr:skew(ax, ay) -> cr skew the user-space
cr:transform(mt) -> cr transform the user-space
cr:safe_transform(mt) -> cr transform the user-space if the matrix is invertible
cr:matrix(mt[, out_mt]) /-> mt get/set the CTM
cr:identity_matrix() -> cr reset the CTM
cr:user_to_device(x, y) -> x, y user to device (point)
cr:user_to_device_distance(x, y) -> x, y user to device (distance)
cr:device_to_user(x, y) -> x, y device to user (point)
cr:device_to_user_distance(x, y) -> x, y device to user (distance)
cr:new_path() clear the current path
cr:new_sub_path() create a sub-path
cr:move_to(x, y) move the current point
cr:line_to(x, y) add a line to the current path
cr:curve_to(x1, y1, x2, y2, x3, y3) add a cubic bezier to the current path
cr:quad_curve_to(x1, y1, x2, y2) add a quad bezier to the current path
cr:arc(cx, cy, r, a1, a2) add an arc to the current path
cr:arc_negative(cx, cy, r, a1, a2) add a negative arc to the current path
cr:circle(cx, cy, r) add a circle to the current path
cr:ellipse(cx, cy, rx, ry, rotation) add an ellipse to the current path
cr:elliptic_arc(cx, cy, rx, ry, rotation, a1, a2) add an elliptic arc to the current path
cr:elliptic_arc_negative(cx, cy, rx, ry, rotation, a1, a2) add a negative elliptic arc to the current path
cr:rel_move_to(x, y) move the current point
cr:rel_line_to(x, y) add a line to the current path
cr:rel_curve_to(x1, y1, x2, y2, x3, y3) add a cubic bezier to the current path
cr:rel_quad_curve_to(x1, y1, x2, y2) add a quad bezier to the current path
cr:rectangle(x, y, w, h) add a rectangle to the current path
cr:close_path() close current path
cr:copy_path() -> path copy current path to a path object
cr:copy_path_flat() -> path copy current path flattened
path:dump() pretty print path instructions
path:equal(other_path) -> t|f compare paths
cr:append_path(path) append a path to current path
cr:path_extents() -> x1, y1, x2, y2 get the bouding box of the current path
cr:current_point() -> x, y get the current point
cr:has_current_point() -> t|f check if there’s a current point
cr:fill() fill the current path and discard it
cr:fill_preserve() fill and keep the path
cr:fill_extents() -> x1, y1, x2, y2 get the bounding box of filling the current path
cr:in_fill(x, y) -> t|f hit-test the fill area
cr:fill_rule(rule]) /-> rule get/set the fill rule
cr:stroke() stroke the current path and discard it
cr:stroke_preserve() stroke and keep the path
cr:stroke_extents() -> x1, y1, x2, y2 get the bounding box of stroking the current path
cr:in_stroke(x, y) -> t|f hit-test the stroke area
cr:line_width(width]) /-> width get/set the line width
cr:line_cap(cap) /-> cap get/set the line cap
cr:line_join(join) /-> join get/set the line join
cr:miter_limit(limit) /-> limit get/set the miter limit
cr:dash(dashes:table, [offset]) set the dash pattern for stroking
cr:dash(dashes:double*, dash_count, [offset]) set the dash pattern for stroking
cr:dash() -> dashes, dash_count get the dash pattern for stroking
cr:dash'#' -> n get the dash count
cr:dash(nil, dashes:double*) -> dash_count get the dash pattern for stroking
rasterization options
cr:tolerance(tolerance]) /-> tolerance get/set tolerance
cr:antialias(antialias]) /-> antialias get/set the antialiasing mode
cr:clip() intersect the current path to the current clipping region and discard the path
cr:clip_preserve() clip and keep the current path
cr:reset_clip() remove all clipping
cr:clip_extents() -> x1, y1, x2, y2 get the clip extents
cr:in_clip(x, y) -> t|f hit-test the clip area
cr:clip_rectangles() -> rlist get the clipping rectangles
solid-color patterns
cairo.color_pattern(r, g, b[, a]) -> patt create a solid color pattern
patt:color() -> r, g, b, a get the color of a solid color pattern
gradient patterns
cairo.linear_gradient(x0, y0, x1, y1) -> patt create a linear gradient
cairo.radial_gradient(cx0, cy0, r0, cx1, cy1, r1) -> patt create a radial gradient
patt:linear_points() -> x0, y0, x1, y1 get the endpoints of a linear gradient
patt:radial_circles() -> cx0, cy0, r0, cx1, cy1, r1 get the circles of a radial gradient
patt:add_color_stop(offset, r, g, b[, a]) add a RGB(A) color stop
patt:color_stop'#' -> n get the number of color stops
patt:color_stop(i) -> offset, r, g, b, a get a color stop
surface patterns
cairo.surface_pattern(sr) -> patt create a surface-type pattern
patt:surface() -> sr | nil get the pattern’s surface
raster-source patterns
cairo.raster_source_pattern(data, content, w, h) -> patt create a raster source-type pattern
patt:callback_data(data) /-> data get/set callback data
patt:acquire_function(func) /-> func get/set the acquire function
patt:snapshot_function(func) /-> func get/set the snapshot function
patt:copy_function(func) /-> func get/set the copy function
patt:finish_function(func) /-> func get/set the finish function
mesh patterns
cairo.mesh_pattern() -> patt create a mesh pattern
patt:begin_patch() start a new patch
patt:end_patch() end current patch
patt:move_to(x, y) move the current point
patt:line_to(x, y) add a line
patt:curve_to(x1, y1, x2, y2, x3, y3) add a cubic bezier
patt:control_point(point_num, x, y) set a control point of the current patch
patt:control_point(patch_num, point_num) -> x, y get a control point
patt:corner_color(corner_num, r, g, b[, a]) set a corner color of the current patch
patt:corner_color(patch_num, corner_num) -> r, g, b, a get a corner color
all patterns
patt:type() -> type get the pattern type
patt:matrix(mt) /-> mt get/set the matrix
patt:extend(extend) /-> extend get/set the extend
patt:filter(filter) /-> filter get/set the filter
drawing text
cr:font_face(face) /-> face get/set the font face
cr:font_size(size) set the font size
cr:font_matrix(mt) /-> mt get/set the font matrix
cr:scaled_font(sfont) /-> sfont get/set the scaled font
cr:font_extents() -> cairo_font_extents_t get the font extents of the current font
sr:font_options() -> fopt get the default font options
cr:font_options(fopt) /-> fopt get/set custom font options
drawing text (toy API)
cr:font_face(family[, slant[, weight]]) select a font face
cr:show_text(s) show text
cr:text_path(s) add closed paths for text to the current path
cr:text_extents(s) -> cairo_text_extents_t get text extents
drawing glyphs
cairo.allocate_glyphs(count) -> cairo_glyph_t* allocate an array of glyphs
cr:show_glyphs(glyphs, #glyphs) draw glyphs
cr:glyph_path(glyphs, #glyphs) add paths for the glyphs to the current path
cr:glyph_extents(glyphs, #glyphs) -> cairo_text_extents_t get the text extents of an array of glyphs
text cluster mapping
cairo.allocate_text_clusters(count) -> cairo_text_cluster_t* allocate an array of text clusters
sfont:text_to_glyphs(x,y, s,[#s]) -> g,#g, c,#c, cf | nil,err convert text to glyphs
cr:show_text_glyphs(s, [#s], g, #g, c, #c, f) draw glyphs with native cluster mapping
sr:has_show_text_glyphs() -> t|f check if surface has support for cluster mapping
freetype fonts
cairo.ft_font_face(ft_face[, ft_flags]) -> face create a font face from a freetype handle
face:synthesize_bold(t|f) /-> t|f get/set synthethize bold flag
face:synthesize_oblique(t|f) /-> t|f get/set synthethize oblique flag
sfont:lock_face() -> FT_Face lock font face
sfont:unlock_face() unlock font face
toy fonts
cairo.toy_font_face(family[, slant[, weight]]) -> face select a font with the toy text API
face:family() -> family get font family
face:slant() -> slant get font slant
face:weight() -> weight get font weight
callback-based fonts
cairo.user_font_face() -> face create a user font
face:init_func(func) /-> func get/set the scaled-font init function
face:render_glyph_func(func) /-> func get/set the glyph rendering function
face:text_to_glyphs_func(func) /-> func get/set the text-to-glyphs function
face:unicode_to_glyph_func(func) /-> func get/set the text-to-glyphs easy function
all fonts
face:type() -> type get font type
scaled fonts
face:scaled_font(mt, ctm, fopt) -> sfont create scaled font
sfont:type() -> cairo_font_type_t get scaled font type
sfont:extents() -> cairo_font_extents_t get font extents
sfont:text_extents(s) -> cairo_text_extents_t get text extents
sfont:glyph_extents(glyphs, #glyphs) -> cairo_text_extents_t get the extents of an array of glyphs
sfont:font_matrix() -> mt get the font matrix
sfont:ctm() -> mt get the CTM
sfont:scale_matrix() -> mt get the scale matrix
sfont:font_options(fopt) /-> fopt get/set the font options
sfont:font_face() -> face get the font face
font options
cairo.font_options() -> fopt create a font options object
fopt:copy() -> fopt copy font options
fopt:merge(fopt) merge options
fopt:equal(fopt) -> t|f compare options
fopt:hash() -> n get options hash
fopt:antialias(antialias) /-> antialias get/set the antialiasing mode
fopt:subpixel_order(order) /-> order get/set the subpixel order
fopt:hint_style(style) /-> style get/set the hint style
fopt:hint_metrics(metrics) /-> metrics get/set the hint metrics
fopt:lcd_filter(filter) /-> filter get/set the lcd filter
fopt:round_glyph_positions(pos) /-> pos get/set the round glyph positions
multi-page backends
sr:copy_page() emit the current page and retain surface contents
sr:show_page() emit the current page and clear surface contents
sr:device() -> cairo_device_t get the device of the surface
sr:device_offset([x, y]) /-> x, y set device offset
dev:type() -> type get device type
dev:acquire() -> true | nil,err,status acquire device
dev:release() release acquired device
dev:flush() flush pending drawing operations
dev:finish() finish device
cairo.matrix([mt | a,b,c,d,e,f]) -> mt create a matrix (init as identity by default)
mt:reset([mt | a,b,c,d,e,f]) -> mt reinitialize the matrix (as identity if no args given)
mt:translate(x, y) -> mt translate
mt:scale(sx[, sy]) -> mt scale
mt:scale_around(cx, cy, sx[, sy]) -> mt scale around a point
mt:rotate(angle) -> mt rotate
mt:rotate_around(cx, cy, angle) -> mt rotate arount a point
mt:invert() -> t|f invert if possible
mt1 * mt2 -> mt3 multiply matrices
mt:multiply(mt1[, mt2]) -> mt perform mt * mt1 -> mt or mt1 * mt2 -> mt
mt(x, y) -> x, y transform point
mt:distance(x, y) -> x, y transform distance
mt:transform(mt) -> mt transform by other matrix
mt:determinant() -> d compute the determinant
mt:invertible() -> t|f check if the matrix is invertible
mt:safe_transform(mt) -> mt transform by matrix only if it’s invertible
mt:skew(ax, ay) -> mt skew
mt:copy() -> mt copy the matrix
mt:equal(mt2) -> t|f
mt == mt2
test matrices for equality
cairo.region([[x, y, w, h] | rlist]) -> rgn create a region
rgn:copy() -> rgn copy region
rgn:equal(rgn) -> t|f compare regions
rgn:extents() -> x, y, w, h region extents
rgn:num_rectangles() -> n number of rectangles
rgn:rectangle(i) -> x, y, w, h get a rectangle
rgn:is_empty() -> t|f check if empty
rgn:contains_rectangle(x, y, w, h) -> t|f | 'partial' rectangle hit test
rgn:contains_point(x, y) -> t|f point hit test
rgn:translate(x, y) translate region
rgn:subtract(rgn | x, y, w, h) substract region or rectangle
rgn:intersect(rgn | x, y, w, h) intersect with region or rectangle
rgn:union(rgn | x, y, w, h) union with region or rectangle
rgn:xor(rgn | x, y, w, h) xor with region or rectangle
memory management
obj:free() free object
obj:refcount() -> refcount get ref count (*)
obj:ref() increase ref count (*)
obj:unref() decrease ref count and free when 0 (*)
obj:status() -> status get status
obj:status_message() -> s get status message
obj:check() raise an error if the object has an error status
cairo.stride(fmt, w) -> stride get stride for a format and width
cairo.bitmap_format(cairo_fmt) -> bmp_fmt get the bitmap format matching a cairo format
cairo.cairo_format(bmp_fmt) -> cairo_fmt get the cairo format matching a bitmap format
cairo.version() -> n get lib version
cairo.version_string() -> s get lib version as “X.Y.Z”
cairo.NULL a void* NULL pointer to disambiguate from nil when needed
cairo.enums -> {prefix -> {name -> value}} access to enum tables

(+) supported formats: ‘bgra8’, ‘bgrx8’, ‘g8’, ‘g1’, ‘rgb565’, ‘bgr10’; the field is anchored!

(*) for ref-counted objects only: cr, sr, dev, patt, sfont, font and rgn.


The included binaries are built with support for:

  • surfaces: image (pixman), recording, PS, PDF, SVG, GDI, Quartz
  • font selectors: Windows native, Quartz native
  • fonts: Windows native, Quartz native, freetype
  • PNG support

The build is configurable so you can add/remove these extensions as needed. The binding won’t break if extensions are missing in the binary.

Last updated: 3 years ago | Edit on GitHub

Pkg type:Lua+ffi
Version: r3-118-gff9605a
Last commit:
Author: Cosmin Apreutesei
License: MPL/LGPL
Import ver: 1.12.16

Requires: +freetype  +libpng  +luajit  +pixman  +winapi  +zlib  +harfbuzz  +ucdn  +freetype  +libpng  +luajit  +pixman  +zlib  +harfbuzz  +ucdn