Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
3.6 kB · 86 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687//! Widening a decoded 8-bit PNG frame to RGBA.//!//! `camo` and `flare` both decode a player-supplied PNG with the same//! `normalize_to_color8() | ALPHA` transformations and then need the same//! step: turning whatever 8-bit colour type came out of that into RGBA//! bytes to re-encode. The only thing that differs between the two call//! sites is the image's dimensions, so this is that step, shared.
/// Widens a decoded 8-bit frame of `width` x `height` pixels to RGBA. `None`/// if `data`'s length does not match what `color` and the dimensions imply,/// or if `color` is `Indexed` — the decoder's transformations should already/// have removed it, but this is not the place to assume that held.pub fn to_rgba(data: &[u8], color: png::ColorType, width: u32, height: u32) -> Option<Vec<u8>> { let pixels = (width as usize).checked_mul(height as usize)?; match color { png::ColorType::Rgba if data.len() == pixels * 4 => Some(data.to_vec()), png::ColorType::Rgb if data.len() == pixels * 3 => Some( data.chunks_exact(3) .flat_map(|p| [p[0], p[1], p[2], 255]) .collect(), ), png::ColorType::GrayscaleAlpha if data.len() == pixels * 2 => Some( data.chunks_exact(2) .flat_map(|p| [p[0], p[0], p[0], p[1]]) .collect(), ), png::ColorType::Grayscale if data.len() == pixels => { Some(data.iter().flat_map(|&g| [g, g, g, 255]).collect()) } _ => None, }}
#[cfg(test)]mod tests { use super::*;
/// Pins the byte layout `to_rgba` produces, at both the size `camo` calls /// it with and a size shaped like a `flare` screenshot — a regression in /// either caller's PNG path should show up here first. #[test] fn widens_every_colour_type_at_camo_and_flare_sizes() { for (width, height) in [(84u32, 72u32), (320, 200)] { let pixels = (width * height) as usize;
let rgb: Vec<u8> = (0..pixels).flat_map(|i| [i as u8, 1, 2]).collect(); assert_eq!( to_rgba(&rgb, png::ColorType::Rgb, width, height).unwrap(), rgb.chunks_exact(3) .flat_map(|p| [p[0], p[1], p[2], 255]) .collect::<Vec<u8>>() );
let gray: Vec<u8> = (0..pixels).map(|i| i as u8).collect(); assert_eq!( to_rgba(&gray, png::ColorType::Grayscale, width, height).unwrap(), gray.iter() .flat_map(|&g| [g, g, g, 255]) .collect::<Vec<u8>>() );
let gray_alpha: Vec<u8> = (0..pixels).flat_map(|i| [i as u8, 9]).collect(); assert_eq!( to_rgba(&gray_alpha, png::ColorType::GrayscaleAlpha, width, height).unwrap(), gray_alpha .chunks_exact(2) .flat_map(|p| [p[0], p[0], p[0], p[1]]) .collect::<Vec<u8>>() );
let rgba: Vec<u8> = (0..pixels).flat_map(|i| [i as u8, 1, 2, 3]).collect(); assert_eq!( to_rgba(&rgba, png::ColorType::Rgba, width, height).unwrap(), rgba );
assert!(to_rgba(&gray, png::ColorType::Indexed, width, height).is_none()); } }
#[test] fn wrong_length_data_is_refused() { assert!(to_rgba(&[0u8; 3], png::ColorType::Rgba, 84, 72).is_none()); assert!(to_rgba(&[], png::ColorType::Grayscale, 320, 200).is_none()); }}