Commit 24096468 authored by Paolo Borelli's avatar Paolo Borelli

handle: port get_pixbuf_sub to rust

parent 77f94b29
......@@ -957,6 +957,7 @@ dependencies = [
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
......
......@@ -176,6 +176,7 @@ extern gboolean rsvg_handle_rust_has_sub (RsvgHandle *handle, const char *id);
extern gboolean rsvg_handle_rust_render_cairo_sub (RsvgHandle *handle,
cairo_t *cr,
const char *id);
extern GdkPixbuf *rsvg_handle_rust_get_pixbuf_sub (RsvgHandle *handle, const char *id);
struct RsvgHandlePrivate {
RsvgSizeFunc size_func;
......@@ -1241,42 +1242,13 @@ rsvg_handle_has_sub (RsvgHandle *handle,
GdkPixbuf *
rsvg_handle_get_pixbuf_sub (RsvgHandle * handle, const char *id)
{
RsvgDimensionData dimensions;
GdkPixbuf *output = NULL;
cairo_surface_t *surface;
cairo_t *cr;
g_return_val_if_fail (RSVG_IS_HANDLE (handle), NULL);
if (!is_loaded (handle)) {
return NULL;
}
rsvg_handle_get_dimensions (handle, &dimensions);
if (!(dimensions.width && dimensions.height))
return NULL;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
dimensions.width, dimensions.height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
return NULL;
}
cr = cairo_create (surface);
if (!rsvg_handle_render_cairo_sub (handle, cr, id)) {
cairo_destroy (cr);
cairo_surface_destroy (surface);
return NULL;
}
cairo_destroy (cr);
output = rsvg_cairo_surface_to_pixbuf (surface);
cairo_surface_destroy (surface);
return output;
return rsvg_handle_rust_get_pixbuf_sub (handle, id);
}
/**
......
......@@ -223,79 +223,3 @@ rsvg_pixbuf_from_file_at_max_size (const gchar * file_name,
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
*
* Copyright (C) 1999 Michael Zucchi
*
* Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
* Cody Russell <bratsche@dfw.net>
* Federico Mena-Quintero <federico@gimp.org>
*/
static void
convert_alpha (guchar *dest_data,
int dest_stride,
guchar *src_data,
int src_stride,
int src_x,
int src_y,
int width,
int height)
{
int x, y;
src_data += src_stride * src_y + src_x * 4;
for (y = 0; y < height; y++) {
guint32 *src = (guint32 *) src_data;
for (x = 0; x < width; x++) {
guint alpha = src[x] >> 24;
if (alpha == 0) {
dest_data[x * 4 + 0] = 0;
dest_data[x * 4 + 1] = 0;
dest_data[x * 4 + 2] = 0;
} else {
dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
}
dest_data[x * 4 + 3] = alpha;
}
src_data += src_stride;
dest_data += dest_stride;
}
}
GdkPixbuf *
rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface)
{
GdkPixbuf *dest;
int width, height;
/* General sanity checks */
g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
if (width == 0 || height == 0)
return NULL;
dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE,
8,
width, height);
convert_alpha (gdk_pixbuf_get_pixels (dest),
gdk_pixbuf_get_rowstride (dest),
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface),
0, 0,
width, height);
return dest;
}
......@@ -66,9 +66,6 @@ double rsvg_get_default_dpi_x (void);
G_GNUC_INTERNAL
double rsvg_get_default_dpi_y (void);
G_GNUC_INTERNAL
GdkPixbuf *rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface);
G_GNUC_INTERNAL
void rsvg_return_if_fail_warning (const char *pretty_function,
const char *expression, GError ** error);
......
......@@ -28,6 +28,7 @@ downcast-rs = "^1.0.0"
encoding = "0.2.33"
float-cmp = "0.4.0"
gdk-pixbuf = "0.5.0"
gdk-pixbuf-sys = "0.7.0"
gio = { version="0.5.1", features=["v2_48"] } # per configure.ac
gio-sys = "0.7.0"
glib = "0.6.0"
......
......@@ -6,7 +6,8 @@ use std::slice;
use cairo::{self, ImageSurface, Status};
use cairo_sys;
use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gdk_pixbuf::{Colorspace, Pixbuf, PixbufLoader, PixbufLoaderExt};
use gdk_pixbuf_sys;
use gio::{File as GFile, InputStream};
use gio_sys;
use glib::translate::*;
......@@ -20,11 +21,16 @@ use defs::{Fragment, Href};
use dpi::Dpi;
use drawing_ctx::{DrawingCtx, RsvgRectangle};
use error::{set_gerror, DefsLookupErrorKind, LoadingError, RenderingError};
use filters::context::IRect;
use io;
use load::LoadContext;
use node::{Node, RsvgNode};
use structure::NodeSvg;
use surface_utils::shared_surface::SharedImageSurface;
use surface_utils::{
iterators::Pixels,
shared_surface::SharedImageSurface,
shared_surface::SurfaceType,
};
use svg::Svg;
use util::rsvg_g_warning;
use xml::XmlState;
......@@ -428,6 +434,60 @@ impl Handle {
res
}
fn get_pixbuf_sub(
&mut self,
handle: *mut RsvgHandle,
id: Option<&str>,
) -> Result<Pixbuf, RenderingError> {
let mut dimensions = unsafe { mem::zeroed() };
unsafe {
rsvg_handle_get_dimensions(handle, &mut dimensions);
}
if dimensions.width == 0 || dimensions.height == 0 {
return Err(RenderingError::SvgHasNoSize);
}
let surface =
ImageSurface::create(cairo::Format::ARgb32, dimensions.width, dimensions.height)?;
{
let cr = cairo::Context::new(&surface);
self.render_cairo_sub(handle, &cr, id)?;
}
let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
let bounds = IRect {
x0: 0,
y0: 0,
x1: dimensions.width,
y1: dimensions.height,
};
let pixbuf = Pixbuf::new(
Colorspace::Rgb,
true,
8,
dimensions.width,
dimensions.height,
);
for (x, y, pixel) in Pixels::new(&surface, bounds) {
let (r, g, b, a) = if pixel.a == 0 {
(0, 0, 0, 0)
} else {
let pixel = pixel.unpremultiply();
(pixel.r, pixel.g, pixel.b, pixel.a)
};
pixbuf.put_pixel(x as i32, y as i32, r, g, b, a);
}
Ok(pixbuf)
}
}
// Keep these in sync with rsvg.h:RsvgHandleFlags
......@@ -910,3 +970,18 @@ pub unsafe extern "C" fn rsvg_handle_rust_render_cairo_sub(
}
}
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_handle_rust_get_pixbuf_sub(
handle: *mut RsvgHandle,
id: *const libc::c_char,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
let rhandle = get_rust_handle(handle);
let id: Option<String> = from_glib_none(id);
match rhandle.get_pixbuf_sub(handle, id.as_ref().map(String::as_str)) {
Ok(pixbuf) => pixbuf.to_glib_full(),
Err(_) => ptr::null_mut(),
}
}
......@@ -11,6 +11,7 @@ extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
extern crate gdk_pixbuf;
extern crate gdk_pixbuf_sys;
extern crate gio;
extern crate gio_sys;
extern crate glib;
......@@ -44,6 +45,7 @@ pub use handle::{
rsvg_handle_rust_get_flags,
rsvg_handle_rust_get_geometry_sub,
rsvg_handle_rust_get_load_state,
rsvg_handle_rust_get_pixbuf_sub,
rsvg_handle_rust_has_sub,
rsvg_handle_rust_new,
rsvg_handle_rust_read_stream_sync,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment