Commit 7c92faea authored by Ivan Molodetskikh's avatar Ivan Molodetskikh

Impl set_pixel() for cairo::ImageSurfaceData

parent a03bc942
......@@ -14,7 +14,7 @@ use util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::iterators::{ImageSurfaceDataShared, Pixels};
use super::iterators::{ImageSurfaceDataExt, ImageSurfaceDataShared, Pixel, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};
/// Enumeration of the possible compositing operations.
......@@ -134,31 +134,27 @@ impl Filter for Composite {
let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
let oa = clamp(oa, 0f64, 1f64);
let output_base = y * output_stride + 4 * x;
// 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 {
output_data[output_base + 3] = (oa * 255f64).round() as u8;
// TODO: make this much better with mutable pixel iterators for output.
for (ch, &(i1, i2)) in [
(pixel.r, pixel_2.r),
(pixel.g, pixel_2.g),
(pixel.b, pixel_2.b),
].iter()
.enumerate()
{
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);
let o = (o * 255f64).round() as u8;
output_data[output_base + ch] = o;
}
(o * 255f64).round() 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).round() as u8,
};
output_data.set_pixel(output_stride, output_pixel, x, y);
}
}
}
......
//! Pixel iterators for surfaces.
use std::ops::DerefMut;
use std::slice;
use cairo;
......@@ -36,6 +37,20 @@ pub struct Pixels<'a> {
y: usize,
}
/// Extension methods for `cairo::ImageSurfaceData`.
pub trait ImageSurfaceDataExt: DerefMut<Target = [u8]> {
/// Sets the pixel at the given coordinates.
#[inline]
fn set_pixel(&mut self, stride: usize, pixel: Pixel, x: usize, y: usize) {
let base = y * stride + x * 4;
self[base + 0] = pixel.r;
self[base + 1] = pixel.g;
self[base + 2] = pixel.b;
self[base + 3] = pixel.a;
}
}
impl<'a> ImageSurfaceDataShared<'a> {
/// Creates a shared (read-only) surface data accessor for an image surface.
pub fn new(surface: &cairo::ImageSurface) -> Result<Self, FilterError> {
......@@ -127,6 +142,8 @@ impl<'a> Iterator for Pixels<'a> {
}
}
impl<'a> ImageSurfaceDataExt for cairo::ImageSurfaceData<'a> {}
#[cfg(test)]
mod tests {
use super::*;
......
......@@ -12,7 +12,7 @@ use property_bag::PropertyBag;
use util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::iterators::{ImageSurfaceDataShared, Pixels};
use super::iterators::{ImageSurfaceDataExt, ImageSurfaceDataShared, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};
/// The `feOffset` filter primitive.
......@@ -100,12 +100,7 @@ impl Filter for Offset {
for (x, y, pixel) in Pixels::new(input_data, input_bounds) {
let output_x = (x as i32 + ox) as usize;
let output_y = (y as i32 + oy) as usize;
let output_base = output_y * output_stride + output_x * 4;
output_data[output_base + 0] = pixel.r;
output_data[output_base + 1] = pixel.g;
output_data[output_base + 2] = pixel.b;
output_data[output_base + 3] = pixel.a;
output_data.set_pixel(output_stride, pixel, output_x, output_y);
}
}
......
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