/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 | | } |