giza

Drawing to an external Cairo context

Giza can plot into a caller-owned cairo_t context. This is intended for embedding giza plots in GUI toolkits (for example GtkDrawingArea) or other applications that already use Cairo for rendering.

This device is not opened with giza_open_device("/cairo", ...). Use the dedicated API described below instead.

Overview

Opening a giza device and binding a cairo context are separate steps:

  1. Open a cairo device (logical size only; no drawing yet).
  2. Configure the plot (world coordinates, colours, etc.) at any time.
  3. Bind a cairo_t with giza_set_cairo_context when you are ready to draw.
  4. Plot using the usual giza drawing routines.
  5. Release the context with giza_release_cairo_context when the frame is finished.

Giza performs cairo_save when binding and cairo_restore when releasing, so toolkit state on the context is preserved. Giza never destroys the caller's context or surface.

API summary

int giza_open_device_cairo (void);
int giza_open_device_size_cairo (double width, double height, int units);
int giza_open_device_size_cairo_float (float width, float height, int units);

int giza_set_cairo_context (cairo_t *cr);
int giza_release_cairo_context (void);
int giza_resize_device_cairo (double width, double height, int units);
cairo_surface_t *giza_get_cairo_surface (void);
    

giza_open_device_cairo() is like giza_open_device(): it opens a device with a default logical size (800×600 pixels). giza_open_device_size_cairo() is like giza_open_device_size() and lets you specify width, height and units (GIZA_UNITS_PIXELS, GIZA_UNITS_MM, etc.).

Plotting routines require a bound context. Call giza_set_cairo_context before drawing and giza_release_cairo_context when done (typically once per expose/redraw event in a GUI).

Off-screen example (image surface)

Click here for a complete C example, or follow the steps below.

1. Open the device

#include <giza.h>
#include <cairo/cairo.h>

int dev = giza_open_device_size_cairo (400., 300., GIZA_UNITS_PIXELS);
if (dev <= 0)
  return 1;
    

2. Create a cairo surface and bind it

cairo_surface_t *surface =
    cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 300);
cairo_t *cr = cairo_create (surface);

if (giza_set_cairo_context (cr) != 0)
  return 1;
    

3. Plot as usual

giza_set_environment (0., 1., 0., 1., 0, 0);
giza_box ("BCNT", 0., 0, "BCNT", 0., 0);
giza_move (0.1, 0.5);
giza_draw (0.9, 0.5);
    

4. Release, close, and save

giza_release_cairo_context ();
giza_close_device ();

cairo_surface_write_to_png (surface, "plot.png");
cairo_destroy (cr);
cairo_surface_destroy (surface);
    

GTK / toolkit integration

In a typical GtkDrawingArea (GTK 4) draw handler, the toolkit supplies a fresh cairo_t for each frame. Open the giza device once when the widget is created; bind and release on every draw:

/* once, e.g. in widget init */
int giza_dev = giza_open_device_size_cairo (w, h, GIZA_UNITS_PIXELS);
giza_select_device (giza_dev);
giza_set_environment (...);   /* optional one-time setup */

/* on each draw callback */
static void on_draw (GtkDrawingArea *area, cairo_t *cr, int w, int h, gpointer data)
{
  (void) area;
  (void) data;

  giza_select_device (giza_dev);
  giza_resize_device_cairo ((double) w, (double) h, GIZA_UNITS_PIXELS);
  giza_set_cairo_context (cr);

  /* ... giza plotting calls ... */

  giza_release_cairo_context ();
}
    

Keep giza_resize_device_cairo in sync with the widget size whenever the allocation changes. The cairo surface passed to giza_set_cairo_context should match that logical size.

Important notes

Compiling

Link against giza and cairo, for example:

gcc -o cairo-device cairo-device.c -lgiza -lcairo
    

See also the API reference for full function documentation.