Tutorial preparation

http://cairographics.org/tutorial
- wget http://cairographics.org/cairo-tutorial.tar.gz
- tar xzf cairo-tutorial.tar.gz
- cd cairo-tutorial
- make
- cat README
IRC: irc.freenode.net #cairo
Carl Worth
Red Hat, Inc.
linux.conf.au
2006-01-26
http://cairographics.org

Ugly graphics

Jaggies
Fuzzies
Fireworks

Jaggies

Fuzzies

Fireworks

What you can do about it

- Let application authors know there are options
- Learn to use cairo—patch the applications
- Write your own cairo-using applications

Getting started

Various shell cairo programs

Minimal cairo-xlib program

#include <cairo.h>
#include <cairo-xlib.h>
int main (void) {
Display *dpy = XOpenDisplay (0);
Window w = XCreateSimpleWindow (dpy,RootWindow (dpy, 0),
0, 0, WIDTH, HEIGHT, 0, 0, WhitePixel (dpy, 0));
cairo_surface_t *surface = cairo_xlib_surface_create (dpy, w,
DefaultVisual (dpy, DefaultScreen (dpy)),
WIDTH, HEIGHT);
XEvent ev;
XSelectInput (dpy, w, ExposureMask);
XMapWindow (dpy, w);
while (XNextEvent (dpy, &ev) == 0)
if (ev.type == Expose && !ev.xexpose.count) {
cairo_t *cr = cairo_create (surface);
draw (cr);
cairo_destroy (cr);
}
}

Minimal cairo-gtk program

#include <gtk/gtk.h>
static gboolean
handle_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_t *cr = gdk_cairo_create (widget->window);
draw (cr);
cairo_destroy (cr);
return FALSE;
}
int main (int argc, char **argv) {
GtkWidget *window, *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT);
drawing_area = gtk_drawing_area_new ();
gtk_container_add (GTK_CONTAINER (window), drawing_area);
g_signal_connect (drawing_area, "expose-event",
G_CALLBACK (handle_expose), NULL);
gtk_widget_show_all (window); gtk_main ();
}

Minimal cairo-png program

#include <cairo.h>
int main (void)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
WIDTH, HEIGHT);
cr = cairo_create (surface);
draw (cr);
cairo_surface_write_to_png (surface, "foo.png");
cairo_surface_destroy (surface);
cairo_destroy (cr);
return 0;
}

Minimal cairo-pdf program

#include <cairo.h>
#include <cairo-pdf.h>
int main (void)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_pdf_surface_create ("foo.pdf", WIDTH, HEIGHT);
cr = cairo_create (surface);
draw (cr);
cairo_show_page (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
return 0;
}

Minimal pycairo-gtk shell

#!/usr/bin/env python
import gtk
import cairo
def expose (widget, event):
cr = widget.window.cairo_create ()
draw (cr)
win = gtk.Window ()
win.connect ('destroy', gtk.main_quit)
win.set_default_size(WIDTH, HEIGHT)
drawingarea = gtk.DrawingArea ()
win.add (drawingarea)
drawingarea.connect ('expose_event', expose)
win.show_all ()
gtk.main ()

Minimal pycairo-png shell

#!/usr/bin/env python
import cairo
surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
cr = cairo.Context (surface)
draw (cr)
surface.write_to_png ('foo.png')

Minimal nickle program

autoimport Cairo;
cairo_t cr = new (WIDTH, HEIGHT);
draw (cr);

Available bindings:

- C++ (cairomm)
- Haskell (hscairo)
- Java (CairoJava, cairo-java)
- Common Lisp (cl-cairo)
- Nickle (cairo-5c)
- Objective Caml (cairo-ocaml)
- perl (cairo-perl)
- python (pycairo)
- ruby (rcairo)
- squeak (cairo-squeak)

Following along

http://cairographics.org/tutorial
http://cairographics.org/cairo-tutorial.tar.gz
- tar xzf cairo-tutorial.tar.gz
- cd cairo-tutorial
- make
- cat README
IRC: irc.freenode.net #cairo

Cairo's rendering model

Let's start drawing

Here comes the fun part

API Overview

- Paths

- construction
- filling, stroking

- Images

- loading from disk
- using as source
- transforming/filtering

- Text

- “Toy” API
- “Full” API

Drawing functions

- Paths

