[librsvg] surface_utils: go back on set_pixel directly on the data slice
- From: Paolo Borelli <pborelli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] surface_utils: go back on set_pixel directly on the data slice
- Date: Wed, 15 Jan 2020 02:57:03 +0000 (UTC)
commit dea449a31975977ec6523909c582539cb2d8f932
Author: Paolo Borelli <pborelli gnome org>
Date: Wed Jan 15 03:16:43 2020 +0100
surface_utils: go back on set_pixel directly on the data slice
It turns out that having set_pixel on the ExclusiveImageSurface
caused a regression in the benchmarks. Instead add a modify()
method taking a closure that gets passed data and stride and
call set_pixel directly on the data slice.
rsvg_internals/benches/srgb.rs | 26 ++---
rsvg_internals/src/filters/color_matrix.rs | 58 ++++++-----
rsvg_internals/src/filters/component_transfer.rs | 32 +++---
rsvg_internals/src/filters/convolve_matrix.rs | 110 +++++++++++----------
rsvg_internals/src/filters/morphology.rs | 74 +++++++-------
rsvg_internals/src/filters/turbulence.rs | 58 +++++------
rsvg_internals/src/surface_utils/shared_surface.rs | 71 +++++++------
rsvg_internals/src/surface_utils/srgb.rs | 40 ++++----
8 files changed, 247 insertions(+), 222 deletions(-)
---
diff --git a/rsvg_internals/benches/srgb.rs b/rsvg_internals/benches/srgb.rs
index 39cf9578..98427743 100644
--- a/rsvg_internals/benches/srgb.rs
+++ b/rsvg_internals/benches/srgb.rs
@@ -6,7 +6,7 @@ use rsvg_internals::rect::IRect;
use rsvg_internals::surface_utils::{
shared_surface::{ExclusiveImageSurface, SurfaceType},
srgb::{linearize, map_unpremultiplied_components_loop},
- Pixel,
+ ImageSurfaceDataExt, Pixel,
};
const SURFACE_SIDE: i32 = 512;
@@ -23,18 +23,20 @@ fn bench_srgb_linearization(c: &mut Criterion) {
ExclusiveImageSurface::new(SURFACE_SIDE, SURFACE_SIDE, SurfaceType::LinearRgb).unwrap();
// Fill the surface with non-zero alpha (otherwise linearization is a no-op).
- for y in BOUNDS.y_range() {
- for x in BOUNDS.x_range() {
- let pixel = Pixel {
- r: 0,
- g: 0,
- b: 0,
- a: 127,
- };
-
- surface.set_pixel(pixel, x as u32, y as u32);
+ surface.modify(&mut |data, stride| {
+ for y in BOUNDS.y_range() {
+ for x in BOUNDS.x_range() {
+ let pixel = Pixel {
+ r: 0,
+ g: 0,
+ b: 0,
+ a: 127,
+ };
+
+ data.set_pixel(stride, pixel, x as u32, y as u32);
+ }
}
- }
+ });
let surface = surface.share().unwrap();
let mut output_surface =
diff --git a/rsvg_internals/src/filters/color_matrix.rs b/rsvg_internals/src/filters/color_matrix.rs
index 230f200b..4db2d24c 100644
--- a/rsvg_internals/src/filters/color_matrix.rs
+++ b/rsvg_internals/src/filters/color_matrix.rs
@@ -8,7 +8,9 @@ use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
-use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface, Pixel};
+use crate::surface_utils::{
+ iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
+};
use crate::util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -170,36 +172,38 @@ impl FilterEffect for FeColorMatrix {
input.surface().surface_type(),
)?;
- for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
- let alpha = f64::from(pixel.a) / 255f64;
-
- let pixel_vec = if alpha == 0.0 {
- Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
- } else {
- Vector5::new(
- f64::from(pixel.r) / 255f64 / alpha,
- f64::from(pixel.g) / 255f64 / alpha,
- f64::from(pixel.b) / 255f64 / alpha,
- alpha,
- 1.0,
- )
- };
- let mut new_pixel_vec = Vector5::zeros();
- self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);
+ surface.modify(&mut |data, stride| {
+ for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+ let alpha = f64::from(pixel.a) / 255f64;
+
+ let pixel_vec = if alpha == 0.0 {
+ Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
+ } else {
+ Vector5::new(
+ f64::from(pixel.r) / 255f64 / alpha,
+ f64::from(pixel.g) / 255f64 / alpha,
+ f64::from(pixel.b) / 255f64 / alpha,
+ alpha,
+ 1.0,
+ )
+ };
+ let mut new_pixel_vec = Vector5::zeros();
+ self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);
- let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);
+ let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);
- let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;
+ let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;
- let output_pixel = Pixel {
- r: premultiply(new_pixel_vec[0]),
- g: premultiply(new_pixel_vec[1]),
- b: premultiply(new_pixel_vec[2]),
- a: ((new_alpha * 255f64) + 0.5) as u8,
- };
+ let output_pixel = Pixel {
+ r: premultiply(new_pixel_vec[0]),
+ g: premultiply(new_pixel_vec[1]),
+ b: premultiply(new_pixel_vec[2]),
+ a: ((new_alpha * 255f64) + 0.5) as u8,
+ };
- surface.set_pixel(output_pixel, x, y);
- }
+ data.set_pixel(stride, output_pixel, x, y);
+ }
+ });
Ok(FilterResult {
name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/component_transfer.rs
b/rsvg_internals/src/filters/component_transfer.rs
index f433fe93..c5790ecb 100644
--- a/rsvg_internals/src/filters/component_transfer.rs
+++ b/rsvg_internals/src/filters/component_transfer.rs
@@ -9,7 +9,9 @@ use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
-use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface, Pixel};
+use crate::surface_utils::{
+ iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
+};
use crate::util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -355,19 +357,21 @@ impl FilterEffect for FeComponentTransfer {
let compute_a = |alpha| compute_a(¶ms_a, alpha);
// Do the actual processing.
- for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
- let alpha = f64::from(pixel.a) / 255f64;
- let new_alpha = compute_a(alpha);
-
- let output_pixel = Pixel {
- r: compute_r(pixel.r, alpha, new_alpha),
- g: compute_g(pixel.g, alpha, new_alpha),
- b: compute_b(pixel.b, alpha, new_alpha),
- a: ((new_alpha * 255f64) + 0.5) as u8,
- };
-
- surface.set_pixel(output_pixel, x, y);
- }
+ surface.modify(&mut |data, stride| {
+ for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+ let alpha = f64::from(pixel.a) / 255f64;
+ let new_alpha = compute_a(alpha);
+
+ let output_pixel = Pixel {
+ r: compute_r(pixel.r, alpha, new_alpha),
+ g: compute_g(pixel.g, alpha, new_alpha),
+ b: compute_b(pixel.b, alpha, new_alpha),
+ a: ((new_alpha * 255f64) + 0.5) as u8,
+ };
+
+ data.set_pixel(stride, output_pixel, x, y);
+ }
+ });
Ok(FilterResult {
name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/convolve_matrix.rs b/rsvg_internals/src/filters/convolve_matrix.rs
index 0d49ab80..de6c1ca8 100644
--- a/rsvg_internals/src/filters/convolve_matrix.rs
+++ b/rsvg_internals/src/filters/convolve_matrix.rs
@@ -12,7 +12,7 @@ use crate::rect::IRect;
use crate::surface_utils::{
iterators::{PixelRectangle, Pixels},
shared_surface::ExclusiveImageSurface,
- EdgeMode, Pixel,
+ EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
@@ -235,67 +235,69 @@ impl FilterEffect for FeConvolveMatrix {
input.surface().surface_type(),
)?;
- for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
- // Compute the convolution rectangle bounds.
- let kernel_bounds = IRect::new(
- x as i32 - self.target_x.unwrap() as i32,
- y as i32 - self.target_y.unwrap() as i32,
- x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
- y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
- );
-
- // Do the convolution.
- let mut r = 0.0;
- let mut g = 0.0;
- let mut b = 0.0;
- let mut a = 0.0;
-
- for (x, y, pixel) in
- PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
- {
- let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
- let kernel_y = (kernel_bounds.y1 - y - 1) as usize;
-
- r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
- g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
- b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];
-
- if !self.preserve_alpha {
- a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
+ surface.modify(&mut |data, stride| {
+ for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
+ // Compute the convolution rectangle bounds.
+ let kernel_bounds = IRect::new(
+ x as i32 - self.target_x.unwrap() as i32,
+ y as i32 - self.target_y.unwrap() as i32,
+ x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
+ y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
+ );
+
+ // Do the convolution.
+ let mut r = 0.0;
+ let mut g = 0.0;
+ let mut b = 0.0;
+ let mut a = 0.0;
+
+ for (x, y, pixel) in
+ PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
+ {
+ let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
+ let kernel_y = (kernel_bounds.y1 - y - 1) as usize;
+
+ r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
+ g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
+ b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];
+
+ if !self.preserve_alpha {
+ a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
+ }
}
- }
- // If preserve_alpha is true, set a to the source alpha value.
- if self.preserve_alpha {
- a = f64::from(pixel.a) / 255.0;
- } else {
- a = a / self.divisor.unwrap() + self.bias;
- }
+ // If preserve_alpha is true, set a to the source alpha value.
+ if self.preserve_alpha {
+ a = f64::from(pixel.a) / 255.0;
+ } else {
+ a = a / self.divisor.unwrap() + self.bias;
+ }
- let clamped_a = clamp(a, 0.0, 1.0);
+ let clamped_a = clamp(a, 0.0, 1.0);
- let compute = |x| {
- let x = x / self.divisor.unwrap() + self.bias * a;
+ let compute = |x| {
+ let x = x / self.divisor.unwrap() + self.bias * a;
- let x = if self.preserve_alpha {
- // Premultiply the output value.
- clamp(x, 0.0, 1.0) * clamped_a
- } else {
- clamp(x, 0.0, clamped_a)
- };
+ let x = if self.preserve_alpha {
+ // Premultiply the output value.
+ clamp(x, 0.0, 1.0) * clamped_a
+ } else {
+ clamp(x, 0.0, clamped_a)
+ };
- ((x * 255.0) + 0.5) as u8
- };
+ ((x * 255.0) + 0.5) as u8
+ };
- let output_pixel = Pixel {
- r: compute(r),
- g: compute(g),
- b: compute(b),
- a: ((clamped_a * 255.0) + 0.5) as u8,
- };
+ let output_pixel = Pixel {
+ r: compute(r),
+ g: compute(g),
+ b: compute(b),
+ a: ((clamped_a * 255.0) + 0.5) as u8,
+ };
- surface.set_pixel(output_pixel, x, y);
- }
+ data.set_pixel(stride, output_pixel, x, y);
+ }
+ });
let mut surface = surface.share()?;
diff --git a/rsvg_internals/src/filters/morphology.rs b/rsvg_internals/src/filters/morphology.rs
index a2ab7fa2..0fed43b7 100644
--- a/rsvg_internals/src/filters/morphology.rs
+++ b/rsvg_internals/src/filters/morphology.rs
@@ -12,7 +12,7 @@ use crate::rect::IRect;
use crate::surface_utils::{
iterators::{PixelRectangle, Pixels},
shared_surface::ExclusiveImageSurface,
- EdgeMode, Pixel,
+ EdgeMode, ImageSurfaceDataExt, Pixel,
};
use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -98,44 +98,46 @@ impl FilterEffect for FeMorphology {
input.surface().surface_type(),
)?;
- for (x, y, _pixel) in Pixels::within(input.surface(), bounds) {
- // Compute the kernel rectangle bounds.
- let kernel_bounds = IRect::new(
- (f64::from(x) - rx).floor() as i32,
- (f64::from(y) - ry).floor() as i32,
- (f64::from(x) + rx).ceil() as i32 + 1,
- (f64::from(y) + ry).ceil() as i32 + 1,
- );
-
- // Compute the new pixel values.
- let initial = match self.operator {
- Operator::Erode => u8::max_value(),
- Operator::Dilate => u8::min_value(),
- };
-
- let mut output_pixel = Pixel {
- r: initial,
- g: initial,
- b: initial,
- a: initial,
- };
-
- for (_x, _y, pixel) in
- PixelRectangle::within(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
- {
- let op = match self.operator {
- Operator::Erode => min,
- Operator::Dilate => max,
+ surface.modify(&mut |data, stride| {
+ for (x, y, _pixel) in Pixels::within(input.surface(), bounds) {
+ // Compute the kernel rectangle bounds.
+ let kernel_bounds = IRect::new(
+ (f64::from(x) - rx).floor() as i32,
+ (f64::from(y) - ry).floor() as i32,
+ (f64::from(x) + rx).ceil() as i32 + 1,
+ (f64::from(y) + ry).ceil() as i32 + 1,
+ );
+
+ // Compute the new pixel values.
+ let initial = match self.operator {
+ Operator::Erode => u8::max_value(),
+ Operator::Dilate => u8::min_value(),
};
- output_pixel.r = op(output_pixel.r, pixel.r);
- output_pixel.g = op(output_pixel.g, pixel.g);
- output_pixel.b = op(output_pixel.b, pixel.b);
- output_pixel.a = op(output_pixel.a, pixel.a);
- }
+ let mut output_pixel = Pixel {
+ r: initial,
+ g: initial,
+ b: initial,
+ a: initial,
+ };
- surface.set_pixel(output_pixel, x, y);
- }
+ for (_x, _y, pixel) in
+ PixelRectangle::within(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
+ {
+ let op = match self.operator {
+ Operator::Erode => min,
+ Operator::Dilate => max,
+ };
+
+ output_pixel.r = op(output_pixel.r, pixel.r);
+ output_pixel.g = op(output_pixel.g, pixel.g);
+ output_pixel.b = op(output_pixel.b, pixel.b);
+ output_pixel.a = op(output_pixel.a, pixel.a);
+ }
+
+ data.set_pixel(stride, output_pixel, x, y);
+ }
+ });
Ok(FilterResult {
name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/turbulence.rs b/rsvg_internals/src/filters/turbulence.rs
index 26b3fc18..b8046a22 100644
--- a/rsvg_internals/src/filters/turbulence.rs
+++ b/rsvg_internals/src/filters/turbulence.rs
@@ -8,7 +8,7 @@ use crate::parsers::{NumberOptionalNumber, Parse, ParseValue};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{
shared_surface::{ExclusiveImageSurface, SurfaceType},
- Pixel,
+ ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;
@@ -364,38 +364,40 @@ impl FilterEffect for FeTurbulence {
surface_type,
)?;
- for y in bounds.y_range() {
- for x in bounds.x_range() {
- let point = affine.transform_point(f64::from(x), f64::from(y));
- let point = [point.0, point.1];
-
- let generate = |color_channel| {
- let v = noise_generator.turbulence(
- color_channel,
- point,
- f64::from(x - bounds.x0),
- f64::from(y - bounds.y0),
- );
-
- let v = match self.type_ {
- NoiseType::FractalNoise => (v * 255.0 + 255.0) / 2.0,
- NoiseType::Turbulence => v * 255.0,
+ surface.modify(&mut |data, stride| {
+ for y in bounds.y_range() {
+ for x in bounds.x_range() {
+ let point = affine.transform_point(f64::from(x), f64::from(y));
+ let point = [point.0, point.1];
+
+ let generate = |color_channel| {
+ let v = noise_generator.turbulence(
+ color_channel,
+ point,
+ f64::from(x - bounds.x0),
+ f64::from(y - bounds.y0),
+ );
+
+ let v = match self.type_ {
+ NoiseType::FractalNoise => (v * 255.0 + 255.0) / 2.0,
+ NoiseType::Turbulence => v * 255.0,
+ };
+
+ (clamp(v, 0.0, 255.0) + 0.5) as u8
};
- (clamp(v, 0.0, 255.0) + 0.5) as u8
- };
+ let pixel = Pixel {
+ r: generate(0),
+ g: generate(1),
+ b: generate(2),
+ a: generate(3),
+ }
+ .premultiply();
- let pixel = Pixel {
- r: generate(0),
- g: generate(1),
- b: generate(2),
- a: generate(3),
+ data.set_pixel(stride, pixel, x as u32, y as u32);
}
- .premultiply();
-
- surface.set_pixel(pixel, x as u32, y as u32);
}
- }
+ });
Ok(FilterResult {
name: self.base.result.clone(),
diff --git a/rsvg_internals/src/surface_utils/shared_surface.rs
b/rsvg_internals/src/surface_utils/shared_surface.rs
index 292c0c76..ef7d089e 100644
--- a/rsvg_internals/src/surface_utils/shared_surface.rs
+++ b/rsvg_internals/src/surface_utils/shared_surface.rs
@@ -1159,37 +1159,39 @@ pub fn composite_arithmetic(
k3: f64,
k4: f64,
) {
- for (x, y, pixel, pixel_2) in
- Pixels::within(surface1, bounds).map(|(x, y, p)| (x, y, p, surface2.get_pixel(x, y)))
- {
- let i1a = f64::from(pixel.a) / 255f64;
- let i2a = f64::from(pixel_2.a) / 255f64;
- let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
- let oa = clamp(oa, 0f64, 1f64);
-
- // Contents of image surfaces are transparent by default, so if the resulting pixel is
- // transparent there's no need to do anything.
- if oa > 0f64 {
- let compute = |i1, i2| {
- let i1 = f64::from(i1) / 255f64;
- let i2 = f64::from(i2) / 255f64;
-
- let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
- let o = clamp(o, 0f64, oa);
-
- ((o * 255f64) + 0.5) as u8
- };
+ output_surface.modify(&mut |data, stride| {
+ for (x, y, pixel, pixel_2) in
+ Pixels::within(surface1, bounds).map(|(x, y, p)| (x, y, p, surface2.get_pixel(x, y)))
+ {
+ let i1a = f64::from(pixel.a) / 255f64;
+ let i2a = f64::from(pixel_2.a) / 255f64;
+ let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
+ let oa = clamp(oa, 0f64, 1f64);
+
+ // Contents of image surfaces are transparent by default, so if the resulting pixel is
+ // transparent there's no need to do anything.
+ if oa > 0f64 {
+ let compute = |i1, i2| {
+ let i1 = f64::from(i1) / 255f64;
+ let i2 = f64::from(i2) / 255f64;
+
+ let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
+ let o = clamp(o, 0f64, oa);
+
+ ((o * 255f64) + 0.5) as u8
+ };
- let output_pixel = Pixel {
- r: compute(pixel.r, pixel_2.r),
- g: compute(pixel.g, pixel_2.g),
- b: compute(pixel.b, pixel_2.b),
- a: ((oa * 255f64) + 0.5) as u8,
- };
+ let output_pixel = Pixel {
+ r: compute(pixel.r, pixel_2.r),
+ g: compute(pixel.g, pixel_2.g),
+ b: compute(pixel.b, pixel_2.b),
+ a: ((oa * 255f64) + 0.5) as u8,
+ };
- output_surface.set_pixel(output_pixel, x, y);
+ data.set_pixel(stride, output_pixel, x, y);
+ }
}
- }
+ });
}
impl ImageSurface<Exclusive> {
@@ -1236,11 +1238,16 @@ impl ImageSurface<Exclusive> {
self.surface.get_data().unwrap()
}
- /// Sets the pixel at the given coordinates. Assumes the `ARgb32` format.
+ /// Modify the image data
#[inline]
- pub fn set_pixel(&mut self, pixel: Pixel, x: u32, y: u32) {
- let stride = self.stride as usize;
- self.get_data().set_pixel(stride, pixel, x, y);
+ pub fn modify(
+ &mut self,
+ draw_fn: &mut dyn FnMut(&mut cairo::ImageSurfaceData, usize),
+ ) {
+ let stride = self.stride() as usize;
+ let mut data = self.get_data();
+
+ draw_fn(&mut data, stride)
}
/// Draw on the surface using cairo
diff --git a/rsvg_internals/src/surface_utils/srgb.rs b/rsvg_internals/src/surface_utils/srgb.rs
index 462fe94a..b88f486e 100644
--- a/rsvg_internals/src/surface_utils/srgb.rs
+++ b/rsvg_internals/src/surface_utils/srgb.rs
@@ -6,7 +6,7 @@ use crate::rect::IRect;
use crate::surface_utils::{
iterators::Pixels,
shared_surface::{ExclusiveImageSurface, SharedImageSurface, SurfaceType},
- Pixel,
+ ImageSurfaceDataExt, Pixel,
};
// Include the linearization and unlinearization tables.
@@ -32,28 +32,30 @@ pub fn map_unpremultiplied_components_loop<F: Fn(u8) -> u8>(
bounds: IRect,
f: F,
) {
- for (x, y, pixel) in Pixels::within(surface, bounds) {
- if pixel.a > 0 {
- let alpha = f64::from(pixel.a) / 255f64;
+ output_surface.modify(&mut |data, stride| {
+ for (x, y, pixel) in Pixels::within(surface, bounds) {
+ if pixel.a > 0 {
+ let alpha = f64::from(pixel.a) / 255f64;
- let compute = |x| {
- let x = f64::from(x) / alpha; // Unpremultiply alpha.
- let x = (x + 0.5) as u8; // Round to nearest u8.
- let x = f(x);
- let x = f64::from(x) * alpha; // Premultiply alpha again.
- (x + 0.5) as u8
- };
+ let compute = |x| {
+ let x = f64::from(x) / alpha; // Unpremultiply alpha.
+ let x = (x + 0.5) as u8; // Round to nearest u8.
+ let x = f(x);
+ let x = f64::from(x) * alpha; // Premultiply alpha again.
+ (x + 0.5) as u8
+ };
- let output_pixel = Pixel {
- r: compute(pixel.r),
- g: compute(pixel.g),
- b: compute(pixel.b),
- a: pixel.a,
- };
+ let output_pixel = Pixel {
+ r: compute(pixel.r),
+ g: compute(pixel.g),
+ b: compute(pixel.b),
+ a: pixel.a,
+ };
- output_surface.set_pixel(output_pixel, x, y);
+ data.set_pixel(stride, output_pixel, x, y);
+ }
}
- }
+ });
}
/// Applies the function to each pixel component after unpremultiplying.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]