246 lines
6.5 KiB
C
246 lines
6.5 KiB
C
/*
|
|
rsvg-convert.c - Command line utility for exercising rsvg with cairo.
|
|
|
|
Copyright (C) Red Hat, Inc.
|
|
2005, Carl Worth <cworth@cworth.org>
|
|
Caleb Moore <c.moore@student.unsw.edu.au>
|
|
Dom Lachowicz <cinamod@hotmail.com>
|
|
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
|
|
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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <locale.h>
|
|
|
|
#include <librsvg/rsvg.h>
|
|
#include <librsvg/rsvg-cairo.h>
|
|
|
|
|
|
#ifdef CAIRO_HAS_PS_SURFACE
|
|
#include <cairo-ps.h>
|
|
#endif
|
|
|
|
#ifdef CAIRO_HAS_PDF_SURFACE
|
|
#include <cairo-pdf.h>
|
|
#endif
|
|
|
|
#ifdef CAIRO_HAS_SVG_SURFACE
|
|
#include <cairo-svg.h>
|
|
#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_("<int>")},
|
|
{"height", 'h', 0, G_OPTION_ARG_INT, &height,
|
|
N_("height [optional; defaults to the SVG's height]"), N_("<int>")},
|
|
{"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;
|
|
}
|