TODO
diff --git a/sparse_strips/vello_bench/src/pixmap.rs b/sparse_strips/vello_bench/src/pixmap.rs index a0fecd5..dfd3f6d 100644 --- a/sparse_strips/vello_bench/src/pixmap.rs +++ b/sparse_strips/vello_bench/src/pixmap.rs
@@ -41,7 +41,7 @@ group.bench_function("take_unpremultiplied", |b| { b.iter_batched( || pixmap.clone(), - |pixmap| black_box(pixmap.take_unpremultiplied()), + |pixmap| black_box(pixmap.take(ImageAlphaType::Alpha)), BatchSize::LargeInput, ); });
diff --git a/sparse_strips/vello_common/src/pixmap.rs b/sparse_strips/vello_common/src/pixmap.rs index ae65391..95b05da 100644 --- a/sparse_strips/vello_common/src/pixmap.rs +++ b/sparse_strips/vello_common/src/pixmap.rs
@@ -9,10 +9,7 @@ use std::io::{BufRead, Seek}; use crate::fearless_simd::{Level, Simd, SimdBase, SimdInt, SimdMask, dispatch, mask8x16}; -use crate::peniko::{ - ImageAlphaType, - color::{PremulRgba8, Rgba8}, -}; +use crate::peniko::{ImageAlphaType, color::PremulRgba8}; use crate::util::Div255Ext; #[cfg(feature = "png")] @@ -312,7 +309,7 @@ encoder.set_color(png::ColorType::Rgba); encoder.set_depth(png::BitDepth::Eight); let mut writer = encoder.write_header()?; - writer.write_image_data(bytemuck::cast_slice(&self.take_unpremultiplied()))?; + writer.write_image_data(&self.take(ImageAlphaType::Alpha))?; writer.finish().map(|_| data) } @@ -386,37 +383,30 @@ self.buf[idx] = pixel; } - /// Consume the pixmap, returning the data as the underlying [`Vec`] of premultiplied RGBA8. + /// Consume the pixmap, returning its RGBA8 bytes with the requested alpha representation. /// - /// The pixels are in row-major order. - pub fn take(self) -> Vec<PremulRgba8> { - self.buf - } - - /// Consume the pixmap, returning the data as (unpremultiplied) RGBA8. - /// - /// Not fast, but useful for saving to PNG etc. - /// - /// The pixels are in row-major order. - pub fn take_unpremultiplied(self) -> Vec<Rgba8> { - self.buf - .into_iter() - .map(|PremulRgba8 { r, g, b, a }| { - let alpha = 255.0 / f32::from(a); - if a != 0 { - #[expect(clippy::cast_possible_truncation, reason = "deliberate quantization")] - let unpremultiply = |component| (f32::from(component) * alpha + 0.5) as u8; - Rgba8 { - r: unpremultiply(r), - g: unpremultiply(g), - b: unpremultiply(b), - a, + /// The pixels are in row-major order. Note that it's always cheapest to call this method + /// with [`ImageAlphaType::AlphaPremultiplied`] since this is the internal representation + /// of the pixmap. + pub fn take(self, alpha_type: ImageAlphaType) -> Vec<u8> { + let mut data = bytemuck::cast_vec(self.buf); + if alpha_type == ImageAlphaType::Alpha { + for pixel in data.chunks_exact_mut(4) { + let alpha = pixel[3]; + if alpha != 0 { + let scale = 255.0 / f32::from(alpha); + for component in &mut pixel[..3] { + #[expect( + clippy::cast_possible_truncation, + reason = "deliberate quantization" + )] + let unpremultiplied = (f32::from(*component) * scale + 0.5) as u8; + *component = unpremultiplied; } - } else { - Rgba8 { r, g, b, a } } - }) - .collect() + } + } + data } } @@ -585,4 +575,24 @@ assert!(!pixmap.may_have_transparency()); assert_eq!(pixmap.data_as_u8_slice(), data); } + + #[test] + fn take_returns_requested_alpha_type_as_bytes() { + let data = vec![100, 50, 25, 128, 9, 8, 7, 255, 1, 2, 3, 0]; + let pixmap = Pixmap::from_parts( + data.clone(), + 3, + 1, + PixelMetadata::new(ImageAlphaType::AlphaPremultiplied, true), + ); + + assert_eq!( + pixmap.clone().take(ImageAlphaType::AlphaPremultiplied), + data + ); + assert_eq!( + pixmap.take(ImageAlphaType::Alpha), + [199, 100, 50, 128, 9, 8, 7, 255, 1, 2, 3, 0] + ); + } }
diff --git a/sparse_strips/vello_common/src/probe.rs b/sparse_strips/vello_common/src/probe.rs index 3982fff..a898644 100644 --- a/sparse_strips/vello_common/src/probe.rs +++ b/sparse_strips/vello_common/src/probe.rs
@@ -11,8 +11,8 @@ use crate::kurbo::{Affine, BezPath, Circle, Point, Rect, Shape}; use crate::paint::{Image, ImageSource, PaintType}; use crate::peniko::{ - BlendMode, ColorStop, ColorStops, Compose, Extend, Gradient, ImageQuality, ImageSampler, - LinearGradientPosition, Mix, + BlendMode, ColorStop, ColorStops, Compose, Extend, Gradient, ImageAlphaType, ImageQuality, + ImageSampler, LinearGradientPosition, Mix, }; use crate::pixmap::Pixmap; use alloc::vec::Vec; @@ -207,7 +207,7 @@ Self { width: pixmap.width(), height: pixmap.height(), - data: bytemuck::cast_slice(&pixmap.take_unpremultiplied()).to_vec(), + data: pixmap.take(ImageAlphaType::Alpha), } } }
diff --git a/sparse_strips/vello_hybrid/examples/render_to_file.rs b/sparse_strips/vello_hybrid/examples/render_to_file.rs index a075f28..f0e0ceb 100644 --- a/sparse_strips/vello_hybrid/examples/render_to_file.rs +++ b/sparse_strips/vello_hybrid/examples/render_to_file.rs
@@ -8,6 +8,7 @@ use std::io::BufWriter; use vello_common::kurbo::{Affine, Stroke}; +use vello_common::peniko::ImageAlphaType; use vello_common::pico_svg::{Item, PicoSvg}; use vello_common::pixmap::{PixelMetadata, Pixmap}; use vello_hybrid::{DimensionConstraints, Scene}; @@ -169,7 +170,7 @@ png_encoder.set_color(png::ColorType::Rgba); let mut writer = png_encoder.write_header().unwrap(); writer - .write_image_data(bytemuck::cast_slice(&pixmap.take_unpremultiplied())) + .write_image_data(&pixmap.take(ImageAlphaType::Alpha)) .unwrap(); }
diff --git a/sparse_strips/vello_sparse_tests/src/regenerate_probe_reference.rs b/sparse_strips/vello_sparse_tests/src/regenerate_probe_reference.rs index 3b2c40d..7ade707 100644 --- a/sparse_strips/vello_sparse_tests/src/regenerate_probe_reference.rs +++ b/sparse_strips/vello_sparse_tests/src/regenerate_probe_reference.rs
@@ -3,7 +3,6 @@ //! Regenerate the probe reference assets in `vello_common/assets`. -use bytemuck::cast_slice; use std::{ path::PathBuf, sync::{Arc, LazyLock}, @@ -15,7 +14,7 @@ filter_effects::Filter, kurbo::{Affine, BezPath, Rect}, paint::{ImageSource, PaintType}, - peniko::BlendMode, + peniko::{BlendMode, ImageAlphaType}, pixmap::Pixmap, probe::{self, ProbeRenderer}, }; @@ -102,7 +101,7 @@ fn build_probe_reference_data() -> ProbeReferenceData { let pixmap = render_probe_pixmap(); - let rgba = cast_slice(&pixmap.clone().take_unpremultiplied()).to_vec(); + let rgba = pixmap.clone().take(ImageAlphaType::Alpha); let png = pixmap.into_png().unwrap(); #[cfg(not(target_arch = "wasm32"))] let png = oxipng::optimize_from_memory(&png, &Options::max_compression()).unwrap();
diff --git a/sparse_strips/vello_toy/src/svg.rs b/sparse_strips/vello_toy/src/svg.rs index f3fb9a3..2dba965 100644 --- a/sparse_strips/vello_toy/src/svg.rs +++ b/sparse_strips/vello_toy/src/svg.rs
@@ -19,7 +19,7 @@ use usvg::{Node, Paint, PaintOrder}; use vello_cpu::color::AlphaColor; use vello_cpu::kurbo::{Affine, BezPath, Stroke}; -use vello_cpu::peniko::Fill; +use vello_cpu::peniko::{Fill, ImageAlphaType}; use vello_cpu::{Level, Pixmap, RenderContext, RenderSettings, Resources}; fn main() { @@ -68,14 +68,14 @@ } fn write_pixmap(pixmap: &mut Pixmap) { - let data = pixmap.clone().take_unpremultiplied(); + let data = pixmap.clone().take(ImageAlphaType::Alpha); let mut png_data = Vec::new(); let cursor = Cursor::new(&mut png_data); let encoder = PngEncoder::new(cursor); encoder .write_image( - bytemuck::cast_slice(&data), + &data, pixmap.width() as u32, pixmap.height() as u32, ExtendedColorType::Rgba8,