/* rsvg-convert.c - Command line utility for exercising rsvg with cairo. Copyright (C) Red Hat, Inc. 2005, Carl Worth Caleb Moore Dom Lachowicz 2008, Joel Holdsworth This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ /** @file rsvg-convert.c ** Invoke the rSVG library to render SVG vector graphics with the help of Cairo. ** @note This tool is tightly integrated into the Lumiera build process in order ** to render icons and UI decorations designed as vector graphics, for those ** cases where it is beneficial to use bitmap graphics within the UI toolkit. */ #ifndef N_ #define N_(X) X #endif #include #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\n", 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) { if (fwrite (data, 1, length, (FILE *) closure) == length) return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_WRITE_ERROR; } 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} }; /* Set the locale so that UTF-8 filenames work */ setlocale (LC_ALL, ""); 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; }