Overview of Librsvg

Overview of Librsvg

Librsvg is a library for rendering Scalable Vector Graphics files (SVG). Specifically, it can take non-animated, non-scripted SVG documents and render them into a Cairo surface. Normally this means an in-memory raster surface, but it could also be any of the other surface types that Cairo supports.

Librsvg supports many of the graphic features in the SVG 1.1 and SVG2 specifications. The main features of SVG that librsvg does not support are the following:

  • Scripting or animation: Librsvg reads SVG data and renders it to a static image. There is no provision to execute scripts that may control animation parameters.

  • Access to the DOM: Librsvg creates an internal representation of the SVG data, but it does not provide outside access to the resulting Document Object Model (DOM).

  • SVG fonts: Instead, librsvg relies on the system’s fonts, particularly those that are available through Cairo/Pango.

Librsvg’s API is divided into two main parts: one for loading SVG data and one for rendering it. In the loading stage, you create an RsvgHandle object from SVG data, which can come from a file or from a stream of bytes. In the rendering stage, you take an RsvgHandle and ask it to render itself to a Cairo context.

Loading

RsvgHandle is an object that represents SVG data in memory. Your program creates an RsvgHandle from an SVG file, or from a memory buffer that contains SVG data, or in the most general form, from a GInputStream that will provide SVG data. At this stage you can get either I/O errors or parsing errors. If loading completes successfully, the RsvgHandle will be ready for rendering.

Generally you should use rsvg_handle_new_from_gfile_sync() or rsvg_handle_new_from_stream_sync() to load an SVG document into an RsvgHandle. There are other convenience functions to load an SVG document, but these two functions let one set the “base file” and the RsvgHandleFlags in a single call.

Rendering

Once you have an SVG image loaded into an RsvgHandle, you can render it to a Cairo context any number of times, or to different Cairo contexts, as needed. As a convenience, you can pick a single element in the SVG by its id attribute and render only that element; this is so that sub-elements can be extracted conveniently out of a larger SVG.

Generally you should use rsvg_handle_render_document() to render the whole SVG document at any size you choose into a Cairo context.

Example: simple loading and rendering

The following program loads hello.svg, renders it scaled to fit within 640×480 pixels, and writes a hello.png file.

Note the following:

  • rsvg_handle_render_document() will scale the document proportionally to fit the viewport you specify, and it will center the image within that viewport.

  • Librsvg does not paint a background color by default, so in the following example all unfilled areas of the SVG will appear as fully transparent. If you wish to have a specific background, fill the viewport area yourself before rendering the SVG.

/* gcc -Wall -g -O2 -o load-and-render load-and-render.c `pkg-config --cflags --libs rsvg-2.0` */

#include <stdlib.h>
#include <librsvg/rsvg.h>

#define WIDTH 640
#define HEIGHT 480

int
main (void)
{
  /* First, load an SVG document into an RsvgHandle */

  GError *error = NULL;
  GFile *file = g_file_new_for_path ("hello.svg");
  RsvgHandle *handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, &error);

  if (!handle)
    {
      g_printerr ("could not load: %s", error->message);
      exit (1);
    }

  /* Create a Cairo image surface and a rendering context for it */

  cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
  cairo_t *cr = cairo_create (surface);

  /* Render the handle scaled proportionally into that whole surface */

  RsvgRectangle viewport = {
    .x = 0.0,
    .y = 0.0,
    .width = WIDTH,
    .height = HEIGHT,
  };

  if (!rsvg_handle_render_document (handle, cr, &viewport, &error))
    {
      g_printerr ("could not render: %s", error->message);
      exit (1);
    }

  /* Write a PNG file */

  if (cairo_surface_write_to_png (surface, "hello.png") != CAIRO_STATUS_SUCCESS)
    {
      g_printerr ("could not write output file");
      exit (1);
    }

  /* Free our memory and we are done! */

  cairo_destroy (cr);
  cairo_surface_destroy (surface);
  g_object_unref (handle);
  g_object_unref (file);
  return 0;
}