#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Image {
width: u32,
height: u32,
pixels: Vec<u32>,
}
impl Image {
#[must_use]
pub fn new(width: u32, height: u32) -> Self {
if width == 0 || height == 0 {
return Self::default();
}
Self {
width,
height,
pixels: vec![0; width as usize * height as usize],
}
}
#[must_use]
pub const fn width(&self) -> u32 {
self.width
}
#[must_use]
pub const fn height(&self) -> u32 {
self.height
}
#[must_use]
pub const fn stride_bytes(&self) -> u32 {
self.width * 4
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.width == 0 || self.height == 0
}
#[must_use]
pub fn pixels(&self) -> &[u32] {
&self.pixels
}
pub fn pixels_mut(&mut self) -> &mut [u32] {
&mut self.pixels
}
}
const fn channels(px: u32) -> (u32, u32, u32, u32) {
(px >> 24, (px >> 16) & 0xff, (px >> 8) & 0xff, px & 0xff)
}
const fn div255(x: u32) -> u32 {
let t = x + 128;
(t + (t >> 8)) >> 8
}
#[must_use]
pub const fn src_over(dst: u32, src: u32) -> u32 {
let (sa, sr, sg, sb) = channels(src);
if sa == 255 {
return src;
}
if sa == 0 {
return dst;
}
let (da, dr, dg, db) = channels(dst);
let inv = 255 - sa;
((sa + div255(da * inv)) << 24)
| ((sr + div255(dr * inv)) << 16)
| ((sg + div255(dg * inv)) << 8)
| (sb + div255(db * inv))
}
#[must_use]
pub fn unpremultiply(px: u32) -> [u8; 4] {
let (a, r, g, b) = channels(px);
if a == 0 {
return [0, 0, 0, 0];
}
let straight = |c: u32| u8::try_from((((c * 255) + (a / 2)) / a).min(255)).unwrap_or(u8::MAX);
let alpha = u8::try_from(a).unwrap_or(u8::MAX);
[straight(r), straight(g), straight(b), alpha]
}