use image::RgbaImage;
pub fn bgra_to_rgba(width: u32, height: u32, mut buf: Vec<u8>) -> Result<RgbaImage, String> {
let len = buf.len();
for px in buf.chunks_exact_mut(4) {
px.swap(0, 2);
}
RgbaImage::from_vec(width, height, buf)
.ok_or_else(|| format!("BGRA buffer length {len} does not match {width}x{height}x4", len = len))
}
pub fn remove_row_padding(
width: usize,
height: usize,
bytes_per_row: usize,
buf: Vec<u8>,
) -> Vec<u8> {
let needed = width * 4;
if bytes_per_row == 0 || bytes_per_row < needed || bytes_per_row == needed {
return buf;
}
let mut out = Vec::with_capacity(needed * height);
for row in buf.chunks_exact(bytes_per_row) {
out.extend_from_slice(&row[..needed.min(row.len())]);
}
out
}
pub fn vec_to_rgba(width: u32, height: u32, buf: Vec<u8>) -> Result<RgbaImage, String> {
let len = buf.len();
RgbaImage::from_vec(width, height, buf)
.ok_or_else(|| format!("Buffer length {len} does not match {width}x{height}x4"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bgra_swap() {
let img = bgra_to_rgba(2, 1, vec![1, 2, 3, 4, 255, 254, 253, 252]).unwrap();
assert_eq!(
img.into_raw(),
vec![3, 2, 1, 4, 253, 254, 255, 252]
);
}
#[test]
fn padding_striped() {
let cleaned = remove_row_padding(2, 2, 9, vec![
1, 2, 3, 4, 5, 6, 7, 8, 9,
11, 12, 13, 14, 15, 16, 17, 18, 19,
]);
assert_eq!(cleaned, vec![1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18]);
}
#[test]
fn padding_passthrough_when_none() {
let data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
let out = remove_row_padding(2, 1, 8, data.clone());
assert_eq!(out, data);
}
}