Implement `Image::from_peniko_image` Probably a temporary method until there's better resource binding; in the meantime this is useful for clients already using `Peniko::Image`. Perhaps `Pixmap` should get a method to do the conversion to premultiplied RGBA8 from `&[Rgba8]`, or perhaps `Vec<Rgba8>` using Bytemuck with the `extern_crate_alloc` feature (though the latter doesn't help with `Peniko::Image`, which stores data in an `Arc`).
diff --git a/sparse_strips/vello_common/src/paint.rs b/sparse_strips/vello_common/src/paint.rs index 31c5970..26dd1fb 100644 --- a/sparse_strips/vello_common/src/paint.rs +++ b/sparse_strips/vello_common/src/paint.rs
@@ -64,6 +64,58 @@ pub quality: ImageQuality, } +impl Image { + /// Convert a [`peniko::Image`] to an [`Image`]. + /// + /// This is a somewhat lossy conversion, as the image data data is transformed to + /// [premultiplied RGBA8](`PremulRgba8`). + /// + /// # Panics + /// + /// This panics if `image` has a `width` or `height` greater than `u16::MAX`. + pub fn from_peniko_image(image: &peniko::Image) -> Self { + if image.format != peniko::ImageFormat::Rgba8 { + unimplemented!("Unsupported image format: {:?}", image.format); + } + + assert!( + image.width <= u16::MAX as u32 && image.height <= u16::MAX as u32, + "The image is too big. Its width and height can be no larger than {} pixels.", + u16::MAX, + ); + let width = image.width.try_into().unwrap(); + let height = image.height.try_into().unwrap(); + + #[expect(clippy::cast_possible_truncation, reason = "deliberate quantization")] + let global_alpha = u16::from((image.alpha * 255. + 0.5) as u8); + + #[expect(clippy::cast_possible_truncation, reason = "This cannot overflow.")] + let pixels = image + .data + .data() + .chunks_exact(4) + .map(|rgba| { + let alpha = ((u16::from(rgba[3]) * global_alpha) / 255) as u8; + let multiply = |component| ((u16::from(alpha) * u16::from(component)) / 255) as u8; + PremulRgba8 { + r: multiply(rgba[0]), + g: multiply(rgba[1]), + b: multiply(rgba[2]), + a: alpha, + } + }) + .collect(); + let pixmap = Pixmap::from_parts(pixels, width, height); + + Self { + pixmap: Arc::new(pixmap), + x_extend: image.x_extend, + y_extend: image.y_extend, + quality: image.quality, + } + } +} + /// A premultiplied color. #[derive(Debug, Clone, PartialEq, Copy)] pub struct PremulColor {