diff --git a/zune-png/src/decoder.rs b/zune-png/src/decoder.rs index 76959146..1d4c7fad 100644 --- a/zune-png/src/decoder.rs +++ b/zune-png/src/decoder.rs @@ -207,6 +207,10 @@ impl<'a> PngDecoder<'a> { self.parse_idat(header)?; } + PngChunkType::tRNS => + { + self.parse_trns(header)?; + } PngChunkType::IEND => { @@ -255,25 +259,10 @@ impl<'a> PngDecoder<'a> // runs. // - // { - // use std::fs::OpenOptions; - // use std::io::Write; - // let mut file = OpenOptions::new() - // .write(true) - // .create(true) - // .truncate(true) - // .open("/home/caleb/Documents/zune-image/zune-inflate/tests/zlib/412845_PNG.zlib") - // .unwrap(); - // - // file.write_all(&self.idat_chunks).unwrap(); - // } let mut decoder = zune_inflate::DeflateDecoder::new(&self.idat_chunks); let deflate_data = decoder.decode_zlib().unwrap(); - // let deflate_data = _decode_writer_flate(&self.idat_chunks); - // assert_eq!(deflate_data_x, deflate_data); - let info = &self.png_info; let mut img_width_bytes; @@ -407,9 +396,7 @@ impl<'a> PngDecoder<'a> // This is the loop filter, // the only trick we have is how we do get the top row // - // We do it in the following way - // 1. Iterate one stride below, chunk taking 2x width - // + // Complicated filters are handled in filters.rs let mut prev_row_start = 0; let width_stride = chunk_size - 1; @@ -427,6 +414,7 @@ impl<'a> PngDecoder<'a> out_position += width_stride; // take filter let filter_byte = in_stride[0]; + let raw = &in_stride[1..]; // get it's type let filter = FilterMethod::from_int(filter_byte) .ok_or_else(|| PngErrors::Generic(format!("Unknown filter {filter_byte}")))?; @@ -438,19 +426,19 @@ impl<'a> PngDecoder<'a> FilterMethod::None => { // memcpy - current[0..width_stride].copy_from_slice(&in_stride[1..]); + current[0..width_stride].copy_from_slice(raw); } FilterMethod::Average => { - handle_avg(prev_row, &in_stride[1..], current, components); + handle_avg(prev_row, raw, current, components); } FilterMethod::Sub => { - handle_sub(&in_stride[1..], current, components); + handle_sub(raw, current, components); } FilterMethod::Up => { - for ((filt, recon), up) in in_stride[1..].iter().zip(current).zip(prev_row) + for ((filt, recon), up) in raw.iter().zip(current).zip(prev_row) { *recon = (*filt).wrapping_add(*up) } diff --git a/zune-png/src/headers.rs b/zune-png/src/headers.rs index a3c359a9..5a7880d4 100644 --- a/zune-png/src/headers.rs +++ b/zune-png/src/headers.rs @@ -54,7 +54,7 @@ impl<'a> PngDecoder<'a> } else { - return Err(PngErrors::Generic(format!("Unknown color value {}", color))); + return Err(PngErrors::Generic(format!("Unknown color value {color}"))); } self.png_info.component = self.png_info.color.num_components(); // verify colors plus bit depths @@ -104,8 +104,7 @@ impl<'a> PngDecoder<'a> else { return Err(PngErrors::Generic(format!( - "Unknown filter method {}", - filter_method + "Unknown filter method {filter_method}" ))); } @@ -118,8 +117,7 @@ impl<'a> PngDecoder<'a> else { return Err(PngErrors::Generic(format!( - "Unknown interlace method {}", - interlace_method + "Unknown interlace method {interlace_method}", ))); } @@ -181,4 +179,43 @@ impl<'a> PngDecoder<'a> Ok(()) } + + pub(crate) fn parse_trns(&mut self, chunk: PngChunk) -> Result<(), PngErrors> + { + match self.png_info.color + { + PngColor::Luma => + { + let _grey_sample = self.stream.get_u16_be(); + } + PngColor::RGB => + { + let _red_sample = self.stream.get_u16_be(); + let _blue_sample = self.stream.get_u16_be(); + let _green_sample = self.stream.get_u16_be(); + } + PngColor::Palette => + { + if self.palette.is_empty() + { + return Err(PngErrors::GenericStatic("tRNS chunk before plTE")); + } + if self.palette.len() <= chunk.length * 4 + { + return Err(PngErrors::GenericStatic("tRNS chunk with too long entries")); + } + for i in 0..chunk.length + { + self.palette[i * 4 + 3] = self.stream.get_u8(); + } + } + _ => + { + let msg = format!("A tRNS chunk shall not appear for colour type {:?} as it is already transparent", self.png_info.color); + + return Err(PngErrors::Generic(msg)); + } + } + Ok(()) + } } diff --git a/zune-png/tests/test_filters.rs b/zune-png/tests/test_filters.rs index a9f56b49..215fe6f6 100644 --- a/zune-png/tests/test_filters.rs +++ b/zune-png/tests/test_filters.rs @@ -21,7 +21,7 @@ fn decode_ref(data: &[u8]) -> Vec fn decode_zune(data: &[u8]) -> Vec { - zune_png::PngDecoder::new(&data) + zune_png::PngDecoder::new(data) .decode() .unwrap() .u8() @@ -111,3 +111,13 @@ fn test_paeth() test_decoding(path); } } + +#[test] +fn test_black_and_white() +{ + { + let path = env!("CARGO_MANIFEST_DIR").to_string() + "/tests/png_suite/basi0g01.png"; + + test_decoding(path); + } +}