- cairo_stroke
- cairo_fill

- Images

- cairo_paint
- cairo_mask
- cairo_paint_with_alpha

- Text

- cairo_show_text (“toy”)
- cairo_show_glyphs (“full”)

Basic path building

- Paths consist of lines and splines:

- cairo_move_to
start new sub path, set current point
- cairo_line_to
add line segment to path
- cairo_curve_to
add Bézier spline to path
- cairo_close_path
add line segment to last move_to point

Stroking paths

- cairo_stroke

- Paints the path itself as stroked by a pen
- Controlled by various stroke parameters:

- cairo_set_line_width
- cairo_set_line_cap
- cairo_set_line_join
- cairo_set_miter_limit
- cairo_set_dash

cairo_stroke example

cairo_set_line_width

cairo_set_line_cap example

- CAIRO_LINE_CAP_BUTT
- CAIRO_LINE_CAP_ROUND
- CAIRO_LINE_CAP_SQUARE

cairo_set_line_join example

- CAIRO_LINE_JOIN_BEVEL
- CAIRO_LINE_JOIN_ROUND
- CAIRO_LINE_JOIN_MITER

cairo_close_path example

- Adds a line segment (if necessary) to the
start of the path
- Draws a join from that line to the first
element of the path

cairo_set_dash example

cairo_fill

- Paints the “inside” of the path
- Two different ways to determine inside-ness

- cairo_set_fill_rule:
CAIRO_FILL_RULE_WINDING
CAIRO_FILL_RULE_EVEN_ODD

cairo_fill example

cairo_set_fill_rule

- To test a point for inside-ness, imagine a ray
from the point and extending to infinity
(any direction) and examine path crossings
- EVEN_ODD counts crossings and fills when odd
- WINDING counts up/down for left/right crossings
and fills when the final number is not zero

Fill rule example

Something besides black?

- All drawing occurs with the source pattern
- Uniform-color sources can be set
with or without alpha:

- cairo_set_source_rgb
- cairo_set_source_rgba

cairo_set_source example

Fill and stroke the same path

- cairo_stroke and cairo_fill consume the path
- Variants are available to preserve the path:

- cairo_stroke_preserve
- cairo_fill_preserve

- This is a variation from PostScript and PDF

- The cairo approach differs in different ways
- We think this way is better (of course)

Fill and stroke example

More path building

- cairo_rectangle
- cairo_arc
- cairo_text_path
- cairo_glyph_path
- Relative-coordinate variants:

- cairo_rel_move_to
- cairo_rel_line_to
- cairo_rel_curve_to

cairo_arc example

Outline text

Affine Transformations

- Single matrix combines rotation, translation,
scale and shear
- Non-projective transformations

- Pen doesn't change shape along the stroke

- Transformations are cumulative

- translate, scale != scale, translate

Affine Transform Example

Save/Restore Graphics States

- cairo_save and cairo_restore
- Very useful for bracketing function bodies
- Eliminates graphics state side effects
- NOTE: Path is not part of graphics state

- Path is not affected by cairo_save/restore
- Useful for path-generating functions

Clipping

- cairo_clip
- Intersects path with current clip to further
restrict drawing
- Pixel-aligned clipping is much faster
- cairo_clip_preserve is available as well

Other source patterns

- Surface patterns

- Image from disk
- Results of cairo drawing

- Gradient patterns

- linear gradients
- radial gradients

Loading an image file

Painting an image

Pattern transformation

Pattern filtering

Linear gradient example

Radial gradient example

Text

- “Toy” API:

- Useful for demos like we are writing today
- No real layout—not useful for the majority
of writing systems in the world

- “Full” API:

- User must do OS-dependent font selection
- User must access font glyph IDs directly
- User must do all text layout

“Toy” text API

- Simple font selection

- family, weight, slant
- OS independent
- No font listing support

- UTF-8 text drawing and extents functions
- Still supports full font transformations

“Toy” text example

“Real” text example

- Just use pango

Error handling in C

- C has no exceptions
- Checking each return is tedious
- C programmers rarely bother
- Lots of broken programs result

Cairo error handling

- Cairo stores status value when error occurs
- API “shuts down” when an error occurs
- All cairo functions are benign
(and well defined) after any error.
- cairo_status can be called when convenient
- Error status values propagate across objects

Cairo error example