/* -*- 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; }