[librsvg/librsvg-2.48] Reimplement pixbuf_from_surface() in terms of iterators and .as_pixels()



commit 7719415a560957220a75f43622155ef95b40074d
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu May 28 19:41:55 2020 -0500

    Reimplement pixbuf_from_surface() in terms of iterators and .as_pixels()
    
    This gets rid of the calculation and checking of the offset of each
    pixel.
    
    Baseline:
    pixbuf_from_surface     time:   [1.5888 ms 1.5899 ms 1.5911 ms]
    
    Use SharedImageSurface.rows():
    pixbuf_from_surface     time:   [1.4434 ms 1.4514 ms 1.4592 ms]
                            change: [-9.5490% -9.2322% -8.8676%] (p = 0.00 < 0.05)
    
    Use as_pixels() and iterators for GdkPixbuf:
    pixbuf_from_surface     time:   [672.70 us 673.20 us 673.75 us]
                            change: [-53.489% -53.329% -53.174%] (p = 0.00 < 0.05)
    
    This is part of https://gitlab.gnome.org/GNOME/librsvg/-/issues/585

 Cargo.lock                |  1 +
 librsvg/Cargo.toml        |  1 +
 librsvg/pixbuf_utils.rs   | 66 +++++++++++++++++++----------------------------
 rsvg_internals/src/lib.rs |  2 +-
 4 files changed, 29 insertions(+), 41 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index e91ae772..a13f3a85 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -695,6 +695,7 @@ dependencies = [
  "glib-sys",
  "gobject-sys",
  "libc",
+ "rgb",
  "rsvg_internals",
  "url",
 ]
diff --git a/librsvg/Cargo.toml b/librsvg/Cargo.toml
index 669ec866..cb2c9f19 100644
--- a/librsvg/Cargo.toml
+++ b/librsvg/Cargo.toml
@@ -23,6 +23,7 @@ gio = { version="0.8.0", features=["v2_50"] } # per configure.ac
 gio-sys = "0.9.0"
 gobject-sys = "0.9.0"
 libc = "0.2"
+rgb = "0.8.17"
 rsvg_internals = { path = "../rsvg_internals" }
 url = "2"
 
diff --git a/librsvg/pixbuf_utils.rs b/librsvg/pixbuf_utils.rs
index e6dcef7c..6d5df5a7 100644
--- a/librsvg/pixbuf_utils.rs
+++ b/librsvg/pixbuf_utils.rs
@@ -4,6 +4,7 @@ use std::ptr;
 use gdk_pixbuf::{Colorspace, Pixbuf};
 use gio::prelude::*;
 use glib::translate::*;
+use rgb::{AsPixels, RGBA8};
 use url::Url;
 
 use crate::c_api::checked_i32;
@@ -36,61 +37,46 @@ pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, Rende
     let height = surface.height();
 
     let pixbuf = pixbuf_new(width, height)?;
+    assert!(pixbuf.get_colorspace() == Colorspace::Rgb);
+    assert!(pixbuf.get_bits_per_sample() == 8);
+    assert!(pixbuf.get_n_channels() == 4);
 
-    for (y, row) in surface.rows().enumerate() {
-        for (x, pixel) in row.iter().enumerate() {
-            let (r, g, b, a) = if pixel.a == 0 {
+    let pixels = unsafe { pixbuf.get_pixels() };
+    let width = width as usize;
+    let height = height as usize;
+    let stride = pixbuf.get_rowstride() as usize;
+    let width_in_bytes = width * 4;
+    assert!(width_in_bytes <= stride);
+
+    let pixbuf_rows = pixels.chunks_exact_mut(stride).take(height);
+
+    for (src_row, dest_row) in surface.rows().zip(pixbuf_rows) {
+        let row: &mut [RGBA8] = dest_row[..width_in_bytes].as_pixels_mut();
+
+        for (src, dest) in src_row.iter().zip(row.iter_mut()) {
+            let (r, g, b, a) = if src.a == 0 {
                 (0, 0, 0, 0)
             } else {
                 let pixel = Pixel {
-                    r: pixel.r,
-                    g: pixel.g,
-                    b: pixel.b,
-                    a: pixel.a,
+                    r: src.r,
+                    g: src.g,
+                    b: src.b,
+                    a: src.a,
                 }.unpremultiply();
 
                 (pixel.r, pixel.g, pixel.b, pixel.a)
             };
 
-            // FIXME: Use pixbuf.put_pixel when
-            // https://github.com/gtk-rs/gdk-pixbuf/issues/147
-            // is integrated
-            my_put_pixel(&pixbuf, x as i32, y as i32, r, g, b, a);
+            dest.r = r;
+            dest.g = g;
+            dest.b = b;
+            dest.a = a;
         }
     }
 
     Ok(pixbuf)
 }
 
-// Copied from gtk-rs/gdk-pixbuf
-//
-// See the following:
-//   https://gitlab.gnome.org/GNOME/librsvg/-/issues/584
-//   https://github.com/gtk-rs/gdk-pixbuf/issues/147
-//
-// Arithmetic can overflow in the computation of `pos` if it is not done with usize
-// values (everything coming out of a Pixbuf is i32).
-//
-// When this fix appears in a gtk-rs release, we can remove this.
-fn my_put_pixel(pixbuf: &Pixbuf, x: i32, y: i32, red: u8, green: u8, blue: u8, alpha: u8) {
-    unsafe {
-        let x = x as usize;
-        let y = y as usize;
-        let n_channels = pixbuf.get_n_channels() as usize;
-        assert!(n_channels == 3 || n_channels == 4);
-        let rowstride = pixbuf.get_rowstride() as usize;
-        let pixels = pixbuf.get_pixels();
-        let pos = y * rowstride + x * n_channels;
-
-        pixels[pos] = red;
-        pixels[pos + 1] = green;
-        pixels[pos + 2] = blue;
-        if n_channels == 4 {
-            pixels[pos + 3] = alpha;
-        }
-    }
-}
-
 enum SizeKind {
     Zoom,
     WidthHeight,
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 9abe74ca..3b833565 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -58,7 +58,7 @@ pub use crate::structure::IntrinsicDimensions;
 pub use crate::surface_utils::{
     iterators::Pixels,
     shared_surface::{SharedImageSurface, SurfaceType},
-    Pixel,
+    CairoARGB, Pixel,
 };
 
 pub use crate::viewbox::ViewBox;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]