From f8895d8d1ee6d4fb9638a69f29d81f15b69488b6 Mon Sep 17 00:00:00 2001 From: Alisher Galiev Date: Wed, 30 Jul 2025 09:27:44 +0500 Subject: [PATCH] Add Pixmap::take_demultiplied to get raw, demultiplied pixel data --- src/pixmap.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/pixmap.rs b/src/pixmap.rs index 7217995..c914add 100644 --- a/src/pixmap.rs +++ b/src/pixmap.rs @@ -260,6 +260,22 @@ impl Pixmap { self.data } + /// Consumes the pixmap and returns the internal data as demultiplied RGBA bytes. + /// + /// Byteorder: RGBA + pub fn take_demultiplied(mut self) -> Vec { + // Demultiply alpha. + // + // RasterPipeline is 15% faster here, but produces slightly different results + // due to rounding. So we stick with this method for now. + for pixel in self.pixels_mut() { + let c = pixel.demultiply(); + *pixel = + PremultipliedColorU8::from_rgba_unchecked(c.red(), c.green(), c.blue(), c.alpha()); + } + self.data + } + /// Returns a copy of the pixmap that intersects the `rect`. /// /// Returns `None` when `Pixmap`'s rect doesn't contain `rect`. @@ -394,17 +410,7 @@ impl<'a> PixmapRef<'a> { // Sadly, we have to copy the pixmap here, because of demultiplication. // Not sure how to avoid this. // TODO: remove allocation - let mut tmp_pixmap = self.to_owned(); - - // Demultiply alpha. - // - // RasterPipeline is 15% faster here, but produces slightly different results - // due to rounding. So we stick with this method for now. - for pixel in tmp_pixmap.pixels_mut() { - let c = pixel.demultiply(); - *pixel = - PremultipliedColorU8::from_rgba_unchecked(c.red(), c.green(), c.blue(), c.alpha()); - } + let demultiplied_data = self.to_owned().take_demultiplied(); let mut data = Vec::new(); { @@ -412,7 +418,7 @@ impl<'a> PixmapRef<'a> { encoder.set_color(png::ColorType::Rgba); encoder.set_depth(png::BitDepth::Eight); let mut writer = encoder.write_header()?; - writer.write_image_data(&tmp_pixmap.data)?; + writer.write_image_data(&demultiplied_data)?; } Ok(data)