Skip to content

Commit

Permalink
Add support for parsing iCCP chunk.
Browse files Browse the repository at this point in the history
  • Loading branch information
jrmuizel committed Feb 19, 2021
1 parent 043853f commit f4bd5c3
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub const cHRM: ChunkType = ChunkType([b'c', b'H', b'R', b'M']);
pub const gAMA: ChunkType = ChunkType([b'g', b'A', b'M', b'A']);
/// sRGB color space chunk
pub const sRGB: ChunkType = ChunkType([b's', b'R', b'G', b'B']);
/// ICC profile chunk
pub const iCCP: ChunkType = ChunkType([b'i', b'C', b'C', b'P']);

// -- Extension chunks --

Expand Down
3 changes: 3 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ pub struct Info {
///
/// Presence of this value also indicates that the image conforms to the SRGB color space.
pub srgb: Option<SrgbRenderingIntent>,
/// The ICC profile for the image.
pub icc_profile: Option<Vec<u8>>,
}

impl Default for Info {
Expand All @@ -518,6 +520,7 @@ impl Default for Info {
filter: InfoFilterType::Adaptive,
source_chromaticities: None,
srgb: None,
icc_profile: None,
}
}
}
Expand Down
44 changes: 44 additions & 0 deletions src/decoder/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ impl StreamingDecoder {
chunk::fcTL => self.parse_fctl(),
chunk::cHRM => self.parse_chrm(),
chunk::sRGB => self.parse_srgb(),
chunk::iCCP => self.parse_iccp(),
_ => Ok(Decoded::PartialChunk(type_str)),
} {
Err(err) => {
Expand Down Expand Up @@ -911,6 +912,49 @@ impl StreamingDecoder {
}
}

fn parse_iccp(&mut self) -> Result<Decoded, DecodingError> {
if self.have_idat {
Err(DecodingError::Format(
FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(),
))
} else {
let mut buf = &self.current_chunk.raw_bytes[..];

// read profile name
let _: u8 = buf.read_be()?;
for _ in 1..80 {
let raw: u8 = buf.read_be()?;
if raw == 0 {
break;
}
}

match buf.read_be()? {
// compression method
0u8 => (),
n => {
return Err(DecodingError::Format(
FormatErrorInner::UnknownCompressionMethod(n).into(),
))
}
}

let mut profile = Vec::new();
let mut inflater = ZlibStream::new();
while !buf.is_empty() {
let consumed_bytes = inflater.decompress(buf, &mut profile)?;
if profile.len() > 8000000 {
// TODO: this should use Limits.bytes
return Err(DecodingError::LimitsExceeded);
}
buf = &buf[consumed_bytes..];
}

self.info.as_mut().unwrap().icc_profile = Some(profile);
Ok(Decoded::Nothing)
}
}

fn parse_ihdr(&mut self) -> Result<Decoded, DecodingError> {
// TODO: check if color/bit depths combination is valid
let mut buf = &self.current_chunk.raw_bytes[..];
Expand Down

0 comments on commit f4bd5c3

Please sign in to comment.