1use std::convert::TryInto;
2use std::error;
3use std::fmt;
4use std::io;
5use std::{borrow::Cow, cmp::min};
6
7use crc32fast::Hasher as Crc32;
8
9use super::zlib::ZlibStream;
10use crate::chunk::{self, ChunkType, IDAT, IEND, IHDR};
11use crate::common::{
12 AnimationControl, BitDepth, BlendOp, ColorType, DisposeOp, FrameControl, Info, ParameterError,
13 PixelDimensions, ScaledFloat, SourceChromaticities, Unit,
14};
15use crate::text_metadata::{ITXtChunk, TEXtChunk, TextDecodingError, ZTXtChunk};
16use crate::traits::ReadBytesExt;
17use crate::Limits;
18
19pub const CHUNK_BUFFER_SIZE: usize = 32 * 1024;
21
22const CHECKSUM_DISABLED: bool = cfg!(fuzzing);
27
28#[derive(Debug)]
30enum U32ValueKind {
31 Signature1stU32,
34 Signature2ndU32,
37 Length,
40 Type { length: u32 },
43 Crc(ChunkType),
46 ApngSequenceNumber,
49}
50
51#[derive(Debug)]
52enum State {
53 U32 {
57 kind: U32ValueKind,
58 bytes: [u8; 4],
59 accumulated_count: usize,
60 },
61 ReadChunkData(ChunkType),
64 ParseChunkData(ChunkType),
67 ImageData(ChunkType),
70}
71
72impl State {
73 fn new_u32(kind: U32ValueKind) -> Self {
74 Self::U32 {
75 kind,
76 bytes: [0; 4],
77 accumulated_count: 0,
78 }
79 }
80}
81
82#[derive(Debug)]
83pub enum Decoded {
85 Nothing,
87 Header(u32, u32, BitDepth, ColorType, bool),
88 ChunkBegin(u32, ChunkType),
89 ChunkComplete(u32, ChunkType),
90 PixelDimensions(PixelDimensions),
91 AnimationControl(AnimationControl),
92 FrameControl(FrameControl),
93 ImageData,
95 ImageDataFlushed,
99 PartialChunk(ChunkType),
100 ImageEnd,
101}
102
103#[derive(Debug)]
109pub enum DecodingError {
110 IoError(io::Error),
117 Format(FormatError),
124 Parameter(ParameterError),
140 LimitsExceeded,
148}
149
150#[derive(Debug)]
151pub struct FormatError {
152 inner: FormatErrorInner,
153}
154
155#[derive(Debug)]
156pub(crate) enum FormatErrorInner {
157 CrcMismatch {
159 crc_val: u32,
161 crc_sum: u32,
163 chunk: ChunkType,
165 },
166 InvalidSignature,
168 MissingIhdr,
171 MissingFctl,
173 MissingImageData,
175 ChunkBeforeIhdr {
177 kind: ChunkType,
178 },
179 AfterIdat {
181 kind: ChunkType,
182 },
183 AfterPlte {
185 kind: ChunkType,
186 },
187 OutsidePlteIdat {
189 kind: ChunkType,
190 },
191 DuplicateChunk {
193 kind: ChunkType,
194 },
195 ApngOrder {
197 present: u32,
199 expected: u32,
201 },
202 ShortPalette {
205 expected: usize,
206 len: usize,
207 },
208 PaletteRequired,
210 InvalidColorBitDepth {
212 color_type: ColorType,
213 bit_depth: BitDepth,
214 },
215 ColorWithBadTrns(ColorType),
216 InvalidDimensions,
218 InvalidBitDepth(u8),
219 InvalidColorType(u8),
220 InvalidDisposeOp(u8),
221 InvalidBlendOp(u8),
222 InvalidUnit(u8),
223 InvalidSrgbRenderingIntent(u8),
225 UnknownCompressionMethod(u8),
226 UnknownFilterMethod(u8),
227 UnknownInterlaceMethod(u8),
228 BadSubFrameBounds {},
231 CorruptFlateStream {
234 err: fdeflate::DecompressionError,
235 },
236 NoMoreImageData,
238 BadTextEncoding(TextDecodingError),
240 FdatShorterThanFourBytes,
242 UnexpectedRestartOfDataChunkSequence {
251 kind: ChunkType,
252 },
253 ChunkTooShort {
255 kind: ChunkType,
256 },
257}
258
259impl error::Error for DecodingError {
260 fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
261 match self {
262 DecodingError::IoError(err) => Some(err),
263 _ => None,
264 }
265 }
266}
267
268impl fmt::Display for DecodingError {
269 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
270 use self::DecodingError::*;
271 match self {
272 IoError(err) => write!(fmt, "{}", err),
273 Parameter(desc) => write!(fmt, "{}", &desc),
274 Format(desc) => write!(fmt, "{}", desc),
275 LimitsExceeded => write!(fmt, "limits are exceeded"),
276 }
277 }
278}
279
280impl fmt::Display for FormatError {
281 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
282 use FormatErrorInner::*;
283 match &self.inner {
284 CrcMismatch {
285 crc_val,
286 crc_sum,
287 chunk,
288 ..
289 } => write!(
290 fmt,
291 "CRC error: expected 0x{:x} have 0x{:x} while decoding {:?} chunk.",
292 crc_val, crc_sum, chunk
293 ),
294 MissingIhdr => write!(fmt, "IHDR chunk missing"),
295 MissingFctl => write!(fmt, "fcTL chunk missing before fdAT chunk."),
296 MissingImageData => write!(fmt, "IDAT or fdAT chunk is missing."),
297 ChunkBeforeIhdr { kind } => write!(fmt, "{:?} chunk appeared before IHDR chunk", kind),
298 AfterIdat { kind } => write!(fmt, "Chunk {:?} is invalid after IDAT chunk.", kind),
299 AfterPlte { kind } => write!(fmt, "Chunk {:?} is invalid after PLTE chunk.", kind),
300 OutsidePlteIdat { kind } => write!(
301 fmt,
302 "Chunk {:?} must appear between PLTE and IDAT chunks.",
303 kind
304 ),
305 DuplicateChunk { kind } => write!(fmt, "Chunk {:?} must appear at most once.", kind),
306 ApngOrder { present, expected } => write!(
307 fmt,
308 "Sequence is not in order, expected #{} got #{}.",
309 expected, present,
310 ),
311 ShortPalette { expected, len } => write!(
312 fmt,
313 "Not enough palette entries, expect {} got {}.",
314 expected, len
315 ),
316 PaletteRequired => write!(fmt, "Missing palette of indexed image."),
317 InvalidDimensions => write!(fmt, "Invalid image dimensions"),
318 InvalidColorBitDepth {
319 color_type,
320 bit_depth,
321 } => write!(
322 fmt,
323 "Invalid color/depth combination in header: {:?}/{:?}",
324 color_type, bit_depth,
325 ),
326 ColorWithBadTrns(color_type) => write!(
327 fmt,
328 "Transparency chunk found for color type {:?}.",
329 color_type
330 ),
331 InvalidBitDepth(nr) => write!(fmt, "Invalid bit depth {}.", nr),
332 InvalidColorType(nr) => write!(fmt, "Invalid color type {}.", nr),
333 InvalidDisposeOp(nr) => write!(fmt, "Invalid dispose op {}.", nr),
334 InvalidBlendOp(nr) => write!(fmt, "Invalid blend op {}.", nr),
335 InvalidUnit(nr) => write!(fmt, "Invalid physical pixel size unit {}.", nr),
336 InvalidSrgbRenderingIntent(nr) => write!(fmt, "Invalid sRGB rendering intent {}.", nr),
337 UnknownCompressionMethod(nr) => write!(fmt, "Unknown compression method {}.", nr),
338 UnknownFilterMethod(nr) => write!(fmt, "Unknown filter method {}.", nr),
339 UnknownInterlaceMethod(nr) => write!(fmt, "Unknown interlace method {}.", nr),
340 BadSubFrameBounds {} => write!(fmt, "Sub frame is out-of-bounds."),
341 InvalidSignature => write!(fmt, "Invalid PNG signature."),
342 NoMoreImageData => write!(
343 fmt,
344 "IDAT or fDAT chunk does not have enough data for image."
345 ),
346 CorruptFlateStream { err } => {
347 write!(fmt, "Corrupt deflate stream. ")?;
348 write!(fmt, "{:?}", err)
349 }
350 BadTextEncoding(tde) => {
352 match tde {
353 TextDecodingError::Unrepresentable => {
354 write!(fmt, "Unrepresentable data in tEXt chunk.")
355 }
356 TextDecodingError::InvalidKeywordSize => {
357 write!(fmt, "Keyword empty or longer than 79 bytes.")
358 }
359 TextDecodingError::MissingNullSeparator => {
360 write!(fmt, "No null separator in tEXt chunk.")
361 }
362 TextDecodingError::InflationError => {
363 write!(fmt, "Invalid compressed text data.")
364 }
365 TextDecodingError::OutOfDecompressionSpace => {
366 write!(fmt, "Out of decompression space. Try with a larger limit.")
367 }
368 TextDecodingError::InvalidCompressionMethod => {
369 write!(fmt, "Using an unrecognized byte as compression method.")
370 }
371 TextDecodingError::InvalidCompressionFlag => {
372 write!(fmt, "Using a flag that is not 0 or 255 as a compression flag for iTXt chunk.")
373 }
374 TextDecodingError::MissingCompressionFlag => {
375 write!(fmt, "No compression flag in the iTXt chunk.")
376 }
377 }
378 }
379 FdatShorterThanFourBytes => write!(fmt, "fdAT chunk shorter than 4 bytes"),
380 UnexpectedRestartOfDataChunkSequence { kind } => {
381 write!(fmt, "Unexpected restart of {:?} chunk sequence", kind)
382 }
383 ChunkTooShort { kind } => {
384 write!(fmt, "Chunk is too short: {:?}", kind)
385 }
386 }
387 }
388}
389
390impl From<io::Error> for DecodingError {
391 fn from(err: io::Error) -> DecodingError {
392 DecodingError::IoError(err)
393 }
394}
395
396impl From<FormatError> for DecodingError {
397 fn from(err: FormatError) -> DecodingError {
398 DecodingError::Format(err)
399 }
400}
401
402impl From<FormatErrorInner> for FormatError {
403 fn from(inner: FormatErrorInner) -> Self {
404 FormatError { inner }
405 }
406}
407
408impl From<DecodingError> for io::Error {
409 fn from(err: DecodingError) -> io::Error {
410 match err {
411 DecodingError::IoError(err) => err,
412 err => io::Error::new(io::ErrorKind::Other, err.to_string()),
413 }
414 }
415}
416
417impl From<TextDecodingError> for DecodingError {
418 fn from(tbe: TextDecodingError) -> Self {
419 DecodingError::Format(FormatError {
420 inner: FormatErrorInner::BadTextEncoding(tbe),
421 })
422 }
423}
424
425#[derive(Clone)]
427pub struct DecodeOptions {
428 ignore_adler32: bool,
429 ignore_crc: bool,
430 ignore_text_chunk: bool,
431 ignore_iccp_chunk: bool,
432 skip_ancillary_crc_failures: bool,
433}
434
435impl Default for DecodeOptions {
436 fn default() -> Self {
437 Self {
438 ignore_adler32: true,
439 ignore_crc: false,
440 ignore_text_chunk: false,
441 ignore_iccp_chunk: false,
442 skip_ancillary_crc_failures: true,
443 }
444 }
445}
446
447impl DecodeOptions {
448 pub fn set_ignore_adler32(&mut self, ignore_adler32: bool) {
452 self.ignore_adler32 = ignore_adler32;
453 }
454
455 pub fn set_ignore_crc(&mut self, ignore_crc: bool) {
459 self.ignore_crc = ignore_crc;
460 }
461
462 pub fn set_ignore_checksums(&mut self, ignore_checksums: bool) {
465 self.ignore_adler32 = ignore_checksums;
466 self.ignore_crc = ignore_checksums;
467 }
468
469 pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
473 self.ignore_text_chunk = ignore_text_chunk;
474 }
475
476 pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
480 self.ignore_iccp_chunk = ignore_iccp_chunk;
481 }
482
483 pub fn set_skip_ancillary_crc_failures(&mut self, skip_ancillary_crc_failures: bool) {
487 self.skip_ancillary_crc_failures = skip_ancillary_crc_failures;
488 }
489}
490
491pub struct StreamingDecoder {
497 state: Option<State>,
498 current_chunk: ChunkState,
499 inflater: ZlibStream,
501 pub(crate) info: Option<Info<'static>>,
503 current_seq_no: Option<u32>,
505 have_idat: bool,
508 ready_for_idat_chunks: bool,
511 ready_for_fdat_chunks: bool,
515 have_iccp: bool,
517 decode_options: DecodeOptions,
518 pub(crate) limits: Limits,
519}
520
521struct ChunkState {
522 type_: ChunkType,
525
526 crc: Crc32,
528
529 remaining: u32,
531
532 raw_bytes: Vec<u8>,
534}
535
536impl StreamingDecoder {
537 pub fn new() -> StreamingDecoder {
541 StreamingDecoder::new_with_options(DecodeOptions::default())
542 }
543
544 pub fn new_with_options(decode_options: DecodeOptions) -> StreamingDecoder {
545 let mut inflater = ZlibStream::new();
546 inflater.set_ignore_adler32(decode_options.ignore_adler32);
547
548 StreamingDecoder {
549 state: Some(State::new_u32(U32ValueKind::Signature1stU32)),
550 current_chunk: ChunkState::default(),
551 inflater,
552 info: None,
553 current_seq_no: None,
554 have_idat: false,
555 have_iccp: false,
556 ready_for_idat_chunks: true,
557 ready_for_fdat_chunks: false,
558 decode_options,
559 limits: Limits { bytes: usize::MAX },
560 }
561 }
562
563 pub fn reset(&mut self) {
565 self.state = Some(State::new_u32(U32ValueKind::Signature1stU32));
566 self.current_chunk.crc = Crc32::new();
567 self.current_chunk.remaining = 0;
568 self.current_chunk.raw_bytes.clear();
569 self.inflater.reset();
570 self.info = None;
571 self.current_seq_no = None;
572 self.have_idat = false;
573 }
574
575 pub fn info(&self) -> Option<&Info<'static>> {
577 self.info.as_ref()
578 }
579
580 pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
581 self.decode_options.set_ignore_text_chunk(ignore_text_chunk);
582 }
583
584 pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
585 self.decode_options.set_ignore_iccp_chunk(ignore_iccp_chunk);
586 }
587
588 pub fn ignore_adler32(&self) -> bool {
590 self.inflater.ignore_adler32()
591 }
592
593 pub fn set_ignore_adler32(&mut self, ignore_adler32: bool) -> bool {
601 self.inflater.set_ignore_adler32(ignore_adler32)
602 }
603
604 pub fn set_ignore_crc(&mut self, ignore_crc: bool) {
609 self.decode_options.set_ignore_crc(ignore_crc)
610 }
611
612 pub fn set_skip_ancillary_crc_failures(&mut self, skip_ancillary_crc_failures: bool) {
616 self.decode_options
617 .set_skip_ancillary_crc_failures(skip_ancillary_crc_failures)
618 }
619
620 pub fn update(
626 &mut self,
627 mut buf: &[u8],
628 image_data: &mut Vec<u8>,
629 ) -> Result<(usize, Decoded), DecodingError> {
630 let len = buf.len();
631 while !buf.is_empty() && self.state.is_some() {
632 match self.next_state(buf, image_data) {
633 Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..],
634 Ok((bytes, result)) => {
635 buf = &buf[bytes..];
636 return Ok((len - buf.len(), result));
637 }
638 Err(err) => return Err(err),
639 }
640 }
641 Ok((len - buf.len(), Decoded::Nothing))
642 }
643
644 fn next_state(
645 &mut self,
646 buf: &[u8],
647 image_data: &mut Vec<u8>,
648 ) -> Result<(usize, Decoded), DecodingError> {
649 use self::State::*;
650
651 let state = self.state.take().unwrap();
653
654 match state {
655 U32 {
656 kind,
657 mut bytes,
658 mut accumulated_count,
659 } => {
660 debug_assert!(accumulated_count <= 4);
661 if accumulated_count == 0 && buf.len() >= 4 {
662 const CONSUMED_BYTES: usize = 4;
668 self.parse_u32(kind, &buf[0..4], image_data)
669 .map(|decoded| (CONSUMED_BYTES, decoded))
670 } else {
671 let remaining_count = 4 - accumulated_count;
672 let consumed_bytes = {
673 let available_count = min(remaining_count, buf.len());
674 bytes[accumulated_count..accumulated_count + available_count]
675 .copy_from_slice(&buf[0..available_count]);
676 accumulated_count += available_count;
677 available_count
678 };
679
680 if accumulated_count < 4 {
681 self.state = Some(U32 {
682 kind,
683 bytes,
684 accumulated_count,
685 });
686 Ok((consumed_bytes, Decoded::Nothing))
687 } else {
688 debug_assert_eq!(accumulated_count, 4);
689 self.parse_u32(kind, &bytes, image_data)
690 .map(|decoded| (consumed_bytes, decoded))
691 }
692 }
693 }
694 ParseChunkData(type_str) => {
695 debug_assert!(type_str != IDAT && type_str != chunk::fdAT);
696 if self.current_chunk.remaining == 0 {
697 Ok((0, self.parse_chunk(type_str)?))
699 } else {
700 self.reserve_current_chunk()?;
703
704 self.state = Some(ReadChunkData(type_str));
705 Ok((0, Decoded::PartialChunk(type_str)))
706 }
707 }
708 ReadChunkData(type_str) => {
709 debug_assert!(type_str != IDAT && type_str != chunk::fdAT);
710 if self.current_chunk.remaining == 0 {
711 self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
712 Ok((0, Decoded::Nothing))
713 } else {
714 let ChunkState {
715 crc,
716 remaining,
717 raw_bytes,
718 type_: _,
719 } = &mut self.current_chunk;
720
721 let buf_avail = raw_bytes.capacity() - raw_bytes.len();
722 let bytes_avail = min(buf.len(), buf_avail);
723 let n = min(*remaining, bytes_avail as u32);
724 if buf_avail == 0 {
725 self.state = Some(ParseChunkData(type_str));
726 Ok((0, Decoded::Nothing))
727 } else {
728 let buf = &buf[..n as usize];
729 if !self.decode_options.ignore_crc {
730 crc.update(buf);
731 }
732 raw_bytes.extend_from_slice(buf);
733
734 *remaining -= n;
735 if *remaining == 0 {
736 self.state = Some(ParseChunkData(type_str));
737 } else {
738 self.state = Some(ReadChunkData(type_str));
739 }
740 Ok((n as usize, Decoded::Nothing))
741 }
742 }
743 }
744 ImageData(type_str) => {
745 debug_assert!(type_str == IDAT || type_str == chunk::fdAT);
746 let len = std::cmp::min(buf.len(), self.current_chunk.remaining as usize);
747 let buf = &buf[..len];
748 let consumed = self.inflater.decompress(buf, image_data)?;
749 self.current_chunk.crc.update(&buf[..consumed]);
750 self.current_chunk.remaining -= consumed as u32;
751 if self.current_chunk.remaining == 0 {
752 self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
753 } else {
754 self.state = Some(ImageData(type_str));
755 }
756 Ok((consumed, Decoded::ImageData))
757 }
758 }
759 }
760
761 fn parse_u32(
762 &mut self,
763 kind: U32ValueKind,
764 u32_be_bytes: &[u8],
765 image_data: &mut Vec<u8>,
766 ) -> Result<Decoded, DecodingError> {
767 debug_assert_eq!(u32_be_bytes.len(), 4);
768 let bytes = u32_be_bytes.try_into().unwrap();
769 let val = u32::from_be_bytes(bytes);
770
771 match kind {
772 U32ValueKind::Signature1stU32 => {
773 if bytes == [137, 80, 78, 71] {
774 self.state = Some(State::new_u32(U32ValueKind::Signature2ndU32));
775 Ok(Decoded::Nothing)
776 } else {
777 Err(DecodingError::Format(
778 FormatErrorInner::InvalidSignature.into(),
779 ))
780 }
781 }
782 U32ValueKind::Signature2ndU32 => {
783 if bytes == [13, 10, 26, 10] {
784 self.state = Some(State::new_u32(U32ValueKind::Length));
785 Ok(Decoded::Nothing)
786 } else {
787 Err(DecodingError::Format(
788 FormatErrorInner::InvalidSignature.into(),
789 ))
790 }
791 }
792 U32ValueKind::Length => {
793 self.state = Some(State::new_u32(U32ValueKind::Type { length: val }));
794 Ok(Decoded::Nothing)
795 }
796 U32ValueKind::Type { length } => {
797 let type_str = ChunkType(bytes);
798 if self.info.is_none() && type_str != IHDR {
799 return Err(DecodingError::Format(
800 FormatErrorInner::ChunkBeforeIhdr { kind: type_str }.into(),
801 ));
802 }
803 if type_str != self.current_chunk.type_
804 && (self.current_chunk.type_ == IDAT || self.current_chunk.type_ == chunk::fdAT)
805 {
806 self.current_chunk.type_ = type_str;
807 self.inflater.finish_compressed_chunks(image_data)?;
808 self.inflater.reset();
809 self.ready_for_idat_chunks = false;
810 self.ready_for_fdat_chunks = false;
811 self.state = Some(State::U32 {
812 kind,
813 bytes,
814 accumulated_count: 4,
815 });
816 return Ok(Decoded::ImageDataFlushed);
817 }
818 self.state = match type_str {
819 chunk::fdAT => {
820 if !self.ready_for_fdat_chunks {
821 return Err(DecodingError::Format(
822 FormatErrorInner::UnexpectedRestartOfDataChunkSequence {
823 kind: chunk::fdAT,
824 }
825 .into(),
826 ));
827 }
828 if length < 4 {
829 return Err(DecodingError::Format(
830 FormatErrorInner::FdatShorterThanFourBytes.into(),
831 ));
832 }
833 Some(State::new_u32(U32ValueKind::ApngSequenceNumber))
834 }
835 IDAT => {
836 if !self.ready_for_idat_chunks {
837 return Err(DecodingError::Format(
838 FormatErrorInner::UnexpectedRestartOfDataChunkSequence {
839 kind: IDAT,
840 }
841 .into(),
842 ));
843 }
844 self.have_idat = true;
845 Some(State::ImageData(type_str))
846 }
847 _ => Some(State::ReadChunkData(type_str)),
848 };
849 self.current_chunk.type_ = type_str;
850 if !self.decode_options.ignore_crc {
851 self.current_chunk.crc.reset();
852 self.current_chunk.crc.update(&type_str.0);
853 }
854 self.current_chunk.remaining = length;
855 self.current_chunk.raw_bytes.clear();
856 Ok(Decoded::ChunkBegin(length, type_str))
857 }
858 U32ValueKind::Crc(type_str) => {
859 let sum = if self.decode_options.ignore_crc {
863 val
864 } else {
865 self.current_chunk.crc.clone().finalize()
866 };
867
868 if val == sum || CHECKSUM_DISABLED {
869 self.state = Some(State::new_u32(U32ValueKind::Length));
870 if type_str == IEND {
871 Ok(Decoded::ImageEnd)
872 } else {
873 Ok(Decoded::ChunkComplete(val, type_str))
874 }
875 } else if self.decode_options.skip_ancillary_crc_failures
876 && !chunk::is_critical(type_str)
877 {
878 self.state = Some(State::new_u32(U32ValueKind::Length));
880 Ok(Decoded::Nothing)
881 } else {
882 Err(DecodingError::Format(
883 FormatErrorInner::CrcMismatch {
884 crc_val: val,
885 crc_sum: sum,
886 chunk: type_str,
887 }
888 .into(),
889 ))
890 }
891 }
892 U32ValueKind::ApngSequenceNumber => {
893 debug_assert_eq!(self.current_chunk.type_, chunk::fdAT);
894 let next_seq_no = val;
895
896 debug_assert!(self.current_chunk.remaining >= 4);
898 self.current_chunk.remaining -= 4;
899
900 if let Some(seq_no) = self.current_seq_no {
901 if next_seq_no != seq_no + 1 {
902 return Err(DecodingError::Format(
903 FormatErrorInner::ApngOrder {
904 present: next_seq_no,
905 expected: seq_no + 1,
906 }
907 .into(),
908 ));
909 }
910 self.current_seq_no = Some(next_seq_no);
911 } else {
912 return Err(DecodingError::Format(FormatErrorInner::MissingFctl.into()));
913 }
914
915 if !self.decode_options.ignore_crc {
916 let data = next_seq_no.to_be_bytes();
917 self.current_chunk.crc.update(&data);
918 }
919
920 self.state = Some(State::ImageData(chunk::fdAT));
921 Ok(Decoded::PartialChunk(chunk::fdAT))
922 }
923 }
924 }
925
926 fn reserve_current_chunk(&mut self) -> Result<(), DecodingError> {
927 let max = self.limits.bytes;
928 let buffer = &mut self.current_chunk.raw_bytes;
929
930 let reserve_size = max.saturating_sub(buffer.capacity()).min(buffer.len());
932 self.limits.reserve_bytes(reserve_size)?;
933 buffer.reserve_exact(reserve_size);
934
935 if buffer.capacity() == buffer.len() {
936 Err(DecodingError::LimitsExceeded)
937 } else {
938 Ok(())
939 }
940 }
941
942 fn parse_chunk(&mut self, type_str: ChunkType) -> Result<Decoded, DecodingError> {
943 self.state = Some(State::new_u32(U32ValueKind::Crc(type_str)));
944 let parse_result = match type_str {
945 IHDR => self.parse_ihdr(),
946 chunk::PLTE => self.parse_plte(),
947 chunk::tRNS => self.parse_trns(),
948 chunk::pHYs => self.parse_phys(),
949 chunk::gAMA => self.parse_gama(),
950 chunk::acTL => self.parse_actl(),
951 chunk::fcTL => self.parse_fctl(),
952 chunk::cHRM => self.parse_chrm(),
953 chunk::sRGB => self.parse_srgb(),
954 chunk::iCCP if !self.decode_options.ignore_iccp_chunk => self.parse_iccp(),
955 chunk::tEXt if !self.decode_options.ignore_text_chunk => self.parse_text(),
956 chunk::zTXt if !self.decode_options.ignore_text_chunk => self.parse_ztxt(),
957 chunk::iTXt if !self.decode_options.ignore_text_chunk => self.parse_itxt(),
958 _ => Ok(Decoded::PartialChunk(type_str)),
959 };
960
961 let parse_result = parse_result.map_err(|e| {
962 self.state = None;
963 match e {
964 DecodingError::IoError(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
969 let fmt_err: FormatError =
970 FormatErrorInner::ChunkTooShort { kind: type_str }.into();
971 fmt_err.into()
972 }
973 e => e,
974 }
975 });
976
977 parse_result
978 }
979
980 fn parse_fctl(&mut self) -> Result<Decoded, DecodingError> {
981 let mut buf = &self.current_chunk.raw_bytes[..];
982 let next_seq_no = buf.read_be()?;
983
984 self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no {
986 if next_seq_no != seq_no + 1 {
987 return Err(DecodingError::Format(
988 FormatErrorInner::ApngOrder {
989 expected: seq_no + 1,
990 present: next_seq_no,
991 }
992 .into(),
993 ));
994 }
995 next_seq_no
996 } else {
997 if next_seq_no != 0 {
998 return Err(DecodingError::Format(
999 FormatErrorInner::ApngOrder {
1000 expected: 0,
1001 present: next_seq_no,
1002 }
1003 .into(),
1004 ));
1005 }
1006 0
1007 });
1008 self.inflater.reset();
1009 self.ready_for_fdat_chunks = true;
1010 let fc = FrameControl {
1011 sequence_number: next_seq_no,
1012 width: buf.read_be()?,
1013 height: buf.read_be()?,
1014 x_offset: buf.read_be()?,
1015 y_offset: buf.read_be()?,
1016 delay_num: buf.read_be()?,
1017 delay_den: buf.read_be()?,
1018 dispose_op: {
1019 let dispose_op = buf.read_be()?;
1020 match DisposeOp::from_u8(dispose_op) {
1021 Some(dispose_op) => dispose_op,
1022 None => {
1023 return Err(DecodingError::Format(
1024 FormatErrorInner::InvalidDisposeOp(dispose_op).into(),
1025 ))
1026 }
1027 }
1028 },
1029 blend_op: {
1030 let blend_op = buf.read_be()?;
1031 match BlendOp::from_u8(blend_op) {
1032 Some(blend_op) => blend_op,
1033 None => {
1034 return Err(DecodingError::Format(
1035 FormatErrorInner::InvalidBlendOp(blend_op).into(),
1036 ))
1037 }
1038 }
1039 },
1040 };
1041 self.info.as_ref().unwrap().validate(&fc)?;
1042 self.info.as_mut().unwrap().frame_control = Some(fc);
1043 Ok(Decoded::FrameControl(fc))
1044 }
1045
1046 fn parse_actl(&mut self) -> Result<Decoded, DecodingError> {
1047 if self.have_idat {
1048 Err(DecodingError::Format(
1049 FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(),
1050 ))
1051 } else {
1052 let mut buf = &self.current_chunk.raw_bytes[..];
1053 let actl = AnimationControl {
1054 num_frames: buf.read_be()?,
1055 num_plays: buf.read_be()?,
1056 };
1057 self.info.as_mut().unwrap().animation_control = Some(actl);
1058 Ok(Decoded::AnimationControl(actl))
1059 }
1060 }
1061
1062 fn parse_plte(&mut self) -> Result<Decoded, DecodingError> {
1063 let info = self.info.as_mut().unwrap();
1064 if info.palette.is_some() {
1065 Err(DecodingError::Format(
1067 FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(),
1068 ))
1069 } else {
1070 self.limits
1071 .reserve_bytes(self.current_chunk.raw_bytes.len())?;
1072 info.palette = Some(Cow::Owned(self.current_chunk.raw_bytes.clone()));
1073 Ok(Decoded::Nothing)
1074 }
1075 }
1076
1077 fn parse_trns(&mut self) -> Result<Decoded, DecodingError> {
1078 let info = self.info.as_mut().unwrap();
1079 if info.trns.is_some() {
1080 return Err(DecodingError::Format(
1081 FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(),
1082 ));
1083 }
1084 let (color_type, bit_depth) = { (info.color_type, info.bit_depth as u8) };
1085 self.limits
1086 .reserve_bytes(self.current_chunk.raw_bytes.len())?;
1087 let mut vec = self.current_chunk.raw_bytes.clone();
1088 let len = vec.len();
1089 match color_type {
1090 ColorType::Grayscale => {
1091 if len < 2 {
1092 return Err(DecodingError::Format(
1093 FormatErrorInner::ShortPalette { expected: 2, len }.into(),
1094 ));
1095 }
1096 if bit_depth < 16 {
1097 vec[0] = vec[1];
1098 vec.truncate(1);
1099 }
1100 info.trns = Some(Cow::Owned(vec));
1101 Ok(Decoded::Nothing)
1102 }
1103 ColorType::Rgb => {
1104 if len < 6 {
1105 return Err(DecodingError::Format(
1106 FormatErrorInner::ShortPalette { expected: 6, len }.into(),
1107 ));
1108 }
1109 if bit_depth < 16 {
1110 vec[0] = vec[1];
1111 vec[1] = vec[3];
1112 vec[2] = vec[5];
1113 vec.truncate(3);
1114 }
1115 info.trns = Some(Cow::Owned(vec));
1116 Ok(Decoded::Nothing)
1117 }
1118 ColorType::Indexed => {
1119 if info.palette.is_none() {
1122 return Err(DecodingError::Format(
1123 FormatErrorInner::AfterPlte { kind: chunk::tRNS }.into(),
1124 ));
1125 } else if self.have_idat {
1126 return Err(DecodingError::Format(
1127 FormatErrorInner::OutsidePlteIdat { kind: chunk::tRNS }.into(),
1128 ));
1129 }
1130
1131 info.trns = Some(Cow::Owned(vec));
1132 Ok(Decoded::Nothing)
1133 }
1134 c => Err(DecodingError::Format(
1135 FormatErrorInner::ColorWithBadTrns(c).into(),
1136 )),
1137 }
1138 }
1139
1140 fn parse_phys(&mut self) -> Result<Decoded, DecodingError> {
1141 let info = self.info.as_mut().unwrap();
1142 if self.have_idat {
1143 Err(DecodingError::Format(
1144 FormatErrorInner::AfterIdat { kind: chunk::pHYs }.into(),
1145 ))
1146 } else if info.pixel_dims.is_some() {
1147 Err(DecodingError::Format(
1148 FormatErrorInner::DuplicateChunk { kind: chunk::pHYs }.into(),
1149 ))
1150 } else {
1151 let mut buf = &self.current_chunk.raw_bytes[..];
1152 let xppu = buf.read_be()?;
1153 let yppu = buf.read_be()?;
1154 let unit = buf.read_be()?;
1155 let unit = match Unit::from_u8(unit) {
1156 Some(unit) => unit,
1157 None => {
1158 return Err(DecodingError::Format(
1159 FormatErrorInner::InvalidUnit(unit).into(),
1160 ))
1161 }
1162 };
1163 let pixel_dims = PixelDimensions { xppu, yppu, unit };
1164 info.pixel_dims = Some(pixel_dims);
1165 Ok(Decoded::PixelDimensions(pixel_dims))
1166 }
1167 }
1168
1169 fn parse_chrm(&mut self) -> Result<Decoded, DecodingError> {
1170 let info = self.info.as_mut().unwrap();
1171 if self.have_idat {
1172 Err(DecodingError::Format(
1173 FormatErrorInner::AfterIdat { kind: chunk::cHRM }.into(),
1174 ))
1175 } else if info.chrm_chunk.is_some() {
1176 Err(DecodingError::Format(
1177 FormatErrorInner::DuplicateChunk { kind: chunk::cHRM }.into(),
1178 ))
1179 } else {
1180 let mut buf = &self.current_chunk.raw_bytes[..];
1181 let white_x: u32 = buf.read_be()?;
1182 let white_y: u32 = buf.read_be()?;
1183 let red_x: u32 = buf.read_be()?;
1184 let red_y: u32 = buf.read_be()?;
1185 let green_x: u32 = buf.read_be()?;
1186 let green_y: u32 = buf.read_be()?;
1187 let blue_x: u32 = buf.read_be()?;
1188 let blue_y: u32 = buf.read_be()?;
1189
1190 let source_chromaticities = SourceChromaticities {
1191 white: (
1192 ScaledFloat::from_scaled(white_x),
1193 ScaledFloat::from_scaled(white_y),
1194 ),
1195 red: (
1196 ScaledFloat::from_scaled(red_x),
1197 ScaledFloat::from_scaled(red_y),
1198 ),
1199 green: (
1200 ScaledFloat::from_scaled(green_x),
1201 ScaledFloat::from_scaled(green_y),
1202 ),
1203 blue: (
1204 ScaledFloat::from_scaled(blue_x),
1205 ScaledFloat::from_scaled(blue_y),
1206 ),
1207 };
1208
1209 info.chrm_chunk = Some(source_chromaticities);
1210 if info.srgb.is_none() {
1212 info.source_chromaticities = Some(source_chromaticities);
1213 }
1214
1215 Ok(Decoded::Nothing)
1216 }
1217 }
1218
1219 fn parse_gama(&mut self) -> Result<Decoded, DecodingError> {
1220 let info = self.info.as_mut().unwrap();
1221 if self.have_idat {
1222 Err(DecodingError::Format(
1223 FormatErrorInner::AfterIdat { kind: chunk::gAMA }.into(),
1224 ))
1225 } else if info.gama_chunk.is_some() {
1226 Err(DecodingError::Format(
1227 FormatErrorInner::DuplicateChunk { kind: chunk::gAMA }.into(),
1228 ))
1229 } else {
1230 let mut buf = &self.current_chunk.raw_bytes[..];
1231 let source_gamma: u32 = buf.read_be()?;
1232 let source_gamma = ScaledFloat::from_scaled(source_gamma);
1233
1234 info.gama_chunk = Some(source_gamma);
1235 if info.srgb.is_none() {
1237 info.source_gamma = Some(source_gamma);
1238 }
1239
1240 Ok(Decoded::Nothing)
1241 }
1242 }
1243
1244 fn parse_srgb(&mut self) -> Result<Decoded, DecodingError> {
1245 let info = self.info.as_mut().unwrap();
1246 if self.have_idat {
1247 Err(DecodingError::Format(
1248 FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(),
1249 ))
1250 } else if info.srgb.is_some() {
1251 Err(DecodingError::Format(
1252 FormatErrorInner::DuplicateChunk { kind: chunk::sRGB }.into(),
1253 ))
1254 } else {
1255 let mut buf = &self.current_chunk.raw_bytes[..];
1256 let raw: u8 = buf.read_be()?; let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| {
1258 FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw))
1259 })?;
1260
1261 info.srgb = Some(rendering_intent);
1263 info.source_gamma = Some(crate::srgb::substitute_gamma());
1264 info.source_chromaticities = Some(crate::srgb::substitute_chromaticities());
1265 Ok(Decoded::Nothing)
1266 }
1267 }
1268
1269 fn parse_iccp(&mut self) -> Result<Decoded, DecodingError> {
1270 if self.have_idat {
1271 Err(DecodingError::Format(
1272 FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(),
1273 ))
1274 } else if self.have_iccp {
1275 Ok(Decoded::Nothing)
1287 } else {
1288 self.have_iccp = true;
1289 let _ = self.parse_iccp_raw();
1290 Ok(Decoded::Nothing)
1291 }
1292 }
1293
1294 fn parse_iccp_raw(&mut self) -> Result<(), DecodingError> {
1295 let info = self.info.as_mut().unwrap();
1296 let mut buf = &self.current_chunk.raw_bytes[..];
1297
1298 let _: u8 = buf.read_be()?;
1300 for _ in 1..80 {
1301 let raw: u8 = buf.read_be()?;
1302 if raw == 0 {
1303 break;
1304 }
1305 }
1306
1307 match buf.read_be()? {
1308 0u8 => (),
1310 n => {
1311 return Err(DecodingError::Format(
1312 FormatErrorInner::UnknownCompressionMethod(n).into(),
1313 ))
1314 }
1315 }
1316
1317 match fdeflate::decompress_to_vec_bounded(buf, self.limits.bytes) {
1318 Ok(profile) => {
1319 self.limits.reserve_bytes(profile.len())?;
1320 info.icc_profile = Some(Cow::Owned(profile));
1321 }
1322 Err(fdeflate::BoundedDecompressionError::DecompressionError { inner: err }) => {
1323 return Err(DecodingError::Format(
1324 FormatErrorInner::CorruptFlateStream { err }.into(),
1325 ))
1326 }
1327 Err(fdeflate::BoundedDecompressionError::OutputTooLarge { .. }) => {
1328 return Err(DecodingError::LimitsExceeded);
1329 }
1330 }
1331
1332 Ok(())
1333 }
1334
1335 fn parse_ihdr(&mut self) -> Result<Decoded, DecodingError> {
1336 if self.info.is_some() {
1337 return Err(DecodingError::Format(
1338 FormatErrorInner::DuplicateChunk { kind: IHDR }.into(),
1339 ));
1340 }
1341 let mut buf = &self.current_chunk.raw_bytes[..];
1342 let width = buf.read_be()?;
1343 let height = buf.read_be()?;
1344 if width == 0 || height == 0 {
1345 return Err(DecodingError::Format(
1346 FormatErrorInner::InvalidDimensions.into(),
1347 ));
1348 }
1349 let bit_depth = buf.read_be()?;
1350 let bit_depth = match BitDepth::from_u8(bit_depth) {
1351 Some(bits) => bits,
1352 None => {
1353 return Err(DecodingError::Format(
1354 FormatErrorInner::InvalidBitDepth(bit_depth).into(),
1355 ))
1356 }
1357 };
1358 let color_type = buf.read_be()?;
1359 let color_type = match ColorType::from_u8(color_type) {
1360 Some(color_type) => {
1361 if color_type.is_combination_invalid(bit_depth) {
1362 return Err(DecodingError::Format(
1363 FormatErrorInner::InvalidColorBitDepth {
1364 color_type,
1365 bit_depth,
1366 }
1367 .into(),
1368 ));
1369 } else {
1370 color_type
1371 }
1372 }
1373 None => {
1374 return Err(DecodingError::Format(
1375 FormatErrorInner::InvalidColorType(color_type).into(),
1376 ))
1377 }
1378 };
1379 match buf.read_be()? {
1380 0u8 => (),
1382 n => {
1383 return Err(DecodingError::Format(
1384 FormatErrorInner::UnknownCompressionMethod(n).into(),
1385 ))
1386 }
1387 }
1388 match buf.read_be()? {
1389 0u8 => (),
1391 n => {
1392 return Err(DecodingError::Format(
1393 FormatErrorInner::UnknownFilterMethod(n).into(),
1394 ))
1395 }
1396 }
1397 let interlaced = match buf.read_be()? {
1398 0u8 => false,
1399 1 => true,
1400 n => {
1401 return Err(DecodingError::Format(
1402 FormatErrorInner::UnknownInterlaceMethod(n).into(),
1403 ))
1404 }
1405 };
1406
1407 if let Some(mut raw_row_len) = color_type.checked_raw_row_length(bit_depth, width) {
1408 if interlaced {
1409 raw_row_len = raw_row_len.saturating_mul(2);
1412 }
1413 self.inflater
1414 .set_max_total_output((height as usize).saturating_mul(raw_row_len));
1415 }
1416
1417 self.info = Some(Info {
1418 width,
1419 height,
1420 bit_depth,
1421 color_type,
1422 interlaced,
1423 ..Default::default()
1424 });
1425
1426 Ok(Decoded::Header(
1427 width, height, bit_depth, color_type, interlaced,
1428 ))
1429 }
1430
1431 fn split_keyword(buf: &[u8]) -> Result<(&[u8], &[u8]), DecodingError> {
1432 let null_byte_index = buf
1433 .iter()
1434 .position(|&b| b == 0)
1435 .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?;
1436
1437 if null_byte_index == 0 || null_byte_index > 79 {
1438 return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize));
1439 }
1440
1441 Ok((&buf[..null_byte_index], &buf[null_byte_index + 1..]))
1442 }
1443
1444 fn parse_text(&mut self) -> Result<Decoded, DecodingError> {
1445 let buf = &self.current_chunk.raw_bytes[..];
1446 self.limits.reserve_bytes(buf.len())?;
1447
1448 let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1449
1450 self.info
1451 .as_mut()
1452 .unwrap()
1453 .uncompressed_latin1_text
1454 .push(TEXtChunk::decode(keyword_slice, value_slice).map_err(DecodingError::from)?);
1455
1456 Ok(Decoded::Nothing)
1457 }
1458
1459 fn parse_ztxt(&mut self) -> Result<Decoded, DecodingError> {
1460 let buf = &self.current_chunk.raw_bytes[..];
1461 self.limits.reserve_bytes(buf.len())?;
1462
1463 let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1464
1465 let compression_method = *value_slice
1466 .first()
1467 .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?;
1468
1469 let text_slice = &value_slice[1..];
1470
1471 self.info.as_mut().unwrap().compressed_latin1_text.push(
1472 ZTXtChunk::decode(keyword_slice, compression_method, text_slice)
1473 .map_err(DecodingError::from)?,
1474 );
1475
1476 Ok(Decoded::Nothing)
1477 }
1478
1479 fn parse_itxt(&mut self) -> Result<Decoded, DecodingError> {
1480 let buf = &self.current_chunk.raw_bytes[..];
1481 self.limits.reserve_bytes(buf.len())?;
1482
1483 let (keyword_slice, value_slice) = Self::split_keyword(buf)?;
1484
1485 let compression_flag = *value_slice
1486 .first()
1487 .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?;
1488
1489 let compression_method = *value_slice
1490 .get(1)
1491 .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?;
1492
1493 let second_null_byte_index = value_slice[2..]
1494 .iter()
1495 .position(|&b| b == 0)
1496 .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?
1497 + 2;
1498
1499 let language_tag_slice = &value_slice[2..second_null_byte_index];
1500
1501 let third_null_byte_index = value_slice[second_null_byte_index + 1..]
1502 .iter()
1503 .position(|&b| b == 0)
1504 .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?
1505 + (second_null_byte_index + 1);
1506
1507 let translated_keyword_slice =
1508 &value_slice[second_null_byte_index + 1..third_null_byte_index];
1509
1510 let text_slice = &value_slice[third_null_byte_index + 1..];
1511
1512 self.info.as_mut().unwrap().utf8_text.push(
1513 ITXtChunk::decode(
1514 keyword_slice,
1515 compression_flag,
1516 compression_method,
1517 language_tag_slice,
1518 translated_keyword_slice,
1519 text_slice,
1520 )
1521 .map_err(DecodingError::from)?,
1522 );
1523
1524 Ok(Decoded::Nothing)
1525 }
1526}
1527
1528impl Info<'_> {
1529 fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> {
1530 if fc.width == 0 || fc.height == 0 {
1531 return Err(DecodingError::Format(
1532 FormatErrorInner::InvalidDimensions.into(),
1533 ));
1534 }
1535
1536 let in_x_bounds = Some(fc.width) <= self.width.checked_sub(fc.x_offset);
1538 let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset);
1540
1541 if !in_x_bounds || !in_y_bounds {
1542 return Err(DecodingError::Format(
1543 FormatErrorInner::BadSubFrameBounds {}.into(),
1545 ));
1546 }
1547
1548 Ok(())
1549 }
1550}
1551
1552impl Default for StreamingDecoder {
1553 fn default() -> Self {
1554 Self::new()
1555 }
1556}
1557
1558impl Default for ChunkState {
1559 fn default() -> Self {
1560 ChunkState {
1561 type_: ChunkType([0; 4]),
1562 crc: Crc32::new(),
1563 remaining: 0,
1564 raw_bytes: Vec::with_capacity(CHUNK_BUFFER_SIZE),
1565 }
1566 }
1567}
1568
1569#[cfg(test)]
1570mod tests {
1571 use super::ScaledFloat;
1572 use super::SourceChromaticities;
1573 use crate::test_utils::*;
1574 use crate::{Decoder, DecodingError, Reader};
1575 use byteorder::WriteBytesExt;
1576 use std::cell::RefCell;
1577 use std::fs::File;
1578 use std::io::{ErrorKind, Read, Write};
1579 use std::rc::Rc;
1580
1581 #[test]
1582 fn image_gamma() -> Result<(), ()> {
1583 fn trial(path: &str, expected: Option<ScaledFloat>) {
1584 let decoder = crate::Decoder::new(File::open(path).unwrap());
1585 let reader = decoder.read_info().unwrap();
1586 let actual: Option<ScaledFloat> = reader.info().source_gamma;
1587 assert!(actual == expected);
1588 }
1589 trial("tests/pngsuite/f00n0g08.png", None);
1590 trial("tests/pngsuite/f00n2c08.png", None);
1591 trial("tests/pngsuite/f01n0g08.png", None);
1592 trial("tests/pngsuite/f01n2c08.png", None);
1593 trial("tests/pngsuite/f02n0g08.png", None);
1594 trial("tests/pngsuite/f02n2c08.png", None);
1595 trial("tests/pngsuite/f03n0g08.png", None);
1596 trial("tests/pngsuite/f03n2c08.png", None);
1597 trial("tests/pngsuite/f04n0g08.png", None);
1598 trial("tests/pngsuite/f04n2c08.png", None);
1599 trial("tests/pngsuite/f99n0g04.png", None);
1600 trial("tests/pngsuite/tm3n3p02.png", None);
1601 trial("tests/pngsuite/g03n0g16.png", Some(ScaledFloat::new(0.35)));
1602 trial("tests/pngsuite/g03n2c08.png", Some(ScaledFloat::new(0.35)));
1603 trial("tests/pngsuite/g03n3p04.png", Some(ScaledFloat::new(0.35)));
1604 trial("tests/pngsuite/g04n0g16.png", Some(ScaledFloat::new(0.45)));
1605 trial("tests/pngsuite/g04n2c08.png", Some(ScaledFloat::new(0.45)));
1606 trial("tests/pngsuite/g04n3p04.png", Some(ScaledFloat::new(0.45)));
1607 trial("tests/pngsuite/g05n0g16.png", Some(ScaledFloat::new(0.55)));
1608 trial("tests/pngsuite/g05n2c08.png", Some(ScaledFloat::new(0.55)));
1609 trial("tests/pngsuite/g05n3p04.png", Some(ScaledFloat::new(0.55)));
1610 trial("tests/pngsuite/g07n0g16.png", Some(ScaledFloat::new(0.7)));
1611 trial("tests/pngsuite/g07n2c08.png", Some(ScaledFloat::new(0.7)));
1612 trial("tests/pngsuite/g07n3p04.png", Some(ScaledFloat::new(0.7)));
1613 trial("tests/pngsuite/g10n0g16.png", Some(ScaledFloat::new(1.0)));
1614 trial("tests/pngsuite/g10n2c08.png", Some(ScaledFloat::new(1.0)));
1615 trial("tests/pngsuite/g10n3p04.png", Some(ScaledFloat::new(1.0)));
1616 trial("tests/pngsuite/g25n0g16.png", Some(ScaledFloat::new(2.5)));
1617 trial("tests/pngsuite/g25n2c08.png", Some(ScaledFloat::new(2.5)));
1618 trial("tests/pngsuite/g25n3p04.png", Some(ScaledFloat::new(2.5)));
1619 Ok(())
1620 }
1621
1622 #[test]
1623 fn image_source_chromaticities() -> Result<(), ()> {
1624 fn trial(path: &str, expected: Option<SourceChromaticities>) {
1625 let decoder = crate::Decoder::new(File::open(path).unwrap());
1626 let reader = decoder.read_info().unwrap();
1627 let actual: Option<SourceChromaticities> = reader.info().source_chromaticities;
1628 assert!(actual == expected);
1629 }
1630 trial(
1631 "tests/pngsuite/ccwn2c08.png",
1632 Some(SourceChromaticities::new(
1633 (0.3127, 0.3290),
1634 (0.64, 0.33),
1635 (0.30, 0.60),
1636 (0.15, 0.06),
1637 )),
1638 );
1639 trial(
1640 "tests/pngsuite/ccwn3p08.png",
1641 Some(SourceChromaticities::new(
1642 (0.3127, 0.3290),
1643 (0.64, 0.33),
1644 (0.30, 0.60),
1645 (0.15, 0.06),
1646 )),
1647 );
1648 trial("tests/pngsuite/basi0g01.png", None);
1649 trial("tests/pngsuite/basi0g02.png", None);
1650 trial("tests/pngsuite/basi0g04.png", None);
1651 trial("tests/pngsuite/basi0g08.png", None);
1652 trial("tests/pngsuite/basi0g16.png", None);
1653 trial("tests/pngsuite/basi2c08.png", None);
1654 trial("tests/pngsuite/basi2c16.png", None);
1655 trial("tests/pngsuite/basi3p01.png", None);
1656 trial("tests/pngsuite/basi3p02.png", None);
1657 trial("tests/pngsuite/basi3p04.png", None);
1658 trial("tests/pngsuite/basi3p08.png", None);
1659 trial("tests/pngsuite/basi4a08.png", None);
1660 trial("tests/pngsuite/basi4a16.png", None);
1661 trial("tests/pngsuite/basi6a08.png", None);
1662 trial("tests/pngsuite/basi6a16.png", None);
1663 trial("tests/pngsuite/basn0g01.png", None);
1664 trial("tests/pngsuite/basn0g02.png", None);
1665 trial("tests/pngsuite/basn0g04.png", None);
1666 trial("tests/pngsuite/basn0g08.png", None);
1667 trial("tests/pngsuite/basn0g16.png", None);
1668 trial("tests/pngsuite/basn2c08.png", None);
1669 trial("tests/pngsuite/basn2c16.png", None);
1670 trial("tests/pngsuite/basn3p01.png", None);
1671 trial("tests/pngsuite/basn3p02.png", None);
1672 trial("tests/pngsuite/basn3p04.png", None);
1673 trial("tests/pngsuite/basn3p08.png", None);
1674 trial("tests/pngsuite/basn4a08.png", None);
1675 trial("tests/pngsuite/basn4a16.png", None);
1676 trial("tests/pngsuite/basn6a08.png", None);
1677 trial("tests/pngsuite/basn6a16.png", None);
1678 trial("tests/pngsuite/bgai4a08.png", None);
1679 trial("tests/pngsuite/bgai4a16.png", None);
1680 trial("tests/pngsuite/bgan6a08.png", None);
1681 trial("tests/pngsuite/bgan6a16.png", None);
1682 trial("tests/pngsuite/bgbn4a08.png", None);
1683 trial("tests/pngsuite/bggn4a16.png", None);
1684 trial("tests/pngsuite/bgwn6a08.png", None);
1685 trial("tests/pngsuite/bgyn6a16.png", None);
1686 trial("tests/pngsuite/cdfn2c08.png", None);
1687 trial("tests/pngsuite/cdhn2c08.png", None);
1688 trial("tests/pngsuite/cdsn2c08.png", None);
1689 trial("tests/pngsuite/cdun2c08.png", None);
1690 trial("tests/pngsuite/ch1n3p04.png", None);
1691 trial("tests/pngsuite/ch2n3p08.png", None);
1692 trial("tests/pngsuite/cm0n0g04.png", None);
1693 trial("tests/pngsuite/cm7n0g04.png", None);
1694 trial("tests/pngsuite/cm9n0g04.png", None);
1695 trial("tests/pngsuite/cs3n2c16.png", None);
1696 trial("tests/pngsuite/cs3n3p08.png", None);
1697 trial("tests/pngsuite/cs5n2c08.png", None);
1698 trial("tests/pngsuite/cs5n3p08.png", None);
1699 trial("tests/pngsuite/cs8n2c08.png", None);
1700 trial("tests/pngsuite/cs8n3p08.png", None);
1701 trial("tests/pngsuite/ct0n0g04.png", None);
1702 trial("tests/pngsuite/ct1n0g04.png", None);
1703 trial("tests/pngsuite/cten0g04.png", None);
1704 trial("tests/pngsuite/ctfn0g04.png", None);
1705 trial("tests/pngsuite/ctgn0g04.png", None);
1706 trial("tests/pngsuite/cthn0g04.png", None);
1707 trial("tests/pngsuite/ctjn0g04.png", None);
1708 trial("tests/pngsuite/ctzn0g04.png", None);
1709 trial("tests/pngsuite/f00n0g08.png", None);
1710 trial("tests/pngsuite/f00n2c08.png", None);
1711 trial("tests/pngsuite/f01n0g08.png", None);
1712 trial("tests/pngsuite/f01n2c08.png", None);
1713 trial("tests/pngsuite/f02n0g08.png", None);
1714 trial("tests/pngsuite/f02n2c08.png", None);
1715 trial("tests/pngsuite/f03n0g08.png", None);
1716 trial("tests/pngsuite/f03n2c08.png", None);
1717 trial("tests/pngsuite/f04n0g08.png", None);
1718 trial("tests/pngsuite/f04n2c08.png", None);
1719 trial("tests/pngsuite/f99n0g04.png", None);
1720 trial("tests/pngsuite/g03n0g16.png", None);
1721 trial("tests/pngsuite/g03n2c08.png", None);
1722 trial("tests/pngsuite/g03n3p04.png", None);
1723 trial("tests/pngsuite/g04n0g16.png", None);
1724 trial("tests/pngsuite/g04n2c08.png", None);
1725 trial("tests/pngsuite/g04n3p04.png", None);
1726 trial("tests/pngsuite/g05n0g16.png", None);
1727 trial("tests/pngsuite/g05n2c08.png", None);
1728 trial("tests/pngsuite/g05n3p04.png", None);
1729 trial("tests/pngsuite/g07n0g16.png", None);
1730 trial("tests/pngsuite/g07n2c08.png", None);
1731 trial("tests/pngsuite/g07n3p04.png", None);
1732 trial("tests/pngsuite/g10n0g16.png", None);
1733 trial("tests/pngsuite/g10n2c08.png", None);
1734 trial("tests/pngsuite/g10n3p04.png", None);
1735 trial("tests/pngsuite/g25n0g16.png", None);
1736 trial("tests/pngsuite/g25n2c08.png", None);
1737 trial("tests/pngsuite/g25n3p04.png", None);
1738 trial("tests/pngsuite/oi1n0g16.png", None);
1739 trial("tests/pngsuite/oi1n2c16.png", None);
1740 trial("tests/pngsuite/oi2n0g16.png", None);
1741 trial("tests/pngsuite/oi2n2c16.png", None);
1742 trial("tests/pngsuite/oi4n0g16.png", None);
1743 trial("tests/pngsuite/oi4n2c16.png", None);
1744 trial("tests/pngsuite/oi9n0g16.png", None);
1745 trial("tests/pngsuite/oi9n2c16.png", None);
1746 trial("tests/pngsuite/PngSuite.png", None);
1747 trial("tests/pngsuite/pp0n2c16.png", None);
1748 trial("tests/pngsuite/pp0n6a08.png", None);
1749 trial("tests/pngsuite/ps1n0g08.png", None);
1750 trial("tests/pngsuite/ps1n2c16.png", None);
1751 trial("tests/pngsuite/ps2n0g08.png", None);
1752 trial("tests/pngsuite/ps2n2c16.png", None);
1753 trial("tests/pngsuite/s01i3p01.png", None);
1754 trial("tests/pngsuite/s01n3p01.png", None);
1755 trial("tests/pngsuite/s02i3p01.png", None);
1756 trial("tests/pngsuite/s02n3p01.png", None);
1757 trial("tests/pngsuite/s03i3p01.png", None);
1758 trial("tests/pngsuite/s03n3p01.png", None);
1759 trial("tests/pngsuite/s04i3p01.png", None);
1760 trial("tests/pngsuite/s04n3p01.png", None);
1761 trial("tests/pngsuite/s05i3p02.png", None);
1762 trial("tests/pngsuite/s05n3p02.png", None);
1763 trial("tests/pngsuite/s06i3p02.png", None);
1764 trial("tests/pngsuite/s06n3p02.png", None);
1765 trial("tests/pngsuite/s07i3p02.png", None);
1766 trial("tests/pngsuite/s07n3p02.png", None);
1767 trial("tests/pngsuite/s08i3p02.png", None);
1768 trial("tests/pngsuite/s08n3p02.png", None);
1769 trial("tests/pngsuite/s09i3p02.png", None);
1770 trial("tests/pngsuite/s09n3p02.png", None);
1771 trial("tests/pngsuite/s32i3p04.png", None);
1772 trial("tests/pngsuite/s32n3p04.png", None);
1773 trial("tests/pngsuite/s33i3p04.png", None);
1774 trial("tests/pngsuite/s33n3p04.png", None);
1775 trial("tests/pngsuite/s34i3p04.png", None);
1776 trial("tests/pngsuite/s34n3p04.png", None);
1777 trial("tests/pngsuite/s35i3p04.png", None);
1778 trial("tests/pngsuite/s35n3p04.png", None);
1779 trial("tests/pngsuite/s36i3p04.png", None);
1780 trial("tests/pngsuite/s36n3p04.png", None);
1781 trial("tests/pngsuite/s37i3p04.png", None);
1782 trial("tests/pngsuite/s37n3p04.png", None);
1783 trial("tests/pngsuite/s38i3p04.png", None);
1784 trial("tests/pngsuite/s38n3p04.png", None);
1785 trial("tests/pngsuite/s39i3p04.png", None);
1786 trial("tests/pngsuite/s39n3p04.png", None);
1787 trial("tests/pngsuite/s40i3p04.png", None);
1788 trial("tests/pngsuite/s40n3p04.png", None);
1789 trial("tests/pngsuite/tbbn0g04.png", None);
1790 trial("tests/pngsuite/tbbn2c16.png", None);
1791 trial("tests/pngsuite/tbbn3p08.png", None);
1792 trial("tests/pngsuite/tbgn2c16.png", None);
1793 trial("tests/pngsuite/tbgn3p08.png", None);
1794 trial("tests/pngsuite/tbrn2c08.png", None);
1795 trial("tests/pngsuite/tbwn0g16.png", None);
1796 trial("tests/pngsuite/tbwn3p08.png", None);
1797 trial("tests/pngsuite/tbyn3p08.png", None);
1798 trial("tests/pngsuite/tm3n3p02.png", None);
1799 trial("tests/pngsuite/tp0n0g08.png", None);
1800 trial("tests/pngsuite/tp0n2c08.png", None);
1801 trial("tests/pngsuite/tp0n3p08.png", None);
1802 trial("tests/pngsuite/tp1n3p08.png", None);
1803 trial("tests/pngsuite/z00n2c08.png", None);
1804 trial("tests/pngsuite/z03n2c08.png", None);
1805 trial("tests/pngsuite/z06n2c08.png", None);
1806 Ok(())
1807 }
1808
1809 #[test]
1812 fn test_two_iccp_chunks() {
1813 let decoder = crate::Decoder::new(File::open("tests/bugfixes/issue#1825.png").unwrap());
1818 let reader = decoder.read_info().unwrap();
1819 let icc_profile = reader.info().icc_profile.clone().unwrap().into_owned();
1820
1821 assert_eq!(4070462061, crc32fast::hash(&icc_profile));
1826 }
1827
1828 #[test]
1829 fn test_png_with_broken_iccp() {
1830 let decoder = crate::Decoder::new(File::open("tests/iccp/broken_iccp.png").unwrap());
1831 assert!(decoder.read_info().is_ok());
1832 let mut decoder = crate::Decoder::new(File::open("tests/iccp/broken_iccp.png").unwrap());
1833 decoder.set_ignore_iccp_chunk(true);
1834 assert!(decoder.read_info().is_ok());
1835 }
1836
1837 fn write_actl(w: &mut impl Write, animation: &crate::AnimationControl) {
1840 let mut data = Vec::new();
1841 data.write_u32::<byteorder::BigEndian>(animation.num_frames)
1842 .unwrap();
1843 data.write_u32::<byteorder::BigEndian>(animation.num_plays)
1844 .unwrap();
1845 write_chunk(w, b"acTL", &data);
1846 }
1847
1848 fn write_fctl(w: &mut impl Write, frame: &crate::FrameControl) {
1851 let mut data = Vec::new();
1852 data.write_u32::<byteorder::BigEndian>(frame.sequence_number)
1853 .unwrap();
1854 data.write_u32::<byteorder::BigEndian>(frame.width).unwrap();
1855 data.write_u32::<byteorder::BigEndian>(frame.height)
1856 .unwrap();
1857 data.write_u32::<byteorder::BigEndian>(frame.x_offset)
1858 .unwrap();
1859 data.write_u32::<byteorder::BigEndian>(frame.y_offset)
1860 .unwrap();
1861 data.write_u16::<byteorder::BigEndian>(frame.delay_num)
1862 .unwrap();
1863 data.write_u16::<byteorder::BigEndian>(frame.delay_den)
1864 .unwrap();
1865 data.write_u8(frame.dispose_op as u8).unwrap();
1866 data.write_u8(frame.blend_op as u8).unwrap();
1867 write_chunk(w, b"fcTL", &data);
1868 }
1869
1870 fn write_fdat(w: &mut impl Write, sequence_number: u32, image_data: &[u8]) {
1873 let mut data = Vec::new();
1874 data.write_u32::<byteorder::BigEndian>(sequence_number)
1875 .unwrap();
1876 data.write_all(image_data).unwrap();
1877 write_chunk(w, b"fdAT", &data);
1878 }
1879
1880 fn write_fdat_prefix(w: &mut impl Write, num_frames: u32, width: u32) {
1885 write_png_sig(w);
1886 write_rgba8_ihdr_with_width(w, width);
1887 write_actl(
1888 w,
1889 &crate::AnimationControl {
1890 num_frames,
1891 num_plays: 0,
1892 },
1893 );
1894
1895 let mut fctl = crate::FrameControl {
1896 width,
1897 height: width,
1898 ..Default::default()
1899 };
1900 write_fctl(w, &fctl);
1901 write_rgba8_idats(w, width, 0x7fffffff);
1902
1903 fctl.sequence_number += 1;
1904 write_fctl(w, &fctl);
1905 }
1906
1907 #[test]
1908 fn test_fdat_chunk_payload_length_0() {
1909 let mut png = Vec::new();
1910 write_fdat_prefix(&mut png, 2, 8);
1911 write_chunk(&mut png, b"fdAT", &[]);
1912
1913 let decoder = Decoder::new(png.as_slice());
1914 let mut reader = decoder.read_info().unwrap();
1915 let mut buf = vec![0; reader.output_buffer_size()];
1916 reader.next_frame(&mut buf).unwrap();
1917
1918 let err = reader.next_frame(&mut buf).unwrap_err();
1920 assert!(matches!(&err, DecodingError::Format(_)));
1921 let msg = format!("{err}");
1922 assert_eq!("fdAT chunk shorter than 4 bytes", msg);
1923 }
1924
1925 #[test]
1926 fn test_fdat_chunk_payload_length_3() {
1927 let mut png = Vec::new();
1928 write_fdat_prefix(&mut png, 2, 8);
1929 write_chunk(&mut png, b"fdAT", &[1, 0, 0]);
1930
1931 let decoder = Decoder::new(png.as_slice());
1932 let mut reader = decoder.read_info().unwrap();
1933 let mut buf = vec![0; reader.output_buffer_size()];
1934 reader.next_frame(&mut buf).unwrap();
1935
1936 let err = reader.next_frame(&mut buf).unwrap_err();
1938 assert!(matches!(&err, DecodingError::Format(_)));
1939 let msg = format!("{err}");
1940 assert_eq!("fdAT chunk shorter than 4 bytes", msg);
1941 }
1942
1943 #[test]
1944 fn test_frame_split_across_two_fdat_chunks() {
1945 let png = {
1960 let mut png = Vec::new();
1961 write_fdat_prefix(&mut png, 2, 8);
1962 let image_data = generate_rgba8_with_width_and_height(8, 8);
1963 write_fdat(&mut png, 2, &image_data[..30]);
1964 write_fdat(&mut png, 3, &image_data[30..]);
1965 write_iend(&mut png);
1966 png
1967 };
1968
1969 let decoder = Decoder::new(png.as_slice());
1971 let mut reader = decoder.read_info().unwrap();
1972 let mut buf = vec![0; reader.output_buffer_size()];
1973 let Some(animation_control) = reader.info().animation_control else {
1974 panic!("No acTL");
1975 };
1976 assert_eq!(animation_control.num_frames, 2);
1977
1978 let first_frame: Vec<u8>;
1980 {
1981 reader.next_frame(&mut buf).unwrap();
1982 first_frame = buf.clone();
1983
1984 let Some(frame_control) = reader.info().frame_control else {
1988 panic!("No fcTL (1st frame)");
1989 };
1990 assert_eq!(frame_control.sequence_number, 0);
1993 }
1994
1995 let second_frame: Vec<u8>;
1997 {
1998 reader.next_frame(&mut buf).unwrap();
1999 second_frame = buf.clone();
2000
2001 let Some(frame_control) = reader.info().frame_control else {
2003 panic!("No fcTL (2nd frame)");
2004 };
2005 assert_eq!(frame_control.sequence_number, 1);
2009 }
2010
2011 assert_eq!(first_frame, second_frame);
2012 }
2013
2014 #[test]
2015 fn test_idat_bigger_than_image_size_from_ihdr() {
2016 let png = {
2017 let mut png = Vec::new();
2018 write_png_sig(&mut png);
2019 write_rgba8_ihdr_with_width(&mut png, 8);
2020
2021 write_chunk(
2025 &mut png,
2026 b"IDAT",
2027 &generate_rgba8_with_width_and_height(8, 256),
2028 );
2029
2030 write_iend(&mut png);
2031 png
2032 };
2033 let decoder = Decoder::new(png.as_slice());
2034 let mut reader = decoder.read_info().unwrap();
2035 let mut buf = vec![0; reader.output_buffer_size()];
2036
2037 reader.next_frame(&mut buf).unwrap();
2040 assert_eq!(3093270825, crc32fast::hash(&buf));
2041 }
2042
2043 #[derive(Clone)]
2046 struct StreamingInput(Rc<RefCell<StreamingInputState>>);
2047
2048 struct StreamingInputState {
2049 full_input: Vec<u8>,
2050 current_pos: usize,
2051 available_len: usize,
2052 }
2053
2054 impl StreamingInput {
2055 fn new(full_input: Vec<u8>) -> Self {
2056 Self(Rc::new(RefCell::new(StreamingInputState {
2057 full_input,
2058 current_pos: 0,
2059 available_len: 0,
2060 })))
2061 }
2062
2063 fn with_noncompressed_png(width: u32, idat_size: usize) -> Self {
2064 let mut png = Vec::new();
2065 write_noncompressed_png(&mut png, width, idat_size);
2066 Self::new(png)
2067 }
2068
2069 fn expose_next_byte(&self) {
2070 let mut state = self.0.borrow_mut();
2071 assert!(state.available_len < state.full_input.len());
2072 state.available_len += 1;
2073 }
2074
2075 fn stream_input_until_reader_is_available(&self) -> Reader<StreamingInput> {
2076 loop {
2077 self.0.borrow_mut().current_pos = 0;
2078 match Decoder::new(self.clone()).read_info() {
2079 Ok(reader) => {
2080 break reader;
2081 }
2082 Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2083 self.expose_next_byte();
2084 }
2085 _ => panic!("Unexpected error"),
2086 }
2087 }
2088 }
2089
2090 fn decode_full_input<F, R>(&self, f: F) -> R
2091 where
2092 F: FnOnce(Reader<&[u8]>) -> R,
2093 {
2094 let state = self.0.borrow();
2095 let decoder = Decoder::new(state.full_input.as_slice());
2096 f(decoder.read_info().unwrap())
2097 }
2098 }
2099
2100 impl Read for StreamingInput {
2101 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
2102 let mut state = self.0.borrow_mut();
2103 let mut available_bytes = &state.full_input[state.current_pos..state.available_len];
2104 let number_of_read_bytes = available_bytes.read(buf)?;
2105 state.current_pos += number_of_read_bytes;
2106 assert!(state.current_pos <= state.available_len);
2107 Ok(number_of_read_bytes)
2108 }
2109 }
2110
2111 #[test]
2113 fn test_streaming_input_and_decoding_via_next_frame() {
2114 const WIDTH: u32 = 16;
2115 const IDAT_SIZE: usize = 512;
2116 let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2117
2118 let (whole_output_info, decoded_from_whole_input) =
2119 streaming_input.decode_full_input(|mut r| {
2120 let mut buf = vec![0; r.output_buffer_size()];
2121 let output_info = r.next_frame(&mut buf).unwrap();
2122 (output_info, buf)
2123 });
2124
2125 let mut png_reader = streaming_input.stream_input_until_reader_is_available();
2126 let mut decoded_from_streaming_input = vec![0; png_reader.output_buffer_size()];
2127 let streaming_output_info = loop {
2128 match png_reader.next_frame(decoded_from_streaming_input.as_mut_slice()) {
2129 Ok(output_info) => break output_info,
2130 Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2131 streaming_input.expose_next_byte()
2132 }
2133 e => panic!("Unexpected error: {:?}", e),
2134 }
2135 };
2136 assert_eq!(whole_output_info, streaming_output_info);
2137 assert_eq!(
2138 crc32fast::hash(&decoded_from_whole_input),
2139 crc32fast::hash(&decoded_from_streaming_input)
2140 );
2141 }
2142
2143 #[test]
2145 fn test_streaming_input_and_decoding_via_next_row() {
2146 const WIDTH: u32 = 16;
2147 const IDAT_SIZE: usize = 512;
2148 let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2149
2150 let decoded_from_whole_input = streaming_input.decode_full_input(|mut r| {
2151 let mut buf = vec![0; r.output_buffer_size()];
2152 r.next_frame(&mut buf).unwrap();
2153 buf
2154 });
2155
2156 let mut png_reader = streaming_input.stream_input_until_reader_is_available();
2157 let mut decoded_from_streaming_input = Vec::new();
2158 loop {
2159 match png_reader.next_row() {
2160 Ok(None) => break,
2161 Ok(Some(row)) => decoded_from_streaming_input.extend_from_slice(row.data()),
2162 Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2163 streaming_input.expose_next_byte()
2164 }
2165 e => panic!("Unexpected error: {:?}", e),
2166 }
2167 }
2168 assert_eq!(
2169 crc32fast::hash(&decoded_from_whole_input),
2170 crc32fast::hash(&decoded_from_streaming_input)
2171 );
2172 }
2173
2174 #[test]
2176 fn test_streaming_input_and_reading_header_info() {
2177 const WIDTH: u32 = 16;
2178 const IDAT_SIZE: usize = 512;
2179 let streaming_input = StreamingInput::with_noncompressed_png(WIDTH, IDAT_SIZE);
2180
2181 let info_from_whole_input = streaming_input.decode_full_input(|r| r.info().clone());
2182
2183 let mut decoder = Decoder::new(streaming_input.clone());
2184 let info_from_streaming_input = loop {
2185 match decoder.read_header_info() {
2186 Ok(info) => break info.clone(),
2187 Err(DecodingError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
2188 streaming_input.expose_next_byte()
2189 }
2190 e => panic!("Unexpected error: {:?}", e),
2191 }
2192 };
2193
2194 assert_eq!(info_from_whole_input.width, info_from_streaming_input.width);
2195 assert_eq!(
2196 info_from_whole_input.height,
2197 info_from_streaming_input.height
2198 );
2199 assert_eq!(
2200 info_from_whole_input.bit_depth,
2201 info_from_streaming_input.bit_depth
2202 );
2203 assert_eq!(
2204 info_from_whole_input.color_type,
2205 info_from_streaming_input.color_type
2206 );
2207 assert_eq!(
2208 info_from_whole_input.interlaced,
2209 info_from_streaming_input.interlaced
2210 );
2211 }
2212}