use super::ImageError;
pub(super) const PNG_SIGNATURE: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
pub(super) fn parse_png(bytes: &[u8]) -> Result<(u32, u32, u8), ImageError> {
if bytes.len() < 8 + 8 + 13 || bytes[0..8] != PNG_SIGNATURE {
return Err(ImageError::Malformed);
}
let chunk_len = usize::try_from(u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]])).map_err(|_| ImageError::Malformed)?;
if &bytes[12..16] != b"IHDR" || chunk_len != 13 {
return Err(ImageError::Malformed);
}
let ihdr = &bytes[16..16 + 13];
let width = u32::from_be_bytes([ihdr[0], ihdr[1], ihdr[2], ihdr[3]]);
let height = u32::from_be_bytes([ihdr[4], ihdr[5], ihdr[6], ihdr[7]]);
let bit_depth = ihdr[8];
let color_type = ihdr[9];
let interlace = ihdr[12];
if width == 0 || height == 0 {
return Err(ImageError::Malformed);
}
if interlace != 0 || bit_depth != 8 {
return Err(ImageError::UnsupportedPng);
}
let components = match color_type {
2 => 3, 6 => 4, _ => return Err(ImageError::UnsupportedPng), };
Ok((width, height, components))
}