png/decoder/mod.rs
1mod interlace_info;
2mod read_decoder;
3pub(crate) mod stream;
4pub(crate) mod transform;
5mod unfiltering_buffer;
6mod zlib;
7
8use self::read_decoder::{ImageDataCompletionStatus, ReadDecoder};
9use self::stream::{DecodeOptions, DecodingError, FormatErrorInner};
10use self::transform::{create_transform_fn, TransformFn};
11use self::unfiltering_buffer::UnfilteringBuffer;
12
13use std::io::{BufRead, Seek};
14use std::mem;
15
16use crate::adam7::Adam7Info;
17use crate::common::{
18 BitDepth, BytesPerPixel, ColorType, Info, ParameterErrorKind, Transformations,
19};
20use crate::FrameControl;
21pub use zlib::{UnfilterBuf, UnfilterRegion};
22
23pub use interlace_info::InterlaceInfo;
24use interlace_info::InterlaceInfoIter;
25
26/*
27pub enum InterlaceHandling {
28 /// Outputs the raw rows
29 RawRows,
30 /// Fill missing the pixels from the existing ones
31 Rectangle,
32 /// Only fill the needed pixels
33 Sparkle
34}
35*/
36
37/// Output info.
38///
39/// This describes one particular frame of the image that was written into the output buffer.
40#[derive(Debug, PartialEq, Eq)]
41pub struct OutputInfo {
42 /// The pixel width of this frame.
43 pub width: u32,
44 /// The pixel height of this frame.
45 pub height: u32,
46 /// The chosen output color type.
47 pub color_type: ColorType,
48 /// The chosen output bit depth.
49 pub bit_depth: BitDepth,
50 /// The byte count of each scan line in the image.
51 pub line_size: usize,
52}
53
54impl OutputInfo {
55 /// Returns the size needed to hold a decoded frame
56 /// If the output buffer was larger then bytes after this count should be ignored. They may
57 /// still have been changed.
58 pub fn buffer_size(&self) -> usize {
59 self.line_size * self.height as usize
60 }
61}
62
63#[derive(Clone, Copy, Debug)]
64/// Limits on the resources the `Decoder` is allowed too use
65pub struct Limits {
66 /// maximum number of bytes the decoder is allowed to allocate, default is 64Mib
67 pub bytes: usize,
68}
69
70impl Limits {
71 pub(crate) fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> {
72 if self.bytes >= bytes {
73 self.bytes -= bytes;
74 Ok(())
75 } else {
76 Err(DecodingError::LimitsExceeded)
77 }
78 }
79}
80
81impl Default for Limits {
82 fn default() -> Limits {
83 Limits {
84 bytes: 1024 * 1024 * 64,
85 }
86 }
87}
88
89/// PNG Decoder
90pub struct Decoder<R: BufRead + Seek> {
91 read_decoder: ReadDecoder<R>,
92 /// Output transformations
93 transform: Transformations,
94}
95
96/// A row of data with interlace information attached.
97#[derive(Clone, Copy, Debug)]
98pub struct InterlacedRow<'data> {
99 data: &'data [u8],
100 interlace: InterlaceInfo,
101}
102
103impl<'data> InterlacedRow<'data> {
104 pub fn data(&self) -> &'data [u8] {
105 self.data
106 }
107
108 pub fn interlace(&self) -> &InterlaceInfo {
109 &self.interlace
110 }
111}
112
113/// A row of data without interlace information.
114#[derive(Clone, Copy, Debug)]
115pub struct Row<'data> {
116 data: &'data [u8],
117}
118
119impl<'data> Row<'data> {
120 pub fn data(&self) -> &'data [u8] {
121 self.data
122 }
123}
124
125impl<R: BufRead + Seek> Decoder<R> {
126 /// Create a new decoder configuration with default limits.
127 pub fn new(r: R) -> Decoder<R> {
128 Decoder::new_with_limits(r, Limits::default())
129 }
130
131 /// Create a new decoder configuration with custom limits.
132 pub fn new_with_limits(r: R, limits: Limits) -> Decoder<R> {
133 let mut read_decoder = ReadDecoder::new(r);
134 read_decoder.set_limits(limits);
135
136 Decoder {
137 read_decoder,
138 transform: Transformations::IDENTITY,
139 }
140 }
141
142 /// Create a new decoder configuration with custom [`DecodeOptions`].
143 pub fn new_with_options(r: R, decode_options: DecodeOptions) -> Decoder<R> {
144 let mut read_decoder = ReadDecoder::with_options(r, decode_options);
145 read_decoder.set_limits(Limits::default());
146
147 Decoder {
148 read_decoder,
149 transform: Transformations::IDENTITY,
150 }
151 }
152
153 /// Limit resource usage.
154 ///
155 /// Note that your allocations, e.g. when reading into a pre-allocated buffer, are __NOT__
156 /// considered part of the limits. Nevertheless, required intermediate buffers such as for
157 /// singular lines is checked against the limit.
158 ///
159 /// Note that this is a best-effort basis.
160 ///
161 /// ```
162 /// use std::fs::File;
163 /// use std::io::BufReader;
164 /// use png::{Decoder, Limits};
165 /// // This image is 32×32, 1bit per pixel. The reader buffers one row which requires 4 bytes.
166 /// let mut limits = Limits::default();
167 /// limits.bytes = 3;
168 /// let mut decoder = Decoder::new_with_limits(BufReader::new(File::open("tests/pngsuite/basi0g01.png").unwrap()), limits);
169 /// assert!(decoder.read_info().is_err());
170 ///
171 /// // This image is 32x32 pixels, so the decoder will allocate less than 10Kib
172 /// let mut limits = Limits::default();
173 /// limits.bytes = 10*1024;
174 /// let mut decoder = Decoder::new_with_limits(BufReader::new(File::open("tests/pngsuite/basi0g01.png").unwrap()), limits);
175 /// assert!(decoder.read_info().is_ok());
176 /// ```
177 pub fn set_limits(&mut self, limits: Limits) {
178 self.read_decoder.set_limits(limits);
179 }
180
181 /// Read the PNG header and return the information contained within.
182 ///
183 /// Most image metadata will not be read until `read_info` is called, so those fields will be
184 /// None or empty.
185 pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> {
186 self.read_decoder.read_header_info()
187 }
188
189 /// Reads all meta data until the first IDAT chunk
190 pub fn read_info(mut self) -> Result<Reader<R>, DecodingError> {
191 let info = self.read_header_info()?;
192 let unfiltering_buffer = UnfilteringBuffer::new(info);
193
194 let mut reader = Reader {
195 decoder: self.read_decoder,
196 bpp: BytesPerPixel::One,
197 subframe: SubframeInfo::not_yet_init(),
198 remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`.
199 unfiltering_buffer,
200 transform: self.transform,
201 transform_fn: None,
202 scratch_buffer: Vec::new(),
203 finished: false,
204 };
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 if reader.info().checked_raw_row_length().is_none() {
214 return Err(DecodingError::LimitsExceeded);
215 }
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 if reader.output_buffer_size().is_none() {
222 return Err(DecodingError::LimitsExceeded);
223 }
224
225 reader.read_until_image_data()?;
226
227 reader.remaining_frames = match reader.info().animation_control.as_ref() {
228 None => 1, // No `acTL` => only expecting `IDAT` frame.
229 Some(animation) => {
230 let mut num_frames = animation.num_frames as usize;
231 if reader.info().frame_control.is_none() {
232 // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but
233 // represents an *extra*, default frame for non-APNG-aware decoders.
234 num_frames += 1;
235 }
236 num_frames
237 }
238 };
239 Ok(reader)
240 }
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 pub fn set_transformations(&mut self, transform: Transformations) {
247 self.transform = transform;
248 }
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 pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) {
262 self.read_decoder.set_ignore_text_chunk(ignore_text_chunk);
263 }
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 pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) {
277 self.read_decoder.set_ignore_iccp_chunk(ignore_iccp_chunk);
278 }
279
280 /// Set the decoder to ignore and not verify the Adler-32 checksum
281 /// and CRC code.
282 pub fn ignore_checksums(&mut self, ignore_checksums: bool) {
283 self.read_decoder.ignore_checksums(ignore_checksums);
284 }
285}
286
287/// PNG reader (mostly high-level interface)
288///
289/// Provides a high level that iterates over lines or whole images.
290pub 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.
317struct 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
326impl<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 pub fn next_frame_info(&mut self) -> Result<&FrameControl, DecodingError> {
335 let remaining_frames = if self.subframe.consumed_and_flushed {
336 self.remaining_frames
337 } else {
338 // One remaining frame will be consumed by the `finish_decoding` call below.
339 self.remaining_frames - 1
340 };
341 if remaining_frames == 0 {
342 return Err(DecodingError::Parameter(
343 ParameterErrorKind::PolledAfterEndOfImage.into(),
344 ));
345 }
346
347 if !self.subframe.consumed_and_flushed {
348 self.subframe.current_interlace_info = None;
349 self.finish_decoding()?;
350 }
351 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 Ok(self.info().frame_control.as_ref().unwrap())
357 }
358
359 /// Reads all meta data until the next frame data starts.
360 /// Requires IHDR before the IDAT and fcTL before fdAT.
361 fn read_until_image_data(&mut self) -> Result<(), DecodingError> {
362 self.decoder.read_until_image_data()?;
363
364 self.subframe = SubframeInfo::new(self.info());
365 self.bpp = self.info().bpp_in_prediction();
366 self.unfiltering_buffer.reset_all();
367
368 // Allocate output buffer.
369 let buflen = self.unguarded_output_line_size(self.subframe.width);
370 self.decoder.reserve_bytes(buflen)?;
371
372 Ok(())
373 }
374
375 /// Get information on the image.
376 ///
377 /// The structure will change as new frames of an animated image are decoded.
378 pub fn info(&self) -> &Info<'static> {
379 self.decoder.info().unwrap()
380 }
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 pub fn next_frame(&mut self, buf: &mut [u8]) -> Result<OutputInfo, DecodingError> {
396 if self.remaining_frames == 0 {
397 return Err(DecodingError::Parameter(
398 ParameterErrorKind::PolledAfterEndOfImage.into(),
399 ));
400 } 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 self.read_until_image_data()?;
404 }
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 let required_len = self
410 .output_buffer_size()
411 .ok_or(DecodingError::LimitsExceeded)?;
412
413 if buf.len() < required_len {
414 return Err(DecodingError::Parameter(
415 ParameterErrorKind::ImageBufferSize {
416 expected: required_len,
417 actual: buf.len(),
418 }
419 .into(),
420 ));
421 }
422
423 let (color_type, bit_depth) = self.output_color_type();
424 let output_info = OutputInfo {
425 width: self.subframe.width,
426 height: self.subframe.height,
427 color_type,
428 bit_depth,
429 line_size: self.unguarded_output_line_size(self.subframe.width),
430 };
431
432 if self.info().interlaced {
433 let stride = self.unguarded_output_line_size(self.info().width);
434 let samples = color_type.samples() as u8;
435 let bits_pp = samples * (bit_depth as u8);
436 let expand = crate::adam7::expand_pass;
437
438 while let Some(InterlacedRow {
439 data: row,
440 interlace,
441 ..
442 }) = self.next_interlaced_row()?
443 {
444 // `unwrap` won't panic, because we checked `self.info().interlaced` above.
445 let adam7info = interlace.get_adam7_info().unwrap();
446 expand(buf, stride, row, adam7info, bits_pp);
447 }
448 } else {
449 let current_interlace_info = self.subframe.current_interlace_info.as_ref();
450 let already_done_rows = current_interlace_info
451 .map(|info| info.line_number())
452 .unwrap_or(self.subframe.height);
453
454 for row in buf
455 .chunks_exact_mut(output_info.line_size)
456 .take(self.subframe.height as usize)
457 .skip(already_done_rows as usize)
458 {
459 self.next_interlaced_row_impl(self.subframe.rowlen, row)?;
460 }
461 }
462
463 // Advance over the rest of data for this (sub-)frame.
464 self.finish_decoding()?;
465
466 Ok(output_info)
467 }
468
469 fn mark_subframe_as_consumed_and_flushed(&mut self) {
470 assert!(self.remaining_frames > 0);
471 self.remaining_frames -= 1;
472
473 self.subframe.consumed_and_flushed = true;
474 }
475
476 /// Advance over the rest of data for this (sub-)frame.
477 /// Called after decoding the last row of a frame.
478 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 assert!(self.subframe.current_interlace_info.is_none());
482
483 // Discard the remaining data in the current sequence of `IDAT` or `fdAT` chunks.
484 if !self.subframe.consumed_and_flushed {
485 self.decoder.finish_decoding_image_data()?;
486 self.mark_subframe_as_consumed_and_flushed();
487 }
488
489 Ok(())
490 }
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 pub fn next_row(&mut self) -> Result<Option<Row<'_>>, DecodingError> {
496 self.next_interlaced_row()
497 .map(|v| v.map(|v| Row { data: v.data }))
498 }
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 pub fn next_interlaced_row(&mut self) -> Result<Option<InterlacedRow<'_>>, DecodingError> {
504 let mut output_buffer = mem::take(&mut self.scratch_buffer);
505 let max_line_size = self
506 .output_line_size(self.info().width)
507 .ok_or(DecodingError::LimitsExceeded)?;
508 output_buffer.resize(max_line_size, 0u8);
509 let result = self.read_row(&mut output_buffer);
510 self.scratch_buffer = output_buffer;
511 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 }
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 pub fn read_row(
531 &mut self,
532 output_buffer: &mut [u8],
533 ) -> Result<Option<InterlaceInfo>, DecodingError> {
534 let interlace = match self.subframe.current_interlace_info.as_ref() {
535 None => {
536 self.finish_decoding()?;
537 return Ok(None);
538 }
539 Some(interlace) => *interlace,
540 };
541 if interlace.line_number() == 0 {
542 self.unfiltering_buffer.reset_prev_row();
543 }
544 let rowlen = match interlace {
545 InterlaceInfo::Null(_) => self.subframe.rowlen,
546 InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => {
547 self.info().raw_row_length_from_width(width)
548 }
549 };
550
551 let output_line_size = self.output_line_size_for_interlace_info(&interlace);
552 let output_buffer = &mut output_buffer[..output_line_size];
553
554 self.next_interlaced_row_impl(rowlen, output_buffer)?;
555
556 Ok(Some(interlace))
557 }
558
559 fn output_line_size_for_interlace_info(&self, interlace: &InterlaceInfo) -> usize {
560 let width = match interlace {
561 InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => *width,
562 InterlaceInfo::Null(_) => self.subframe.width,
563 };
564 self.unguarded_output_line_size(width)
565 }
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 pub fn finish(&mut self) -> Result<(), DecodingError> {
570 if self.finished {
571 return Err(DecodingError::Parameter(
572 ParameterErrorKind::PolledAfterEndOfImage.into(),
573 ));
574 }
575
576 self.remaining_frames = 0;
577 self.unfiltering_buffer.reset_all();
578 self.decoder.read_until_end_of_input()?;
579
580 self.finished = true;
581 Ok(())
582 }
583
584 /// Fetch the next interlaced row and filter it according to our own transformations.
585 fn next_interlaced_row_impl(
586 &mut self,
587 rowlen: usize,
588 output_buffer: &mut [u8],
589 ) -> Result<(), DecodingError> {
590 self.next_raw_interlaced_row(rowlen)?;
591 let row = self.unfiltering_buffer.prev_row();
592 assert_eq!(row.len(), rowlen - 1);
593
594 // Apply transformations and write resulting data to buffer.
595 let transform_fn = {
596 if self.transform_fn.is_none() {
597 self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?);
598 }
599 self.transform_fn.as_deref().unwrap()
600 };
601 transform_fn(row, output_buffer, self.info());
602
603 self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next();
604 Ok(())
605 }
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 pub fn output_color_type(&self) -> (ColorType, BitDepth) {
610 use crate::common::ColorType::*;
611 let t = self.transform;
612 let info = self.info();
613 if t == Transformations::IDENTITY {
614 (info.color_type, info.bit_depth)
615 } else {
616 let bits = match info.bit_depth as u8 {
617 16 if t.intersects(Transformations::STRIP_16) => 8,
618 n if n < 8
619 && (t.contains(Transformations::EXPAND)
620 || t.contains(Transformations::ALPHA)) =>
621 {
622 8
623 }
624 n => n,
625 };
626 let color_type =
627 if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) {
628 let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA);
629 match info.color_type {
630 Grayscale if has_trns => GrayscaleAlpha,
631 Rgb if has_trns => Rgba,
632 Indexed if has_trns => Rgba,
633 Indexed => Rgb,
634 ct => ct,
635 }
636 } else {
637 info.color_type
638 };
639 (color_type, BitDepth::from_u8(bits).unwrap())
640 }
641 }
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 pub fn output_buffer_size(&self) -> Option<usize> {
649 let (width, height) = self.info().size();
650 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 let linelen = color.checked_raw_row_length(depth, width)?.checked_sub(1)?;
656 let height = usize::try_from(height).ok()?;
657 let imglen = linelen.checked_mul(height)?;
658 // Ensure that it fits into address space not only `usize` to allocate.
659 (imglen <= isize::MAX as usize).then_some(imglen)
660 }
661
662 /// Returns the number of bytes required to hold a deinterlaced row.
663 pub(crate) fn unguarded_output_line_size(&self, width: u32) -> usize {
664 let (color, depth) = self.output_color_type();
665 color.raw_row_length_from_width(depth, width) - 1
666 }
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 pub fn output_line_size(&self, width: u32) -> Option<usize> {
673 let (color, depth) = self.output_color_type();
674 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 (length <= isize::MAX as usize).then_some(length)
677 }
678
679 /// Unfilter the next raw interlaced row into `self.unfiltering_buffer`.
680 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 while self.unfiltering_buffer.curr_row_len() < rowlen {
683 if self.subframe.consumed_and_flushed {
684 return Err(DecodingError::Format(
685 FormatErrorInner::NoMoreImageData.into(),
686 ));
687 }
688
689 let mut buffer = self.unfiltering_buffer.as_unfilled_buffer();
690 match self.decoder.decode_image_data(Some(&mut buffer))? {
691 ImageDataCompletionStatus::ExpectingMoreData => (),
692 ImageDataCompletionStatus::Done => self.mark_subframe_as_consumed_and_flushed(),
693 }
694 }
695
696 self.unfiltering_buffer.unfilter_curr_row(rowlen, self.bpp)
697 }
698}
699
700impl SubframeInfo {
701 fn not_yet_init() -> Self {
702 SubframeInfo {
703 width: 0,
704 height: 0,
705 rowlen: 0,
706 current_interlace_info: None,
707 interlace_info_iter: InterlaceInfoIter::empty(),
708 consumed_and_flushed: false,
709 }
710 }
711
712 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 let (width, height) = if let Some(fc) = info.frame_control {
716 (fc.width, fc.height)
717 } else {
718 (info.width, info.height)
719 };
720
721 let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced);
722 let current_interlace_info = interlace_info_iter.next();
723 SubframeInfo {
724 width,
725 height,
726 rowlen: info.raw_row_length_from_width(width),
727 current_interlace_info,
728 interlace_info_iter,
729 consumed_and_flushed: false,
730 }
731 }
732}