diff --git a/admin/Makefile.am b/admin/Makefile.am index 6385eb910..9eb4fbb89 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -22,3 +22,7 @@ vgsuppression_SOURCES = $(admin_srcdir)/vgsuppression.c vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ vgsuppression_LDADD = liblumi.a -lnobugmt -lpthread -ldl +noinst_PROGRAMS += rsvg-convert +rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c +rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 diff --git a/admin/render-icon.py b/admin/render-icon.py index 9bf4c7dc5..ac8ab2453 100755 --- a/admin/render-icon.py +++ b/admin/render-icon.py @@ -24,12 +24,11 @@ import getopt from xml.dom import minidom import os import shutil -import cairo -import rsvg #svgDir = "svg" #prerenderedDir = "prerendered" inkscapePath = "/usr/bin/inkscape" +rsvgPath = "./rsvg-convert" artworkLayerPrefix = "artwork:" def createDirectory( name ): @@ -105,18 +104,11 @@ def renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size): # Prepare a Cairo context width = int(rectangle[2]) height = int(rectangle[3]) - - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) - context = cairo.Context(surface) - context.translate(-rectangle[0], -rectangle[1]) - - # Load an render the SVG - svg = rsvg.Handle(file=file_path) - svg.render_cairo(context) - - # Output a PNG file - surface.write_to_png(os.path.join(out_dir, - "%ix%i/%s.png" % (width, height, artwork_name))) + + os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath, + "--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], rectangle[2], rectangle[3]), + "--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name)), + file_path) def renderSvgIcon(file_path, out_dir): artwork_name, doc_size, rectangles = parseSVG(file_path) diff --git a/admin/rsvg-convert.c b/admin/rsvg-convert.c new file mode 100644 index 000000000..7ed5a9910 --- /dev/null +++ b/admin/rsvg-convert.c @@ -0,0 +1,219 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- + + rsvg-convert.c: Command line utility for exercising rsvg with cairo. + + Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005 Dom Lachowicz + Copyright (C) 2005 Caleb Moore + Copyright (C) 2008 Joel Holdsworth + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Carl Worth , + Caleb Moore , + Dom Lachowicz , + Joel Holdsworth +*/ + +#ifndef N_ +#define N_(X) X +#endif + +#include +#include +#include + +#include +#include + +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif + +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif + +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif + +#ifndef _ +#define _(X) X +#endif + +struct RsvgSizeCallbackData { + gint width; + gint height; +}; + +struct RsvgSourceRectangle { + double left; + double top; + double width; + double height; +}; + +static void +display_error (GError * err) +{ + if (err) { + g_print ("%s", err->message); + g_error_free (err); + } +} + +static void +rsvg_cairo_size_callback (int *width, int *height, gpointer data) +{ + RsvgDimensionData *dimensions = data; + *width = dimensions->width; + *height = dimensions->height; +} + +static cairo_status_t +rsvg_cairo_write_func (void *closure, const unsigned char *data, unsigned int length) +{ + fwrite (data, 1, length, (FILE *) closure); + return CAIRO_STATUS_SUCCESS; +} + +int +main (int argc, char **argv) +{ + GOptionContext *g_option_context; + int width = -1; + int height = -1; + char *source_rect_string = NULL; + char *output = NULL; + GError *error = NULL; + char *filename = NULL; + + char **args = NULL; + RsvgHandle *rsvg; + cairo_surface_t *surface = NULL; + cairo_t *cr = NULL; + RsvgDimensionData dimensions; + FILE *output_file = stdout; + + struct RsvgSourceRectangle source_rect = {0, 0, 0, 0}; + + GOptionEntry options_table[] = { + {"width", 'w', 0, G_OPTION_ARG_INT, &width, + N_("width [optional; defaults to the SVG's width]"), N_("")}, + {"height", 'h', 0, G_OPTION_ARG_INT, &height, + N_("height [optional; defaults to the SVG's height]"), N_("")}, + {"source-rect", 'r', 0, G_OPTION_ARG_STRING, &source_rect_string, + N_("source rectangle [optional; defaults to rectangle of the SVG document]"), N_("left:top:width:height")}, + {"output", 'o', 0, G_OPTION_ARG_STRING, &output, + N_("output filename"), NULL}, + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("FILE")}, + {NULL} + }; + + g_thread_init(NULL); + + g_option_context = g_option_context_new (_("- SVG Converter")); + g_option_context_add_main_entries (g_option_context, options_table, NULL); + g_option_context_set_help_enabled (g_option_context, TRUE); + if (!g_option_context_parse (g_option_context, &argc, &argv, &error)) { + display_error (error); + exit (1); + } + + g_option_context_free (g_option_context); + + if (output != NULL) { + output_file = fopen (output, "wb"); + if (!output_file) { + fprintf (stderr, _("Error saving to file: %s\n"), output); + exit (1); + } + } + + if (args[0] != NULL) { + filename = args[0]; + } + + /* Parse the source rect */ + if(source_rect_string != NULL) { + const int n = sscanf(source_rect_string, "%lg:%lg:%lg:%lg", + &source_rect.left, &source_rect.top, + &source_rect.width, &source_rect.height); + if(n != 4 || source_rect.width <= 0.0 || source_rect.height < 0.0) { + fprintf (stderr, _("Invalid source rect: %s\n"), source_rect_string); + exit(1); + } + } + + rsvg_init (); + + rsvg = rsvg_handle_new_from_file (filename, &error); + + if (!rsvg) { + fprintf (stderr, _("Error reading SVG:")); + display_error (error); + fprintf (stderr, "\n"); + exit (1); + } + + /* if the user did not specify a source rectangle, get the page size from the SVG */ + if(source_rect_string == NULL) { + rsvg_handle_set_size_callback (rsvg, rsvg_cairo_size_callback, &dimensions, NULL); + source_rect.left = 0; + source_rect.top = 0; + source_rect.width = dimensions.width; + source_rect.height = dimensions.height; + } + + rsvg_handle_get_dimensions (rsvg, &dimensions); + + if(width != -1 && height != -1) { + dimensions.width = width; + dimensions.height = height; + } else if(source_rect_string != NULL) { + dimensions.width = source_rect.width; + dimensions.height = source_rect.height; + } + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + dimensions.width, dimensions.height); + + cr = cairo_create (surface); + + cairo_translate(cr, -source_rect.left, -source_rect.top); + + if(width != -1 && height != -1 && source_rect_string != NULL) { + cairo_scale(cr, (double)dimensions.width / (double)source_rect.width, + (double)dimensions.height / (double)source_rect.height); + } + + rsvg_handle_render_cairo (rsvg, cr); + + cairo_surface_write_to_png_stream (surface, rsvg_cairo_write_func, output_file); + + g_object_unref (G_OBJECT (rsvg)); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + fclose (output_file); + + rsvg_term (); + + return 0; +} + diff --git a/icons/Makefile.am b/icons/Makefile.am index d3adca1fa..3edff311d 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -33,6 +33,7 @@ iconcommand = python $(top_srcdir)/admin/render-icon.py 48x48pre = $(prerendereddir)/48x48 lumigui_DEPENDENCIES += \ + rsvg-convert \ $(16x16)/arrow.png $(22x22)/arrow.png $(24x24)/arrow.png $(32x32)/arrow.png $(48x48)/arrow.png \ $(16x16)/i-beam.png $(22x22)/i-beam.png $(24x24)/i-beam.png $(32x32)/i-beam.png $(48x48)/i-beam.png \ $(16x16)/assets-panel.png \