Commit 54b6c145 authored by Dom Lachowicz's avatar Dom Lachowicz

implement rsvg_handle_get_pixbuf() API in terms of Cairo if it's around, and...

implement rsvg_handle_get_pixbuf() API in terms of Cairo if it's around, and libart is disabled, or nothing if neither is found.
parent 37bedd44
2005-08-07 Dom Lachowicz <cinamod@hotmail.com>
* rsvg-cairo-draw.c (rsvg_cairo_render_path): Implement line join, cap, width, dash, miter limit
(rsvg_cairo_render_image): Drawing images now largely works
(rsvg_cairo_push_discrete_layer): Largely implement
(rsvg_cairo_pop_discrete_layer): Largely implement
(rsvg_cairo_render_image): Drawing images now works
(rsvg_cairo_push_discrete_layer): Largely implemented
(rsvg_cairo_pop_discrete_layer): Largely implemented
(_set_source_rsvg_radial_gradient): Make this work for the few tests I have
* rsvg.c (rsvg_handle_get_pixbuf): Implement this in terms of libart, cairo, or nothing depending on what's enabled at configure time.
Defaults to libart, simply because the cairo backend is currently immature. This will change in due time...
* configure.in: Do the hackery necessary to determine what backend to use in rsvg_handle_get_pixbuf()
* Makefile.am: Ditto; make sure that librsvg-2.la is always installed (though it may not always work...)
2005-08-04 Carl Worth <cworth@cworth.org>
......
......@@ -11,7 +11,7 @@ noinst_PROGRAMS =
if HAVE_ART
SUBDIRS += gtk-engine gdk-pixbuf-loader moz-plugin
lib_LTLIBRARIES += librsvg-2-libart.la librsvg-2.la
lib_LTLIBRARIES += librsvg-2-libart.la
bin_PROGRAMS += rsvg $(target_rsvg_view)
noinst_PROGRAMS += test-performance
endif
......@@ -21,6 +21,8 @@ lib_LTLIBRARIES += librsvg-2-cairo.la
bin_PROGRAMS += rsvg-cairo
endif
lib_LTLIBRARIES += librsvg-2.la
man_MANS = rsvg.1
if OS_WIN32
......@@ -51,7 +53,7 @@ librsvg_2_base_la_SOURCES = \
rsvg-path.c \
rsvg-path.h \
rsvg-private.h \
rsvg-file-util.c \
rsvg-base-file-util.c \
rsvg-filter.c \
rsvg-filter.h \
rsvg-marker.c \
......@@ -74,7 +76,6 @@ librsvg_2_base_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -export-d
librsvg_2_base_la_LIBADD = $(LIBGNOME_VFS_LIBS) $(LIBGSF_LIBS) $(LIBCROCO_LIBS) $(LIBRSVG_LIBS) $(FREETYPE_LIBS)
librsvg_2_libart_la_SOURCES = \
rsvg-art-file-util.c \
rsvg-art-composite.c \
rsvg-art-composite.h \
rsvg-art-draw.c \
......@@ -98,10 +99,11 @@ librsvg_2_cairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -export-
librsvg_2_cairo_la_LIBADD = librsvg-2-base.la $(LIBGNOME_VFS_LIBS) $(LIBGSF_LIBS) $(LIBCROCO_LIBS) $(LIBRSVG_LIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS)
librsvg_2_la_SOURCES = \
rsvg.c
rsvg.c \
rsvg-file-util.c
librsvg_2_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -export-dynamic
librsvg_2_la_LIBADD = librsvg-2-base.la librsvg-2-libart.la $(LIBGNOME_VFS_LIBS) $(LIBGSF_LIBS) $(LIBCROCO_LIBS) $(LIBRSVG_LIBS) $(FREETYPE_LIBS) $(LIBART_LIBS)
librsvg_2_la_LIBADD = librsvg-2-base.la librsvg-2-libart.la $(LIBGNOME_VFS_LIBS) $(LIBGSF_LIBS) $(LIBCROCO_LIBS) $(LIBRSVG_LIBS) $(FREETYPE_LIBS) $(LIBRSVG_2_BACKEND_LIBADD)
librsvgincdir = $(includedir)/librsvg-2/librsvg
librsvginc_HEADERS = \
......@@ -121,7 +123,8 @@ INCLUDES = \
-DG_LOG_DOMAIN=\"librsvg\" \
-DLIBRSVG_DATADIR="\"$(datadir)\""\
$(LIBART_CFLAGS) \
$(CAIRO_CFLAGS)
$(CAIRO_CFLAGS) \
$(LIBRSVG_2_BACKEND_CFLAGS)
DEPS = $(top_builddir)/librsvg-2.la $(top_builddir)/librsvg-2-libart.la
LDADDS = \
......
......@@ -470,6 +470,24 @@ GLIB_LC_MESSAGES
dnl ===========================================================================
LIBRSVG_2_BACKEND_LIBADD=
LIBRSVG_2_BACKEND_CFLAGS=
build_librsvg_2_la=no
if test x$test_art = xtrue; then
build_librsvg_2_la=yes
LIBRSVG_2_BACKEND_LIBADD=librsvg-2-libart.la
LIBRSVG_2_BACKEND_CFLAGS=-DWITH_LIBART_BACKEND
elif test x$test_cairo = xtrue; then
build_librsvg_2_la=yes
LIBRSVG_2_BACKEND_LIBADD=librsvg-2-cairo.la
LIBRSVG_2_BACKEND_CFLAGS=-DWITH_CAIRO_BACKEND
fi
AC_SUBST(LIBRSVG_2_BACKEND_LIBADD)
AC_SUBST(LIBRSVG_2_BACKEND_CFLAGS)
dnl ===========================================================================
AC_OUTPUT([
librsvg.spec
librsvg-features.h
......
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-file-util.c: SAX-based renderer for SVG files into a GdkPixbuf.
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
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.
Author: Raph Levien <raph@artofcode.com>
*/
#include "config.h"
#include "rsvg.h"
#include "rsvg-private.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SVG_BUFFER_SIZE (1024 * 8)
static void
rsvg_size_callback (int *width,
int *height,
gpointer data)
{
struct RsvgSizeCallbackData *real_data = (struct RsvgSizeCallbackData *) data;
double zoomx, zoomy, zoom;
int in_width, in_height;
in_width = *width;
in_height = *height;
switch (real_data->type) {
case RSVG_SIZE_ZOOM:
if (*width < 0 || *height < 0)
return;
*width = floor (real_data->x_zoom * *width + 0.5);
*height = floor (real_data->y_zoom * *height + 0.5);
break;
case RSVG_SIZE_ZOOM_MAX:
if (*width < 0 || *height < 0)
return;
*width = floor (real_data->x_zoom * *width + 0.5);
*height = floor (real_data->y_zoom * *height + 0.5);
if (*width > real_data->width || *height > real_data->height)
{
zoomx = (double) real_data->width / *width;
zoomy = (double) real_data->height / *height;
zoom = MIN (zoomx, zoomy);
*width = floor (zoom * *width + 0.5);
*height = floor (zoom * *height + 0.5);
}
break;
case RSVG_SIZE_WH_MAX:
if (*width < 0 || *height < 0)
return;
zoomx = (double) real_data->width / *width;
zoomy = (double) real_data->height / *height;
if (zoomx < 0)
zoom = zoomy;
else if (zoomy < 0)
zoom = zoomx;
else
zoom = MIN (zoomx, zoomy);
*width = floor (zoom * *width + 0.5);
*height = floor (zoom * *height + 0.5);
break;
case RSVG_SIZE_WH:
if (real_data->width != -1)
*width = real_data->width;
if (real_data->height != -1)
*height = real_data->height;
break;
default:
g_assert_not_reached ();
}
if (real_data->keep_aspect_ratio)
{
int out_min = MIN(*width, *height);
if (out_min == *width)
{
*height = in_height * ((double)*width / (double)in_width);
}
else
{
*width = in_width * ((double)*height / (double)in_height);
}
}
}
/* private */
GdkPixbuf *
rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
size_t len,
struct RsvgSizeCallbackData * data,
const char * base_uri,
GError ** error)
{
RsvgHandle * handle;
GdkPixbuf * retval;
handle = rsvg_handle_new ();
if (!handle) {
g_set_error (error, rsvg_error_quark (), 0,
_("Error creating SVG reader"));
return NULL;
}
rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
rsvg_handle_set_base_uri (handle, base_uri);
rsvg_handle_write (handle, buff, len, error);
rsvg_handle_close (handle, error);
retval = rsvg_handle_get_pixbuf (handle);
rsvg_handle_free (handle);
return retval;
}
static GdkPixbuf *
rsvg_pixbuf_from_stdio_file_with_size_data(GByteArray *f,
struct RsvgSizeCallbackData * data,
gchar *base_uri,
GError ** error)
{
RsvgHandle * handle;
GdkPixbuf * retval;
handle = rsvg_handle_new ();
if (!handle) {
g_set_error (error, rsvg_error_quark (), 0,
_("Error creating SVG reader"));
return NULL;
}
rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
rsvg_handle_set_base_uri(handle, base_uri);
rsvg_handle_write (handle, f->data, f->len, error);
rsvg_handle_close (handle, error);
retval = rsvg_handle_get_pixbuf (handle);
rsvg_handle_free (handle);
return retval;
}
static GdkPixbuf *
rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,
struct RsvgSizeCallbackData * data,
GError ** error)
{
GdkPixbuf * pixbuf;
gchar * base_uri;
GByteArray *f;
base_uri = rsvg_get_base_uri_from_filename(file_name);
f = _rsvg_acquire_xlink_href_resource (file_name, base_uri, error);
if (f)
{
pixbuf = rsvg_pixbuf_from_stdio_file_with_size_data(f, data,
base_uri, error);
g_byte_array_free (f, TRUE);
}
else
{
pixbuf = NULL;
}
g_free(base_uri);
return pixbuf;
}
/**
* rsvg_pixbuf_from_file:
* @file_name: A file name
* @error: return location for errors
*
* Loads a new #GdkPixbuf from @file_name and returns it. The caller must
* assume the reference to the reurned pixbuf. If an error occurred, @error is
* set and %NULL is returned.
*
* Return value: A newly allocated #GdkPixbuf, or %NULL
**/
GdkPixbuf *
rsvg_pixbuf_from_file (const gchar *file_name,
GError **error)
{
return rsvg_pixbuf_from_file_at_size (file_name, -1, -1, error);
}
/**
* rsvg_pixbuf_from_file_at_zoom:
* @file_name: A file name
* @x_zoom: The horizontal zoom factor
* @y_zoom: The vertical zoom factor
* @error: return location for errors
*
* Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
* from the size indicated by the file by a factor of @x_zoom and @y_zoom. The
* caller must assume the reference to the returned pixbuf. If an error
* occurred, @error is set and %NULL is returned.
*
* Return value: A newly allocated #GdkPixbuf, or %NULL
**/
GdkPixbuf *
rsvg_pixbuf_from_file_at_zoom (const gchar *file_name,
double x_zoom,
double y_zoom,
GError **error)
{
struct RsvgSizeCallbackData data;
g_return_val_if_fail (file_name != NULL, NULL);
g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
data.type = RSVG_SIZE_ZOOM;
data.x_zoom = x_zoom;
data.y_zoom = y_zoom;
data.keep_aspect_ratio = FALSE;
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
/**
* rsvg_pixbuf_from_file_at_zoom_with_max:
* @file_name: A file name
* @x_zoom: The horizontal zoom factor
* @y_zoom: The vertical zoom factor
* @max_width: The requested max width
* @max_height: The requested max heigh
* @error: return location for errors
*
* Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
* from the size indicated by the file by a factor of @x_zoom and @y_zoom. If the
* resulting pixbuf would be larger than max_width/max_heigh it is uniformly scaled
* down to fit in that rectangle. The caller must assume the reference to the
* returned pixbuf. If an error occurred, @error is set and %NULL is returned.
*
* Return value: A newly allocated #GdkPixbuf, or %NULL
**/
GdkPixbuf *
rsvg_pixbuf_from_file_at_zoom_with_max (const gchar *file_name,
double x_zoom,
double y_zoom,
gint max_width,
gint max_height,
GError **error)
{
struct RsvgSizeCallbackData data;
g_return_val_if_fail (file_name != NULL, NULL);
g_return_val_if_fail (x_zoom > 0.0 && y_zoom > 0.0, NULL);
data.type = RSVG_SIZE_ZOOM_MAX;
data.x_zoom = x_zoom;
data.y_zoom = y_zoom;
data.width = max_width;
data.height = max_height;
data.keep_aspect_ratio = FALSE;
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
/**
* rsvg_pixbuf_from_file_at_size:
* @file_name: A file name
* @width: The new width, or -1
* @height: The new height, or -1
* @error: return location for errors
*
* Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is scaled
* from the size indicated to the new size indicated by @width and @height. If
* either of these are -1, then the default size of the image being loaded is
* used. The caller must assume the reference to the returned pixbuf. If an
* error occurred, @error is set and %NULL is returned.
*
* Return value: A newly allocated #GdkPixbuf, or %NULL
**/
GdkPixbuf *
rsvg_pixbuf_from_file_at_size (const gchar *file_name,
gint width,
gint height,
GError **error)
{
struct RsvgSizeCallbackData data;
data.type = RSVG_SIZE_WH;
data.width = width;
data.height = height;
data.keep_aspect_ratio = FALSE;
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
/**
* rsvg_pixbuf_from_file_at_max_size:
* @file_name: A file name
* @max_width: The requested max width
* @max_height: The requested max heigh
* @error: return location for errors
*
* Loads a new #GdkPixbuf from @file_name and returns it. This pixbuf is uniformly
* scaled so that the it fits into a rectangle of size max_width * max_height. The
* caller must assume the reference to the returned pixbuf. If an error occurred,
* @error is set and %NULL is returned.
*
* Return value: A newly allocated #GdkPixbuf, or %NULL
**/
GdkPixbuf *
rsvg_pixbuf_from_file_at_max_size (const gchar *file_name,
gint max_width,
gint max_height,
GError **error)
{
struct RsvgSizeCallbackData data;
data.type = RSVG_SIZE_WH_MAX;
data.width = max_width;
data.height = max_height;
data.keep_aspect_ratio = FALSE;
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-file-util.c: SAX-based renderer for SVG files into a GdkPixbuf.
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
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.
Author: Raph Levien <raph@artofcode.com>
*/
#include "config.h"
#include "rsvg.h"
#include "rsvg-private.h"
RsvgHandle * rsvg_handle_new_from_data (const guint8 *data,
gsize data_len,
GError **error)
{
RsvgHandle * handle = rsvg_handle_new ();
if(!handle) {
}
else if(!rsvg_handle_write (handle, data, data_len, error)) {
rsvg_handle_free(handle);
handle = NULL;
} else {
rsvg_handle_close(handle, error);
}
return handle;
}
RsvgHandle * rsvg_handle_new_from_file (const gchar *file_name,
GError **error)
{
gchar * base_uri;
GByteArray *f;
RsvgHandle * handle;
base_uri = rsvg_get_base_uri_from_filename(file_name);
f = _rsvg_acquire_xlink_href_resource (file_name, base_uri, error);
if (f)
{
handle = rsvg_handle_new_from_data (f->data, f->len, error);
if (handle)
rsvg_handle_set_base_uri (handle, base_uri);
g_byte_array_free (f, TRUE);
}
else
{
handle = NULL;
}
g_free(base_uri);
return handle;
}
......@@ -259,10 +259,9 @@ void rsvg_cairo_render_image (RsvgDrawingCtx *ctx, const GdkPixbuf * pixbuf,
static const cairo_user_data_key_t key;
int j;
/* XXX: This is not quite right... w & h aren't respected, but everything else seems to work ok */
cairo_save (render->cr);
_set_rsvg_affine (render->cr, state->affine);
cairo_scale (render->cr, w / width, h / height);
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
......@@ -402,7 +401,9 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
double width,
double height)
{
/* XXX: Untested, horribly ineffecient... */
/* XXX: Untested, horribly ineffecient, but probably works...
Ideally we'll want to create_image_surface_for_data() and then translate
ARGB32 into RGBA */
GdkPixbuf *img = NULL;
cairo_surface_t * surface;
......@@ -412,9 +413,7 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
RsvgCairoRender *save_render = (RsvgCairoRender *)ctx->render;
RsvgCairoRender *render;
surface = cairo_surface_create_similar(cairo_get_target (save_render->cr),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
cairo_surface_destroy (surface);
......@@ -433,6 +432,9 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
gdk_pixbuf_loader_write (img_loader, png_bytes->data, png_bytes->len, NULL);
gdk_pixbuf_loader_close (img_loader, NULL);
img = gdk_pixbuf_loader_get_pixbuf (img_loader);
/* ref before closing the loader */
if (img)
g_object_ref (G_OBJECT(img));
g_object_unref (G_OBJECT (img_loader));
}
g_byte_array_free(png_bytes, TRUE);
......
......@@ -27,47 +27,335 @@
#include "rsvg.h"
#include "rsvg-private.h"
RsvgHandle * rsvg_handle_new_from_data (const guint8 *data,
gsize data_len,
GError **error)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SVG_BUFFER_SIZE (1024 * 8)
static void
rsvg_size_callback (int *width,
int *height,
gpointer data)
{
struct RsvgSizeCallbackData *real_data = (struct RsvgSizeCallbackData *) data;
double zoomx, zoomy, zoom;
int in_width, in_height;
in_width = *width;
in_height = *height;
switch (real_data->type) {
case RSVG_SIZE_ZOOM:
if (*width < 0 || *height < 0)
return;
*width = floor (real_data->x_zoom * *width + 0.5);
*height = floor (real_data->y_zoom * *height + 0.5);
break;
case RSVG_SIZE_ZOOM_MAX:
if (*width < 0 || *height < 0)
return;
*width = floor (real_data->x_zoom * *width + 0.5);
*height = floor (real_data->y_zoom * *height + 0.5);
if (*width > real_data->width || *height > real_data->height)
{
zoomx = (double) real_data->width / *width;
zoomy = (double) real_data->height / *height;
zoom = MIN (zoomx, zoomy);
*width = floor (zoom * *width + 0.5);
*height = floor (zoom * *height + 0.5);
}
break;
case RSVG_SIZE_WH_MAX:
if (*width < 0 || *height < 0)
return;
zoomx = (double) real_data->width / *width;
zoomy = (double) real_data->height / *height;
if (zoomx < 0)
zoom = zoomy;
else if (zoomy < 0)
zoom = zoomx;
else
zoom = MIN (zoomx, zoomy);
*width = floor (zoom * *width + 0.5);
*height = floor (zoom * *height + 0.5);
break;
case RSVG_SIZE_WH:
if (real_data->width != -1)
*width = real_data->width;
if (real_data->height != -1)
*height = real_data->height;
break;
default:
g_assert_not_reached ();
}
if (real_data->keep_aspect_ratio)
{
int out_min = MIN(*width, *height);
if (out_min == *width)
{
*height = in_height * ((double)*width / (double)in_width);
}
else
{
*width = in_width * ((double)*height / (double)in_height);
}
}
}
/* private */
GdkPixbuf *
rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
size_t len,
struct RsvgSizeCallbackData * data,
const char * base_uri,
GError ** error)
{
RsvgHandle * handle;
GdkPixbuf * retval;
handle = rsvg_handle_new ();
if (!handle) {
g_set_error (error, rsvg_error_quark (), 0,
_("Error creating SVG reader"));
return NULL;
}
rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
rsvg_handle_set_base_uri (handle, base_uri);
rsvg_handle_write (handle, buff, len, error);
rsvg_handle_close (handle, error);
retval = rsvg_handle_get_pixbuf (handle);
rsvg_handle_free (handle);
return retval;
}
static GdkPixbuf *
rsvg_pixbuf_from_stdio_file_with_size_data(GByteArray *f,
struct RsvgSizeCallbackData * data,
gchar *base_uri,
GError ** error)
{
RsvgHandle * handle = rsvg_handle_new ();
if(!handle) {
}
else if(!rsvg_handle_write (handle, data, data_len, error)) {
rsvg_handle_free(handle);
handle = NULL;
} else {
rsvg_handle_close(handle, error);
RsvgHandle * handle;
GdkPixbuf * retval;
handle = rsvg_handle_new ();
if (!handle) {
g_set_error (error, rsvg_error_quark (), 0,
_("Error creating SVG reader"));
return NULL;
}
return handle;
rsvg_handle_set_size_callback (handle, rsvg_size_callback, data, NULL);
rsvg_handle_set_base_uri(handle, base_uri);
rsvg_handle_write (handle, f->data, f->len, error);
rsvg_handle_close (handle, error);
retval = rsvg_handle_get_pixbuf (handle);
rsvg_handle_free (handle);
return retval;
}
RsvgHandle * rsvg_handle_new_from_file (const gchar *file_name,
GError **error)
static GdkPixbuf *
rsvg_pixbuf_from_file_with_size_data (const gchar * file_name,