Skip to main content

png/decoder/
mod.rs

1mod interlace_info;
2mod read_decoder;
3pub(crate) mod stream;
4pub(crate) mod transform;
5mod unfiltering_buffer;
6mod zlib;
7
8use self::read_decoder::{ImageDataCompletionStatus, ReadDecoder};
9use self::stream::{DecodeOptions, DecodingError, FormatErrorInner};
10use self::transform::{create_transform_fn, TransformFn};
11use self::unfiltering_buffer::UnfilteringBuffer;
12
13use std::io::{BufRead, Seek};
14use std::mem;
15
16use crate::adam7::Adam7Info;
17use crate::common::{
18    BitDepth, BytesPerPixel, ColorType, Info, ParameterErrorKind, Transformations,
19};
20use crate::FrameControl;
21pub use zlib::{UnfilterBuf, UnfilterRegion};
22
23pub use interlace_info::InterlaceInfo;
24use interlace_info::InterlaceInfoIter;
25
26/*
27pub enum InterlaceHandling {
28    /// Outputs the raw rows
29    RawRows,
30    /// Fill missing the pixels from the existing ones
31    Rectangle,
32    /// Only fill the needed pixels
33    Sparkle
34}
35*/
36
37/// Output info.
38///
39/// This describes one particular frame of the image that was written into the output buffer.
40#[derive(Debug, PartialEq, Eq)]
41pub struct OutputInfo {
42    /// The pixel width of this frame.
43    pub width: u32,
44    /// The pixel height of this frame.
45    pub height: u32,
46    /// The chosen output color type.
47    pub color_type: ColorType,
48    /// The chosen output bit depth.
49    pub bit_depth: BitDepth,
50    /// The byte count of each scan line in the image.
51    pub line_size: usize,
52}
53
54impl OutputInfo {
55    /// Returns the size needed to hold a decoded frame
56    /// If the output buffer was larger then bytes after this count should be ignored. They may
57    /// still have been changed.
58    pub fn buffer_size(&self) -> usize {
59        self.line_size * self.height as usize
60    }
61}
62
63#[derive(Clone, Copy, Debug)]
64/// Limits on the resources the `Decoder` is allowed too use
65pub struct Limits {
66    /// maximum number of bytes the decoder is allowed to allocate, default is 64Mib
67    pub bytes: usize,
68}
69
70impl Limits {
71    pub(crate) fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> {
72        if self.bytes >= bytes {
73            self.bytes -= bytes;
74            Ok(())
75        } else {
76            Err(DecodingError::LimitsExceeded)
77        }
78    }
79}
80
81impl Default for Limits {
82    fn default() -> Limits {
83        Limits {
84            bytes: 1024 * 1024 * 64,
85        }
86    }
87}
88
89/// PNG Decoder
90pub struct Decoder<R: BufRead + Seek> {
91    read_decoder: ReadDecoder<R>,
92    /// Output transformations
93    transform: Transformations,
94}
95
96/// A row of data with interlace information attached.
97#[derive(Clone, Copy, Debug)]
98pub struct InterlacedRow<'data> {
99    data: &'data [u8],
100    interlace: InterlaceInfo,
101}
102
103impl<'data> InterlacedRow<'data> {
104    pub fn data(&self) -> &'data [u8] {
105        self.data
106    }
107
108    pub fn interlace(&self) -> &InterlaceInfo {
109        &self.interlace
110    }
111}
112
113/// A row of data without interlace information.
114#[derive(Clone, Copy, Debug)]
115pub struct Row<'data> {
116    data: &'data [u8],
117}
118
119impl<'data> Row<'data> {
120    pub fn data(&self) -> &'data [u8] {
121        self.data
122    }
123}
124
125impl<R: BufRead + Seek> Decoder<R> {
126    /// Create a new decoder configuration with default limits.
127    pub fn new(r: R) -> Decoder<R> {
128        Decoder::new_with_limits(r, Limits::default())
129    }
130
131    /// Create a new decoder configuration with custom limits.
132    pub fn new_with_limits(r: R, limits: Limits) -> Decoder<R> {
133        let mut read_decoder = ReadDecoder::new(r);
134        read_decoder.set_limits(limits);
135
136        Decoder {
137            read_decoder,
138            transform: Transformations::IDENTITY,
139        }
140    }
141
142    /// Create a new decoder configuration with custom [`DecodeOptions`].
143    pub fn new_with_options(r: R, decode_options: DecodeOptions) -> Decoder<R> {
144        let mut read_decoder = ReadDecoder::with_options(r, decode_options);
145        read_decoder.set_limits(Limits::default());
146
147        Decoder {
148            read_decoder,
149            transform: Transformations::IDENTITY,
150        }
151    }
152
153    /// Limit resource usage.
154    ///
155    /// Note that your allocations, e.g. when reading into a pre-allocated buffer, are __NOT__
156    /// considered part of the limits. Nevertheless, required intermediate buffers such as for
157    /// singular lines is checked against the limit.
158    ///
159    /// Note that this is a best-effort basis.
160    ///
161    /// ```
162    /// use std::fs::File;
163    /// use std::io::BufReader;
164    /// use png::{Decoder, Limits};
165    /// // This image is 32×32, 1bit per pixel. The reader buffers one row which requires 4 bytes.
166    /// let mut limits = Limits::default();
167    /// limits.bytes = 3;
168    /// let mut decoder = Decoder::new_with_limits(BufReader::new(File::open("tests/pngsuite/basi0g01.png").unwrap()), limits);
169    /// assert!(decoder.read_info().is_err());
170    ///
171    /// // This image is 32x32 pixels, so the decoder will allocate less than 10Kib
172    /// let mut limits = Limits::default();
173    /// limits.bytes = 10*1024;
174    /// let mut decoder = Decoder::new_with_limits(BufReader::new(File::open("tests/pngsuite/basi0g01.png").unwrap()), limits);
175    /// assert!(decoder.read_info().is_ok());
176    /// ```
177    pub fn set_limits(&mut self, limits: Limits) {
178        self.read_decoder.set_limits(limits);
179    }
180
181    /// Read the PNG header and return the information contained within.
182    ///
183    /// Most image metadata will not be read until [`read_info`] is called, so those fields will be
184    /// None or empty.
185    ///
186    /// [`read_info`]: Self::read_info
187    pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> {
188        self.read_decoder.read_header_info()
189    }
190
191    /// Reads all meta data until the first IDAT chunk
192    pub fn read_info(mut self) -> Result<Reader<R>, DecodingError> {
193        let info = self.read_header_info()?;
194        let unfiltering_buffer = UnfilteringBuffer::new(info);
195
196        let mut reader = Reader {
197            decoder: self.read_decoder,
198            bpp: BytesPerPixel::One,
199            subframe: SubframeInfo::not_yet_init(),
200            remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`.
201            unfiltering_buffer,
202            transform: self.transform,
203            transform_fn: None,
204            scratch_buffer: Vec::new(),
205            finished: false,
206        };
207
208        // Check if the decoding buffer of a single raw line has a valid size.
209        //
210        // FIXME: this check and the next can be delayed until processing image data. This would
211        // allow usage where only the metadata is processes, or where the image is processed
212        // line-by-line even on targets that can not fit the whole image into their address space.
213        // We should strive for a balance between implementation complexity (still ensure that the
214        // no-overflow preconditions are met for internal calculation) and use possibilities.
215        if reader.info().checked_raw_row_length().is_none() {
216            return Err(DecodingError::LimitsExceeded);
217        }
218
219        // Check if the output buffer has a valid size.
220        //
221        // FIXME: see above and
222        // <https://github.com/image-rs/image-png/pull/608#issuecomment-3003576956>
223        if reader.output_buffer_size().is_none() {
224            return Err(DecodingError::LimitsExceeded);
225        }
226
227        reader.read_until_image_data()?;
228
229        reader.remaining_frames = match reader.info().animation_control.as_ref() {
230            None => 1, // No `acTL` => only expecting `IDAT` frame.
231            Some(animation) => {
232                // Note: limited to (2^32 - 1) frames by the APNG spec so addition does not
233                // overflow on 32-bit targets nor 64-bit targets.
234                let mut num_frames = animation.num_frames;
235                if reader.info().frame_control.is_none() {
236                    // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but
237                    // represents an *extra*, default frame for non-APNG-aware decoders.
238                    num_frames += 1;
239                }
240                num_frames
241            }
242        };
243        Ok(reader)
244    }
245
246    /// Set the allowed and performed transformations.
247    ///
248    /// A transformation is a pre-processing on the raw image data modifying content or encoding.
249    /// Many options have an impact on memory or CPU usage during decoding.
250    pub fn set_transformations(&mut self, transform: Transformations) {
251        self.transform = transform;
252    }
253
254    /// Set the decoder to ignore all text chunks while parsing.
255    ///
256    /// eg.
257    /// ```
258    /// use std::fs::File;
259    /// use std::io::BufReader;
260    /// use png::Decoder;
261    /// let mut decoder = Decoder::new(BufReader::new(File::open("tests/pngsuite/basi0g01.png").unwrap()));
262    /// decoder.set_ignore_text_chunk(true);
263    /// assert!(decoder.read_info().is_ok());
264    /// ```
265    pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
266        self.read_decoder.set_ignore_text_chunk(ignore_text_chunk);
267    }
268
269    /// Set the decoder to ignore iccp chunks while parsing.
270    ///
271    /// eg.
272    /// ```
273    /// use std::fs::File;
274    /// use std::io::BufReader;
275    /// use png::Decoder;
276    /// let mut decoder = Decoder::new(BufReader::new(File::open("tests/iccp/broken_iccp.png").unwrap()));
277    /// decoder.set_ignore_iccp_chunk(true);
278    /// assert!(decoder.read_info().is_ok());
279    /// ```
280    pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
281        self.read_decoder.set_ignore_iccp_chunk(ignore_iccp_chunk);
282    }
283
284    /// Set the decoder to ignore and not verify the Adler-32 checksum
285    /// and CRC code.
286    pub fn ignore_checksums(&mut self, ignore_checksums: bool) {
287        self.read_decoder.ignore_checksums(ignore_checksums);
288    }
289}
290
291/// PNG reader (mostly high-level interface)
292///
293/// Provides a high level that iterates over lines or whole images.
294pub struct Reader<R: BufRead + Seek> {
295    decoder: ReadDecoder<R>,
296    bpp: BytesPerPixel,
297    subframe: SubframeInfo,
298    /// How many frames remain to be decoded.  Decremented after each `IDAT` or `fdAT` sequence.
299    remaining_frames: u32,
300    /// Buffer with not-yet-`unfilter`-ed image rows
301    unfiltering_buffer: UnfilteringBuffer,
302    /// Output transformations
303    transform: Transformations,
304    /// Function that can transform decompressed, unfiltered rows into final output.
305    /// See the `transform.rs` module for more details.
306    transform_fn: Option<TransformFn>,
307    /// This buffer is only used so that `next_row` and `next_interlaced_row` can return reference
308    /// to a byte slice. In a future version of this library, this buffer will be removed and
309    /// `next_row` and `next_interlaced_row` will write directly into a user provided output buffer.
310    scratch_buffer: Vec<u8>,
311    /// Whether `ImageEnd` was already reached by `fn finish`.
312    finished: bool,
313}
314
315/// The subframe specific information.
316///
317/// In APNG the frames are constructed by combining previous frame and a new subframe (through a
318/// combination of `dispose_op` and `overlay_op`). These sub frames specify individual dimension
319/// information and reuse the global interlace options. This struct encapsulates the state of where
320/// in a particular IDAT-frame or subframe we are.
321struct SubframeInfo {
322    width: u32,
323    height: u32,
324    rowlen: usize,
325    current_interlace_info: Option<InterlaceInfo>,
326    interlace_info_iter: InterlaceInfoIter,
327    consumed_and_flushed: bool,
328}
329
330impl<R: BufRead + Seek> Reader<R> {
331    /// Advances to the start of the next animation frame and
332    /// returns a reference to the [`FrameControl`] info that describes it.
333    /// Skips and discards the image data of the previous frame if necessary.
334    ///
335    /// Returns a [`ParameterError`] when there are no more animation frames.
336    /// To avoid this the caller can check if [`Info::animation_control`] exists
337    /// and consult [`AnimationControl::num_frames`].
338    ///
339    /// [`ParameterError`]: crate::ParameterError
340    /// [`AnimationControl::num_frames`]: crate::AnimationControl::num_frames
341    pub fn next_frame_info(&mut self) -> Result<&FrameControl, DecodingError> {
342        let remaining_frames = if self.subframe.consumed_and_flushed {
343            self.remaining_frames
344        } else {
345            // One remaining frame will be consumed by the `finish_decoding` call below.
346            self.remaining_frames - 1
347        };
348        if remaining_frames == 0 {
349            return Err(DecodingError::Parameter(
350                ParameterErrorKind::PolledAfterEndOfImage.into(),
351            ));
352        }
353
354        if !self.subframe.consumed_and_flushed {
355            self.subframe.current_interlace_info = None;
356            self.finish_decoding()?;
357        }
358        self.read_until_image_data()?;
359
360        // The PNG standard (and `StreamingDecoder `) guarantes that there is an `fcTL` chunk
361        // before the start of image data in a sequence of `fdAT` chunks.  Therefore `unwrap`
362        // below is guaranteed to not panic.
363        Ok(self.info().frame_control.as_ref().unwrap())
364    }
365
366    /// Reads all meta data until the next frame data starts.
367    /// Requires IHDR before the IDAT and fcTL before fdAT.
368    fn read_until_image_data(&mut self) -> Result<(), DecodingError> {
369        self.decoder.read_until_image_data()?;
370
371        self.subframe = SubframeInfo::new(self.info());
372        self.bpp = self.info().bpp_in_prediction();
373
374        let frame_bytes = if self.info().interlaced {
375            let mut bytes = 0u64;
376            for pass in crate::adam7::PassConstants::PASSES {
377                bytes += self
378                    .info()
379                    .raw_row_length_from_width(pass.count_samples(self.subframe.width))
380                    as u64
381                    * pass.count_lines(self.subframe.height) as u64;
382            }
383            bytes
384        } else {
385            (self.subframe.rowlen as u64) * self.subframe.height as u64
386        };
387        self.unfiltering_buffer.start_frame(frame_bytes);
388
389        // Allocate output buffer.
390        let buflen = self.unguarded_output_line_size(self.subframe.width);
391        self.decoder.reserve_bytes(buflen)?;
392
393        Ok(())
394    }
395
396    /// Get information on the image.
397    ///
398    /// The structure will change as new frames of an animated image are decoded.
399    pub fn info(&self) -> &Info<'static> {
400        self.decoder.info().unwrap()
401    }
402
403    /// Decodes the next frame into `buf`.
404    ///
405    /// Note that this decodes raw subframes that need to be mixed according to blend-op and
406    /// dispose-op by the caller.
407    ///
408    /// The caller must always provide a buffer large enough to hold a complete frame (the APNG
409    /// specification restricts subframes to the dimensions given in the image header). The region
410    /// that has been written be checked afterwards by calling [`Reader::info`] after a successful call and
411    /// inspecting the `frame_control` data. This requirement may be lifted in a later version of
412    /// `png`.
413    ///
414    /// Output lines will be written in row-major, packed matrix with width and height of the read
415    /// frame (or subframe), all samples are in big endian byte order where this matters.
416    pub fn next_frame(&mut self, buf: &mut [u8]) -> Result<OutputInfo, DecodingError> {
417        if self.remaining_frames == 0 {
418            return Err(DecodingError::Parameter(
419                ParameterErrorKind::PolledAfterEndOfImage.into(),
420            ));
421        } else if self.subframe.consumed_and_flushed {
422            // Advance until the next `fdAT`
423            // (along the way we should encounter the fcTL for this frame).
424            self.read_until_image_data()?;
425        }
426
427        // Note that we only check if the buffer size calculation holds in a call to decoding the
428        // frame. Consequently, we can represent the `Info` and frameless decoding even when the
429        // target architecture's address space is too small for a frame. However reading the actual
430        let required_len = self
431            .output_buffer_size()
432            .ok_or(DecodingError::LimitsExceeded)?;
433
434        if buf.len() < required_len {
435            return Err(DecodingError::Parameter(
436                ParameterErrorKind::ImageBufferSize {
437                    expected: required_len,
438                    actual: buf.len(),
439                }
440                .into(),
441            ));
442        }
443
444        let (color_type, bit_depth) = self.output_color_type();
445        let output_info = OutputInfo {
446            width: self.subframe.width,
447            height: self.subframe.height,
448            color_type,
449            bit_depth,
450            line_size: self.unguarded_output_line_size(self.subframe.width),
451        };
452
453        if self.info().interlaced {
454            let stride = self.unguarded_output_line_size(self.info().width);
455            let samples = color_type.samples() as u8;
456            let bits_pp = samples * (bit_depth as u8);
457            let expand = crate::adam7::expand_pass;
458
459            while let Some(InterlacedRow {
460                data: row,
461                interlace,
462                ..
463            }) = self.next_interlaced_row()?
464            {
465                // `unwrap` won't panic, because we checked `self.info().interlaced` above.
466                let adam7info = interlace.get_adam7_info().unwrap();
467                expand(buf, stride, row, adam7info, bits_pp);
468            }
469        } else {
470            let current_interlace_info = self.subframe.current_interlace_info.as_ref();
471            let already_done_rows = current_interlace_info
472                .map(|info| info.line_number())
473                .unwrap_or(self.subframe.height);
474
475            for row in buf
476                .chunks_exact_mut(output_info.line_size)
477                .take(self.subframe.height as usize)
478                .skip(already_done_rows as usize)
479            {
480                self.next_interlaced_row_impl(self.subframe.rowlen, row)?;
481            }
482        }
483
484        // Advance over the rest of data for this (sub-)frame.
485        self.finish_decoding()?;
486
487        Ok(output_info)
488    }
489
490    fn mark_subframe_as_consumed_and_flushed(&mut self) {
491        assert!(self.remaining_frames > 0);
492        self.remaining_frames -= 1;
493
494        self.subframe.consumed_and_flushed = true;
495    }
496
497    /// Advance over the rest of data for this (sub-)frame.
498    /// Called after decoding the last row of a frame.
499    fn finish_decoding(&mut self) -> Result<(), DecodingError> {
500        // Double-check that all rows of this frame have been decoded (i.e. that the potential
501        // `finish_decoding` call below won't be discarding any data).
502        assert!(self.subframe.current_interlace_info.is_none());
503
504        // Discard the remaining data in the current sequence of `IDAT` or `fdAT` chunks.
505        if !self.subframe.consumed_and_flushed {
506            self.decoder.finish_decoding_image_data()?;
507            self.mark_subframe_as_consumed_and_flushed();
508        }
509
510        Ok(())
511    }
512
513    /// Returns the next processed row of the image (discarding [`InterlaceInfo`]).
514    ///
515    /// See also [`Reader::read_row`], which reads into a caller-provided buffer.
516    pub fn next_row(&mut self) -> Result<Option<Row<'_>>, DecodingError> {
517        self.next_interlaced_row()
518            .map(|v| v.map(|v| Row { data: v.data }))
519    }
520
521    /// Returns the next processed row of the image.
522    ///
523    /// See also [`Reader::read_row`], which reads into a caller-provided buffer.
524    pub fn next_interlaced_row(&mut self) -> Result<Option<InterlacedRow<'_>>, DecodingError> {
525        let mut output_buffer = mem::take(&mut self.scratch_buffer);
526        let max_line_size = self
527            .output_line_size(self.info().width)
528            .ok_or(DecodingError::LimitsExceeded)?;
529        output_buffer.resize(max_line_size, 0u8);
530        let result = self.read_row(&mut output_buffer);
531        self.scratch_buffer = output_buffer;
532        result.map(move |option| {
533            option.map(move |interlace| {
534                let output_line_size = self.output_line_size_for_interlace_info(&interlace);
535                InterlacedRow {
536                    data: &self.scratch_buffer[..output_line_size],
537                    interlace,
538                }
539            })
540        })
541    }
542
543    /// Reads the next row of the image into the provided `output_buffer`.
544    /// `Ok(None)` will be returned if the current image frame has no more rows.
545    ///
546    /// `output_buffer` needs to be long enough to accommodate [`Reader::output_line_size`] for
547    /// [`Info::width`] (initial interlaced rows may need less than that).
548    ///
549    /// See also [`Reader::next_row`] and [`Reader::next_interlaced_row`], which read into a
550    /// `Reader`-owned buffer.
551    pub fn read_row(
552        &mut self,
553        output_buffer: &mut [u8],
554    ) -> Result<Option<InterlaceInfo>, DecodingError> {
555        let interlace = match self.subframe.current_interlace_info.as_ref() {
556            None => {
557                self.finish_decoding()?;
558                return Ok(None);
559            }
560            Some(interlace) => *interlace,
561        };
562        if interlace.line_number() == 0 {
563            self.unfiltering_buffer.reset_prev_row();
564        }
565        let rowlen = match interlace {
566            InterlaceInfo::Null(_) => self.subframe.rowlen,
567            InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => {
568                self.info().raw_row_length_from_width(width)
569            }
570        };
571
572        let output_line_size = self.output_line_size_for_interlace_info(&interlace);
573        let output_buffer = &mut output_buffer[..output_line_size];
574
575        self.next_interlaced_row_impl(rowlen, output_buffer)?;
576
577        Ok(Some(interlace))
578    }
579
580    fn output_line_size_for_interlace_info(&self, interlace: &InterlaceInfo) -> usize {
581        let width = match interlace {
582            InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => *width,
583            InterlaceInfo::Null(_) => self.subframe.width,
584        };
585        self.unguarded_output_line_size(width)
586    }
587
588    /// Read the rest of the image and chunks and finish up, including text chunks or others
589    /// This will discard the rest of the image if the image is not read already with [`Reader::next_frame`], [`Reader::next_row`] or [`Reader::next_interlaced_row`]
590    pub fn finish(&mut self) -> Result<(), DecodingError> {
591        if self.finished {
592            return Err(DecodingError::Parameter(
593                ParameterErrorKind::PolledAfterEndOfImage.into(),
594            ));
595        }
596
597        self.remaining_frames = 0;
598        self.decoder.read_until_end_of_input()?;
599
600        self.finished = true;
601        Ok(())
602    }
603
604    /// Fetch the next interlaced row and filter it according to our own transformations.
605    fn next_interlaced_row_impl(
606        &mut self,
607        rowlen: usize,
608        output_buffer: &mut [u8],
609    ) -> Result<(), DecodingError> {
610        self.next_raw_interlaced_row(rowlen)?;
611        let row = self.unfiltering_buffer.prev_row();
612        assert_eq!(row.len(), rowlen - 1);
613
614        // Apply transformations and write resulting data to buffer.
615        let transform_fn = {
616            if self.transform_fn.is_none() {
617                self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?);
618            }
619            self.transform_fn.as_deref().unwrap()
620        };
621        transform_fn(row, output_buffer, self.info());
622
623        self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next();
624        Ok(())
625    }
626
627    /// Returns the color type and the number of bits per sample
628    /// of the data returned by [`Reader::next_row`] and [`Reader::next_frame`].
629    pub fn output_color_type(&self) -> (ColorType, BitDepth) {
630        use crate::common::ColorType::*;
631        let t = self.transform;
632        let info = self.info();
633        if t == Transformations::IDENTITY {
634            (info.color_type, info.bit_depth)
635        } else {
636            let bits = match info.bit_depth as u8 {
637                16 if t.intersects(Transformations::STRIP_16) => 8,
638                n if n < 8
639                    && (t.contains(Transformations::EXPAND)
640                        || t.contains(Transformations::ALPHA)) =>
641                {
642                    8
643                }
644                n => n,
645            };
646            let color_type =
647                if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) {
648                    let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA);
649                    match info.color_type {
650                        Grayscale if has_trns => GrayscaleAlpha,
651                        Rgb if has_trns => Rgba,
652                        Indexed if has_trns => Rgba,
653                        Indexed => Rgb,
654                        ct => ct,
655                    }
656                } else {
657                    info.color_type
658                };
659            (color_type, BitDepth::from_u8(bits).unwrap())
660        }
661    }
662
663    /// Return the number of bytes required to hold a deinterlaced image frame that is decoded
664    /// using the given input transformations.
665    ///
666    /// Returns `None` if the output buffer does not fit into the memory space of the machine,
667    /// otherwise returns the byte length in `Some`. The length is smaller than [`isize::MAX`].
668    pub fn output_buffer_size(&self) -> Option<usize> {
669        let (width, height) = self.info().size();
670        let (color, depth) = self.output_color_type();
671        // The subtraction should always work, but we do this for consistency. Also note that by
672        // calling `checked_raw_row_length` the row buffer is guaranteed to work whereas if we
673        // ran other function that didn't include the filter byte that could later fail on an image
674        // that is `1xN`...
675        let linelen = color.checked_raw_row_length(depth, width)?.checked_sub(1)?;
676        let height = usize::try_from(height).ok()?;
677        let imglen = linelen.checked_mul(height)?;
678        // Ensure that it fits into address space not only `usize` to allocate.
679        (imglen <= isize::MAX as usize).then_some(imglen)
680    }
681
682    /// Returns the number of bytes required to hold a deinterlaced row.
683    pub(crate) fn unguarded_output_line_size(&self, width: u32) -> usize {
684        let (color, depth) = self.output_color_type();
685        color.raw_row_length_from_width(depth, width) - 1
686    }
687
688    /// Returns the number of bytes required to hold a deinterlaced row.
689    ///
690    /// Returns `None` if the output buffer does not fit into the memory space of the machine,
691    /// otherwise returns the byte length in `Some`. The length is smaller than [`isize::MAX`].
692    pub fn output_line_size(&self, width: u32) -> Option<usize> {
693        let (color, depth) = self.output_color_type();
694        let length = color.checked_raw_row_length(depth, width)?.checked_sub(1)?;
695        // Ensure that it fits into address space not only `usize` to allocate.
696        (length <= isize::MAX as usize).then_some(length)
697    }
698
699    /// Unfilter the next raw interlaced row into `self.unfiltering_buffer`.
700    fn next_raw_interlaced_row(&mut self, rowlen: usize) -> Result<(), DecodingError> {
701        // Read image data until we have at least one full row (but possibly more than one).
702        while self.unfiltering_buffer.mutable_len_of_curr_row() < rowlen {
703            if self.subframe.consumed_and_flushed {
704                return Err(DecodingError::Format(
705                    FormatErrorInner::NoMoreImageData.into(),
706                ));
707            }
708
709            assert!(self.unfiltering_buffer.remaining_bytes() > 0);
710            let completion_status = self
711                .unfiltering_buffer
712                .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer)));
713            match completion_status {
714                Ok(ImageDataCompletionStatus::ExpectingMoreData) => (),
715                Ok(ImageDataCompletionStatus::Done) => self.mark_subframe_as_consumed_and_flushed(),
716                Err(DecodingError::IoError(e))
717                    if e.kind() == std::io::ErrorKind::UnexpectedEof
718                        && self.unfiltering_buffer.readable_len_of_curr_row() >= rowlen =>
719                {
720                    return self
721                        .unfiltering_buffer
722                        .unfilter_curr_row_using_scratch_buffer(rowlen, self.bpp);
723                }
724                Err(other_error) => return Err(other_error),
725            }
726        }
727
728        self.unfiltering_buffer
729            .unfilter_curr_row_in_place(rowlen, self.bpp)
730    }
731}
732
733impl SubframeInfo {
734    fn not_yet_init() -> Self {
735        SubframeInfo {
736            width: 0,
737            height: 0,
738            rowlen: 0,
739            current_interlace_info: None,
740            interlace_info_iter: InterlaceInfoIter::empty(),
741            consumed_and_flushed: false,
742        }
743    }
744
745    fn new(info: &Info) -> Self {
746        // The apng fctnl overrides width and height.
747        // All other data is set by the main info struct.
748        let (width, height) = if let Some(fc) = info.frame_control {
749            (fc.width, fc.height)
750        } else {
751            (info.width, info.height)
752        };
753
754        let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced);
755        let current_interlace_info = interlace_info_iter.next();
756        SubframeInfo {
757            width,
758            height,
759            rowlen: info.raw_row_length_from_width(width),
760            current_interlace_info,
761            interlace_info_iter,
762            consumed_and_flushed: false,
763        }
764    }
765}