[librsvg/wip/aruiz/rust-pixbuf-loader] pixbuf-loader: use render_to_pixbuf_at_size to generate the pixbuf
- From: Alberto Ruiz <aruiz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/wip/aruiz/rust-pixbuf-loader] pixbuf-loader: use render_to_pixbuf_at_size to generate the pixbuf
- Date: Mon, 8 Aug 2022 12:13:04 +0000 (UTC)
commit 5df169b63495e4ac1e6b1d39dd2bc4e8496612a5
Author: Alberto Ruiz <aruiz redhat com>
Date: Mon Aug 8 13:12:56 2022 +0100
pixbuf-loader: use render_to_pixbuf_at_size to generate the pixbuf
gdk-pixbuf-loader/src/lib.rs | 143 +++++++++++++++----------------------------
src/c_api/pixbuf_utils.rs | 2 +-
2 files changed, 51 insertions(+), 94 deletions(-)
---
diff --git a/gdk-pixbuf-loader/src/lib.rs b/gdk-pixbuf-loader/src/lib.rs
index 4d26e6a91..e2ce5e680 100644
--- a/gdk-pixbuf-loader/src/lib.rs
+++ b/gdk-pixbuf-loader/src/lib.rs
@@ -1,5 +1,6 @@
use std::ptr::null_mut;
+use gdk_pixbuf_sys::GdkPixbuf;
use gdk_pixbuf_sys::{
GdkPixbufFormat, GdkPixbufModule, GdkPixbufModulePattern, GdkPixbufModulePreparedFunc,
GdkPixbufModuleSizeFunc, GdkPixbufModuleUpdatedFunc, GDK_PIXBUF_FORMAT_SCALABLE,
@@ -7,6 +8,7 @@ use gdk_pixbuf_sys::{
};
use glib::translate::IntoGlib;
+use glib::translate::ToGlibPtr;
use glib_sys::{gboolean, GError};
use gobject_sys::GObject;
use libc::{c_char, c_int, c_uint};
@@ -17,6 +19,7 @@ use glib::Bytes;
use librsvg::Loader;
use cstr::cstr;
+use librsvg::rsvg_convert_only::LegacySize;
struct SvgContext {
size_func: GdkPixbufModuleSizeFunc,
@@ -68,20 +71,6 @@ unsafe extern "C" fn load_increment(
true.into_glib()
}
-fn argb_to_rgba(data: &mut Vec<u8>, width: usize, height: usize, stride: usize) {
- assert!((width * 4) >= stride);
- assert!((stride * height) <= data.len());
- for i in 0..height {
- let row_index = i * stride;
- for j in 0..width {
- let pixel_index = row_index + (j * 4);
- let tmp = data[pixel_index + 2];
- data[pixel_index + 2] = data[pixel_index];
- data[pixel_index] = tmp;
- }
- }
-}
-
#[no_mangle]
unsafe extern "C" fn stop_load(user_data: glib_sys::gpointer, error: *mut *mut GError) -> gboolean {
let ctx = Box::from_raw(user_data as *mut SvgContext);
@@ -89,57 +78,41 @@ unsafe extern "C" fn stop_load(user_data: glib_sys::gpointer, error: *mut *mut G
*error = null_mut();
}
- fn _inner_stop_load(ctx: &Box<SvgContext>) -> Result<(Vec<u8>, c_int, c_int, c_int), String> {
+ fn _inner_stop_load(ctx: &Box<SvgContext>) -> Result<gdk_pixbuf::Pixbuf, String> {
let handle = Loader::new()
.read_stream::<_, gio::File, gio::Cancellable>(&ctx.stream, None, None)
.map_err(|e| e.to_string())?;
let renderer = librsvg::CairoRenderer::new(&handle);
- let (w, h) = match renderer.intrinsic_size_in_pixels() {
- Some((w, h)) => (w, h),
- None => {
- return Err(String::from(
- "Could not get intrinsic size in pixel of Cairo memory surface",
- ));
+ let (w, h) = renderer.legacy_document_size().map_err(|e| e.to_string())?;
+ let mut w = w.ceil() as c_int;
+ let mut h = h.ceil() as c_int;
+
+ if let Some(size_func) = ctx.size_func {
+ let mut tmp_w: c_int = w;
+ let mut tmp_h: c_int = h;
+ unsafe {
+ size_func(
+ &mut tmp_w as *mut c_int,
+ &mut tmp_h as *mut c_int,
+ ctx.user_data,
+ )
+ };
+ if tmp_w != 0 && tmp_h != 0 {
+ w = tmp_w;
+ h = tmp_h;
}
- };
+ }
- let surface = cairo::ImageSurface::create(
- cairo::Format::ARgb32,
- w.ceil() as c_int,
- h.ceil() as c_int,
+ let pb = librsvg::c_api::pixbuf_utils::render_to_pixbuf_at_size(
+ &renderer, w as f64, h as f64, w as f64, h as f64,
)
.map_err(|e| e.to_string())?;
- let cr = cairo::Context::new(&surface).map_err(|e| e.to_string())?;
-
- renderer
- .render_document(
- &cr,
- &cairo::Rectangle {
- x: 0.0,
- y: 0.0,
- width: w,
- height: h,
- },
- )
- .map_err(|e| e.to_string())?;
-
- let w = w.ceil() as c_int;
- let h = h.ceil() as c_int;
-
- let stride = surface.stride();
- // The cairo::Context holds a reference to the surface which needs to be dropped to access the data
- std::mem::drop(cr);
- let sfc_data = surface.take_data().map_err(|e| e.to_string())?;
- let sfc_data = unsafe { std::slice::from_raw_parts(sfc_data.as_ptr(), sfc_data.len()) }; // This is
just a slice to the canonical data
- // We need
it as a mutable vector to move the alpha channel around
- let pb_data = sfc_data.to_vec();
-
- Ok((pb_data, w, h, stride))
+ Ok(pb)
}
- let (mut pb_data, mut w, mut h, stride) = match _inner_stop_load(&ctx) {
+ let pixbuf = match _inner_stop_load(&ctx) {
Ok(r) => r,
Err(e) => {
let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
@@ -148,40 +121,16 @@ unsafe extern "C" fn stop_load(user_data: glib_sys::gpointer, error: *mut *mut G
}
};
- // GDK Pixbuf only support RGBA and Cairo only ARGB32, we swap channels around
- argb_to_rgba(&mut pb_data, w as usize, h as usize, stride as usize);
-
- // Vector length and capacity to rebuild and destroy the vector in destroy_fn
- let cb_data = Box::new((pb_data.len(), pb_data.capacity()));
+ let w = pixbuf.width();
+ let h = pixbuf.height();
+ let pixbuf: *mut GdkPixbuf = pixbuf.to_glib_full();
- // Function to free the pixel data by rebuilding the Vec object
- #[no_mangle]
- unsafe extern "C" fn destroy_cb_foo(pixels: *mut u8, user_data: glib_sys::gpointer) {
- let data = Box::<(usize, usize)>::from_raw(user_data as *mut (usize, usize));
- Vec::from_raw_parts(pixels, data.0, data.1);
- }
-
- let pb_data = pb_data.leak::<'static>(); // Allocator stops tracking vector data
- let pixbuf = gdk_pixbuf_sys::gdk_pixbuf_new_from_data(
- pb_data.as_mut_ptr(),
- gdk_pixbuf_sys::GDK_COLORSPACE_RGB,
- true.into_glib(),
- 8,
- w,
- h,
- stride,
- Some(destroy_cb_foo),
- Box::into_raw(cb_data) as glib_sys::gpointer,
- );
- if let Some(size_func) = ctx.size_func {
- size_func(&mut w, &mut h, ctx.user_data);
+ if let Some(prep_func) = ctx.prep_func {
+ prep_func(pixbuf, null_mut(), ctx.user_data);
}
if let Some(update_func) = ctx.update_func {
update_func(pixbuf, 0, 0, w, h, ctx.user_data);
}
- if let Some(prep_func) = ctx.prep_func {
- prep_func(pixbuf, null_mut(), ctx.user_data);
- }
// The module loader increases a ref so we drop the pixbuf here
gobject_sys::g_object_unref(pixbuf as *mut GObject);
@@ -339,16 +288,24 @@ mod tests {
}
}
- const SVG_DATA: &'static str = r#"<svg
- width="100" height="100" viewBox="0 0 26.458333 26.458333" version="1.1" id="svg5"
xmlns="http://www.w3.org/2000/svg"
- xmlns:svg="http://www.w3.org/2000/svg">
- <defs id="defs2" />
- <g id="layer1">
- <rect style="fill:#aa1144;stroke-width:0.130147" id="rect31"
- width="26.458334" height="26.458334"
- x="-3.1789145e-07" y="-3.1789145e-07" />
- </g>
- </svg>"#;
+ const SVG_DATA: &'static str = r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ <svg
+ width="100px"
+ height="150px"
+ viewBox="0 0 26.458333 26.458333"
+ version="1.1"
+ id="svg5"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <rect
+ style="fill:#aa1144;stroke-width:0.0344347"
+ width="26.458332"
+ height="39.6875"
+ x="4.691162e-07"
+ y="-6.6145835"
+ id="rect2" />
+ </svg>
+ "#;
#[test]
fn minimal_svg() {
@@ -364,7 +321,7 @@ mod tests {
let h = gdk_pixbuf_sys::gdk_pixbuf_get_height(pb);
let stride = gdk_pixbuf_sys::gdk_pixbuf_get_rowstride(pb);
assert_eq!(w, 100);
- assert_eq!(h, 100);
+ assert_eq!(h, 150);
let pixels = gdk_pixbuf_sys::gdk_pixbuf_get_pixels(pb);
diff --git a/src/c_api/pixbuf_utils.rs b/src/c_api/pixbuf_utils.rs
index 9219ca3cd..229cc1f05 100644
--- a/src/c_api/pixbuf_utils.rs
+++ b/src/c_api/pixbuf_utils.rs
@@ -104,7 +104,7 @@ fn get_final_size(in_width: f64, in_height: f64, size_mode: &SizeMode) -> (f64,
(out_width, out_height)
}
-fn render_to_pixbuf_at_size(
+pub fn render_to_pixbuf_at_size(
renderer: &CairoRenderer<'_>,
document_width: f64,
document_height: f64,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]