use crate::render::Bounds;
pub fn rgba_to_argb8888(rgba: &[u8]) -> Vec<u8> {
let mut out = vec![0u8; rgba.len()];
write_argb8888(rgba, &mut out);
out
}
#[hotpath::measure]
pub fn write_argb8888(rgba: &[u8], dst: &mut [u8]) {
for (src, out) in rgba
.as_chunks::<4>()
.0
.iter()
.zip(dst.as_chunks_mut::<4>().0)
{
out[0] = src[2]; out[1] = src[1]; out[2] = src[0]; out[3] = src[3]; }
}
#[hotpath::measure]
pub fn write_argb8888_region(rgba: &[u8], dst: &mut [u8], width: u32, region: Bounds) {
let stride = width as usize * 4;
if stride == 0 {
return;
}
let rows = rgba.len().min(dst.len()) / stride;
let x = region.x.min(width) as usize;
let right = (region.x + region.width).min(width) as usize;
let bottom = (region.y as usize + region.height as usize).min(rows);
for row in region.y as usize..bottom {
let span = row * stride + x * 4..row * stride + right * 4;
write_argb8888(&rgba[span.clone()], &mut dst[span]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn swaps_red_and_blue_preserving_alpha() {
let rgba = [0x10, 0x20, 0x30, 0x40, 0xAA, 0xBB, 0xCC, 0xDD];
let out = rgba_to_argb8888(&rgba);
assert_eq!(out, vec![0x30, 0x20, 0x10, 0x40, 0xCC, 0xBB, 0xAA, 0xDD]);
}
#[test]
fn write_into_canvas_only_touches_pixel_bytes() {
let rgba = [1, 2, 3, 4];
let mut dst = [0xFFu8; 8];
write_argb8888(&rgba, &mut dst);
assert_eq!(&dst[..4], &[3, 2, 1, 4]);
assert_eq!(&dst[4..], &[0xFF, 0xFF, 0xFF, 0xFF]);
}
#[test]
fn a_region_write_converts_only_that_rectangle() {
let rgba: Vec<u8> = (0..4 * 3 * 4).map(|i| i as u8).collect();
let mut dst = vec![0xEE_u8; rgba.len()];
write_argb8888_region(&rgba, &mut dst, 4, Bounds::new(1, 1, 2, 2));
let full = rgba_to_argb8888(&rgba);
for (i, (got, want)) in dst
.as_chunks::<4>()
.0
.iter()
.zip(full.as_chunks::<4>().0)
.enumerate()
{
let (x, y) = (i % 4, i / 4);
if (1..3).contains(&x) && (1..3).contains(&y) {
assert_eq!(got, want, "pixel ({x}, {y})");
} else {
assert_eq!(got, &[0xEE; 4], "pixel ({x}, {y}) outside the region");
}
}
write_argb8888_region(&rgba, &mut dst, 4, Bounds::new(3, 2, 10, 10));
assert_eq!(&dst[(2 * 4 + 3) * 4..], &full[(2 * 4 + 3) * 4..]);
}
#[test]
fn output_length_matches_input() {
let rgba = vec![0u8; 320 * 32 * 4];
assert_eq!(rgba_to_argb8888(&rgba).len(), rgba.len());
}
}