[librsvg: 3/4] gitlab#328 - Make masking work on big-endian
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 3/4] gitlab#328 - Make masking work on big-endian
- Date: Thu, 30 Aug 2018 17:42:09 +0000 (UTC)
commit 242842c01849b7ecb950902c6491c7994048d091
Author: Federico Mena Quintero <federico gnome org>
Date: Thu Aug 30 10:56:50 2018 -0500
gitlab#328 - Make masking work on big-endian
The code only worked in little-endian machines; it wrote to the pixels
directly. Now it uses the pixel iterator for SharedImageSurface,
which handles endianness properly.
https://gitlab.gnome.org/GNOME/librsvg/issues/328
rsvg_internals/src/mask.rs | 98 +++++++++++++++++++++++++++++++---------------
1 file changed, 66 insertions(+), 32 deletions(-)
---
diff --git a/rsvg_internals/src/mask.rs b/rsvg_internals/src/mask.rs
index b64b1198..83fd158f 100644
--- a/rsvg_internals/src/mask.rs
+++ b/rsvg_internals/src/mask.rs
@@ -7,12 +7,20 @@ use attributes::Attribute;
use coord_units::CoordUnits;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
+use filters::context::IRect;
use handle::RsvgHandle;
use length::{Length, LengthDir};
use node::{NodeResult, NodeTrait, RsvgNode};
use parsers::{parse, parse_and_validate, Parse};
use property_bag::PropertyBag;
use state::Opacity;
+use surface_utils::{
+ iterators::Pixels,
+ shared_surface::SharedImageSurface,
+ shared_surface::SurfaceType,
+ ImageSurfaceDataExt,
+ Pixel,
+};
coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);
@@ -166,46 +174,72 @@ impl NodeMask {
}
}
-// Takes a surface and overwrites the alpha channel of each pixel
-// with the luminance of that pixel's RGB values.
+// Returns a surface whose alpha channel for each pixel is equal to the
+// luminance of that pixel's unpremultiplied RGB values. The resulting
+// surface's RGB values are not meanignful; only the alpha channel has
+// useful luminance data.
+//
+// This is to get a mask suitable for use with cairo_mask_surface().
fn compute_luminance_to_alpha(
- mut surface: cairo::ImageSurface,
+ surface: cairo::ImageSurface,
opacity: u8,
) -> Result<cairo::ImageSurface, cairo::Status> {
- let width = surface.get_width();
- let rowstride = surface.get_stride() as usize;
+ let surface = SharedImageSurface::new(surface, SurfaceType::SRgb)?;
+
+ let width = surface.width();
+ let height = surface.height();
+
+ let bounds = IRect {
+ x0: 0,
+ y0: 0,
+ x1: width,
+ y1: height,
+ };
+
+ let opacity = opacity as u32;
+
+ let mut output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;
+
+ let output_stride = output.get_stride() as usize;
{
- let mut pixels = surface.get_data().unwrap();
-
- for row in pixels.chunks_mut(rowstride) {
- for p in row[..4 * width as usize].chunks_mut(4) {
- // Assuming, the pixel is linear RGB (not sRGB)
- // y = luminance
- // Y = 0.2126 R + 0.7152 G + 0.0722 B
- // 1.0 opacity = 255
- //
- // When Y = 1.0, pixel for mask should be 0xFFFFFFFF
- // (you get 1.0 luminance from 255 from R, G and B)
- //
- // r_mult = 0xFFFFFFFF / (255.0 * 255.0) * .2126 = 14042.45 ~= 14042
- // g_mult = 0xFFFFFFFF / (255.0 * 255.0) * .7152 = 47239.69 ~= 47240
- // b_mult = 0xFFFFFFFF / (255.0 * 255.0) * .0722 = 4768.88 ~= 4769
- //
- // This allows for the following expected behaviour:
- // (we only care about the most sig byte)
- // if pixel = 0x00FFFFFF, pixel' = 0xFF......
- // if pixel = 0x00020202, pixel' = 0x02......
- // if pixel = 0x00000000, pixel' = 0x00......
- //
- // NOTE: the following assumes little-endian
- let (r, g, b, o) = (p[2] as u32, p[1] as u32, p[0] as u32, opacity as u32);
- p[3] = (((r * 14042 + g * 47240 + b * 4769) * o) >> 24) as u8;
- }
+ let mut output_data = output.get_data().unwrap();
+
+ for (x, y, pixel) in Pixels::new(&surface, bounds) {
+ // Assuming, the pixel is linear RGB (not sRGB)
+ // y = luminance
+ // Y = 0.2126 R + 0.7152 G + 0.0722 B
+ // 1.0 opacity = 255
+ //
+ // When Y = 1.0, pixel for mask should be 0xFFFFFFFF
+ // (you get 1.0 luminance from 255 from R, G and B)
+ //
+ // r_mult = 0xFFFFFFFF / (255.0 * 255.0) * .2126 = 14042.45 ~= 14042
+ // g_mult = 0xFFFFFFFF / (255.0 * 255.0) * .7152 = 47239.69 ~= 47240
+ // b_mult = 0xFFFFFFFF / (255.0 * 255.0) * .0722 = 4768.88 ~= 4769
+ //
+ // This allows for the following expected behaviour:
+ // (we only care about the most sig byte)
+ // if pixel = 0x00FFFFFF, pixel' = 0xFF......
+ // if pixel = 0x00020202, pixel' = 0x02......
+ // if pixel = 0x00000000, pixel' = 0x00......
+
+ let r = pixel.r as u32;
+ let g = pixel.g as u32;
+ let b = pixel.b as u32;
+
+ let output_pixel = Pixel {
+ r: 0,
+ g: 0,
+ b: 0,
+ a: (((r * 14042 + g * 47240 + b * 4769) * opacity) >> 24) as u8,
+ };
+
+ output_data.set_pixel(output_stride, output_pixel, x, y);
}
}
- Ok(surface)
+ Ok(output)
}
impl NodeTrait for NodeMask {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]