diff --git a/src/error.rs b/src/error.rs index 0f099d5d..550f0316 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,4 @@ +use crate::colors::{BitDepth, ColorType}; use std::error::Error; use std::fmt; @@ -11,6 +12,8 @@ pub enum PngError { InvalidData, TruncatedData, ChunkMissing(&'static str), + InvalidDepthForType(BitDepth, ColorType), + IncorrectDataLength(usize, usize), Other(Box), } @@ -30,6 +33,14 @@ impl fmt::Display for PngError { } PngError::APNGNotSupported => f.write_str("APNG files are not (yet) supported"), PngError::ChunkMissing(s) => write!(f, "Chunk {} missing or empty", s), + PngError::InvalidDepthForType(d, ref c) => { + write!(f, "Invalid bit depth {} for color type {}", d, c) + } + PngError::IncorrectDataLength(l1, l2) => write!( + f, + "Data length {} does not match the expected length {}", + l1, l2 + ), PngError::Other(ref s) => f.write_str(s), } } diff --git a/src/lib.rs b/src/lib.rs index b68a4528..db566f46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,6 +331,24 @@ impl RawImage { bit_depth: BitDepth, data: Vec, ) -> Result { + // Validate bit depth + let valid_depth = match color_type { + ColorType::Grayscale { .. } => true, + ColorType::Indexed { .. } => (bit_depth as u8) <= 8, + _ => (bit_depth as u8) >= 8, + }; + if !valid_depth { + return Err(PngError::InvalidDepthForType(bit_depth, color_type)); + } + + // Validate data length + let bpp = bit_depth as usize * color_type.channels_per_pixel() as usize; + let row_bytes = (bpp * width as usize + 7) / 8; + let expected_len = row_bytes * height as usize; + if data.len() != expected_len { + return Err(PngError::IncorrectDataLength(data.len(), expected_len)); + } + Ok(Self { png: Arc::new(PngImage { ihdr: IhdrData {