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