Coverage Report

Created: 2026-03-07 07:19

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