rsvg.c 5.43 KB
Newer Older
1
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/*
3
   rsvg.c: SAX-based renderer for SVG files into a GdkPixbuf.
4

5
   Copyright (C) 2000 Eazel, Inc.
6
   Copyright (C) 2002-2005 Dom Lachowicz <cinamod@hotmail.com>
7

8
   This program is free software; you can redistribute it and/or
9
   modify it under the terms of the GNU Library General Public License as
10 11
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
12

13 14 15
   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
16
   Library General Public License for more details.
17

18
   You should have received a copy of the GNU Library General Public
19 20 21
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
22

23 24 25
   Author: Raph Levien <raph@artofcode.com>
*/

26
#include "config.h"
27

28
#include "rsvg.h"
29
#include "rsvg-private.h"
30 31 32
#include "rsvg-css.h"
#include "rsvg-styles.h"
#include "rsvg-shapes.h"
33
#include "rsvg-image.h"
34
#include "rsvg-text.h"
35
#include "rsvg-filter.h"
36
#include "rsvg-mask.h"
37
#include "rsvg-marker.h"
38

39
#include <math.h>
40
#include <string.h>
Michael Meeks's avatar
Michael Meeks committed
41
#include <stdarg.h>
42

43 44
#if defined(WITH_LIBART_BACKEND)

45 46 47 48
#include "rsvg-bpath-util.h"
#include "rsvg-path.h"
#include "rsvg-paint-server.h"

Caleb Michael Moore's avatar
Caleb Michael Moore committed
49 50 51
#include "rsvg-art-render.h"
#include "rsvg-art-draw.h"

52
static RsvgDrawingCtx * 
Caleb Michael Moore's avatar
Caleb Michael Moore committed
53
rsvg_new_drawing_ctx(RsvgHandle * handle)
54
{
55
	RsvgDimensionData data;
56
	RsvgDrawingCtx * draw;
57 58
	RsvgState * state;
	double affine[6];
Dom Lachowicz's avatar
Dom Lachowicz committed
59

60
	rsvg_handle_get_dimensions(handle, &data);
Dom Lachowicz's avatar
Dom Lachowicz committed
61 62 63
	if(data.width == 0 || data.height == 0)
		return NULL;

64 65
	draw = g_new(RsvgDrawingCtx, 1);

Dom Lachowicz's avatar
Dom Lachowicz committed
66
	draw->render = (RsvgRender *) rsvg_art_render_new (data.width, data.height);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
67

Dom Lachowicz's avatar
Dom Lachowicz committed
68
	if(!draw->render)
69
		return NULL;	
Caleb Michael Moore's avatar
Caleb Michael Moore committed
70 71

	draw->state = NULL;
72

73
	/* should this be G_ALLOC_ONLY? */
Caleb Michael Moore's avatar
Caleb Michael Moore committed
74 75 76 77 78 79 80
	draw->state_allocator = g_mem_chunk_create (RsvgState, 256, G_ALLOC_AND_FREE);

	draw->defs = handle->defs;
	draw->base_uri = g_strdup(handle->base_uri);
	draw->dpi_x = handle->dpi_x;
	draw->dpi_y = handle->dpi_y;
	draw->pango_context = NULL;
81

Caleb Michael Moore's avatar
Caleb Michael Moore committed
82 83
	rsvg_state_push(draw);

84 85 86 87 88 89 90
	state = rsvg_state_current(draw);
	affine[0] = data.width / data.em;
	affine[1] = 0;
	affine[2] = 0;
	affine[3] = data.height / data.ex;
	affine[4] = 0;
	affine[5] = 0;
91

92 93 94
	_rsvg_affine_multiply(state->affine, affine, 
						  state->affine);
	
Caleb Michael Moore's avatar
Caleb Michael Moore committed
95
	return draw;
96 97
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
{
	GdkPixbuf * output = NULL;
	RsvgDrawingCtx * draw;

	draw = rsvg_new_drawing_ctx(handle);
	if (!draw)
		return NULL;
	rsvg_state_push(draw);
	rsvg_node_draw((RsvgNode *)handle->treebase, draw, 0);
	rsvg_state_pop(draw);
	output = ((RsvgArtRender *)draw->render)->pixbuf;
	rsvg_drawing_ctx_free(draw);
	
	return output;
}

#elif defined(WITH_CAIRO_BACKEND)

#include "rsvg-cairo.h"

119 120
static void
rsvg_pixmap_destroy (gchar *pixels, gpointer data)
121
{
122
  g_free (pixels);
123 124 125 126 127 128
}

static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
{
	RsvgDimensionData dimensions;
	GdkPixbuf *output = NULL;
129
	guint8 *pixels;
130 131
	cairo_surface_t *surface;
	cairo_t *cr;
132
	int row, rowstride;
133 134

	rsvg_handle_get_dimensions (handle, &dimensions);
135
	rowstride = dimensions.width * 4;
136

137 138 139 140 141
	pixels = g_new(guint8, dimensions.width * dimensions.height * 4);
	surface = cairo_image_surface_create_for_data (pixels,
												   CAIRO_FORMAT_ARGB32,
												   dimensions.width, dimensions.height,
												   rowstride);
142 143 144 145
	cr = cairo_create (surface);

	rsvg_cairo_render (cr, handle);

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
	/* un-premultiply data */
	for(row = 0; row < dimensions.height; row++) {
		guint8 *row_data = (pixels + (row * rowstride));
		int i;

		for(i = 0; i < rowstride; i += 4) {
			guint8 *b = &row_data[i];
			guint32 pixel;
			guint8 alpha;

			memcpy(&pixel, b, sizeof(guint32));
			alpha = (pixel & 0xff000000) >> 24;
			if(alpha == 0) {
				b[0] = b[1] = b[2] = b[3] = 0;
			} else {
				b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
				b[1] = (((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
				b[2] = (((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
				b[3] = alpha;
			}
		}
167
	}
168 169 170 171 172 173 174 175 176 177

	output = gdk_pixbuf_new_from_data (pixels,
									   GDK_COLORSPACE_RGB,
									   TRUE,
									   8,
									   dimensions.width,
									   dimensions.height,
									   rowstride,
									   (GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
									   NULL);
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199

	cairo_destroy (cr);
	cairo_surface_destroy (surface);

	return output;
}

#else

#ifdef __GNUC__
#warning "No backend defined. Needs either Cairo or Libart in order to work."
#endif

static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
{
	g_warning ("No backend defined. Needs either Cairo or Libart in order to work.");
	return NULL;
}


#endif

200 201 202 203 204 205 206 207 208 209
/**
 * rsvg_handle_get_pixbuf:
 * @handle: An #RsvgHandle
 *
 * Returns the pixbuf loaded by #handle.  The pixbuf returned will be reffed, so
 * the caller of this function must assume that ref.  If insufficient data has
 * been read to create the pixbuf, or an error occurred in loading, then %NULL
 * will be returned.  Note that the pixbuf may not be complete until
 * @rsvg_handle_close has been called.
 *
210
 * Returns: the pixbuf loaded by #handle, or %NULL.
211 212 213
 **/
GdkPixbuf *
rsvg_handle_get_pixbuf (RsvgHandle *handle)
214
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
215
	g_return_val_if_fail (handle != NULL, NULL);
216 217 218 219

	if (!handle->finished)
		return NULL;

220
	return _rsvg_handle_get_pixbuf (handle);
221
}