Coverage Report

Created: 2025-11-05 08:08

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