Tux Paint, again - Bill Kendrick - Linux Users' Group of Davis - June 18, 2007


SVG Support via Cairo

Snippet from SVG-related code in Tux Paint(as of May 2007):

#include "cairo.h"
#include "svg.h"
#include "svg-cairo.h"

loadstamp_callback(), which is called for each file found in the stamps folder, now checks for SVG variations of files when it comes across PNG images, and avoids loading the PNG if an SVG is found. (i.e., if "bucket.png" and "bucket.svg" both exist, only "bucket.svg" should be loaded.)

// Based on cairo-demo/sdl/main.c from Cairo
//(GPL'd, (c) 2004 Eric Windisch):

SDL_Surface * load_svg(char * file)
{
  // Create the SVG cairo stuff:
  if (svg_cairo_create(&scr) != SVG_CAIRO_STATUS_SUCCESS)
    return(NULL);

  // Parse the SVG file:
  if (svg_cairo_parse(scr, file) != SVG_CAIRO_STATUS_SUCCESS) {
    svg_cairo_destroy(scr);
    return(NULL);
  }

  // Get the natural size of the SVG
  svg_cairo_get_size(scr, &rwidth, &rheight);

  if (rwidth == 0 || rheight == 0) {
    svg_cairo_destroy(scr);
    return(NULL);
  }

  // We will create a CAIRO_FORMAT_ARGB32 surface. We don't need to match
  // the screen SDL format, but we are interested in the alpha bit...
  bpp = 32;
  btpp = 4;

  // We want to render at full Tux Paint canvas size, so that the stamp
  // at its largest scale remains highest quality (no pixelization):
  // (but not messing up the aspect ratio)

  scale = pick_best_scape(rwidth, rheight, r_canvas.w, r_canvas.h);

  width = ((float) rwidth * scale);
  height = ((float) rheight * scale);

  // scanline width
  stride = width * btpp;

  // Allocate space for an image:
  image = calloc(stride * height, 1);

Continued to right...

Continued from left...
  // Create the cairo surface with the adjusted width and height
  cairo_surface = cairo_image_surface_create_for_data(image,
                    CAIRO_FORMAT_ARGB32,
                    width, height, stride);

  cr = cairo_create(cairo_surface);
  if (cr == NULL) {
    svg_cairo_destroy(scr);
    return(NULL);
  }

  // Scale it (proportionally)
  cairo_scale(cr, scale, scale);  // no return value :(

  // Render SVG to our surface:
  res = svg_cairo_render(scr, cr);

  // Clean up:
  cairo_surface_destroy(cairo_surface);
  cairo_destroy(cr);
  svg_cairo_destroy(scr);

  if (res != SVG_CAIRO_STATUS_SUCCESS)
    return(NULL);

  // Adjust the SDL surface to match the cairo surface created
  // (surface mask of ARGB)
  rmask = 0x00ff0000;
  gmask = 0x0000ff00;
  bmask = 0x000000ff;
  amask = 0xff000000;

  // Create the SDL surface using the pixel data stored:
  sdl_surface_tmp = SDL_CreateRGBSurfaceFrom((void *) image, width, height,
                                             bpp, stride,
                                             rmask, gmask, bmask, amask);

  if (sdl_surface_tmp == NULL)
    return(NULL);

  // Convert the SDL surface to the display format, for faster blitting:
  sdl_surface = SDL_DisplayFormatAlpha(sdl_surface_tmp);
  SDL_FreeSurface(sdl_surface_tmp);

  return(sdl_surface);
}

Full source (as of May 2007) of load_svg() function (from tuxpaint.c):


Next