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, CHUNK_BUFFER_SIZE}; |
10 | use self::transform::{create_transform_fn, TransformFn}; |
11 | use self::unfiltering_buffer::UnfilteringBuffer; |
12 | |
13 | use std::io::Read; |
14 | use std::mem; |
15 | |
16 | use crate::adam7::{self, Adam7Info}; |
17 | use crate::common::{ |
18 | BitDepth, BytesPerPixel, ColorType, Info, ParameterErrorKind, Transformations, |
19 | }; |
20 | use crate::FrameControl; |
21 | |
22 | pub use interlace_info::InterlaceInfo; |
23 | use interlace_info::InterlaceInfoIter; |
24 | |
25 | /* |
26 | pub enum InterlaceHandling { |
27 | /// Outputs the raw rows |
28 | RawRows, |
29 | /// Fill missing the pixels from the existing ones |
30 | Rectangle, |
31 | /// Only fill the needed pixels |
32 | Sparkle |
33 | } |
34 | */ |
35 | |
36 | /// Output info. |
37 | /// |
38 | /// This describes one particular frame of the image that was written into the output buffer. |
39 | #[derive (Debug, PartialEq, Eq)] |
40 | pub struct OutputInfo { |
41 | /// The pixel width of this frame. |
42 | pub width: u32, |
43 | /// The pixel height of this frame. |
44 | pub height: u32, |
45 | /// The chosen output color type. |
46 | pub color_type: ColorType, |
47 | /// The chosen output bit depth. |
48 | pub bit_depth: BitDepth, |
49 | /// The byte count of each scan line in the image. |
50 | pub line_size: usize, |
51 | } |
52 | |
53 | impl OutputInfo { |
54 | /// Returns the size needed to hold a decoded frame |
55 | /// If the output buffer was larger then bytes after this count should be ignored. They may |
56 | /// still have been changed. |
57 | pub fn buffer_size(&self) -> usize { |
58 | self.line_size * self.height as usize |
59 | } |
60 | } |
61 | |
62 | #[derive (Clone, Copy, Debug)] |
63 | /// Limits on the resources the `Decoder` is allowed too use |
64 | pub struct Limits { |
65 | /// maximum number of bytes the decoder is allowed to allocate, default is 64Mib |
66 | pub bytes: usize, |
67 | } |
68 | |
69 | impl Limits { |
70 | pub(crate) fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { |
71 | if self.bytes >= bytes { |
72 | self.bytes -= bytes; |
73 | Ok(()) |
74 | } else { |
75 | Err(DecodingError::LimitsExceeded) |
76 | } |
77 | } |
78 | } |
79 | |
80 | impl Default for Limits { |
81 | fn default() -> Limits { |
82 | Limits { |
83 | bytes: 1024 * 1024 * 64, |
84 | } |
85 | } |
86 | } |
87 | |
88 | /// PNG Decoder |
89 | pub struct Decoder<R: Read> { |
90 | read_decoder: ReadDecoder<R>, |
91 | /// Output transformations |
92 | transform: Transformations, |
93 | } |
94 | |
95 | /// A row of data with interlace information attached. |
96 | #[derive (Clone, Copy, Debug)] |
97 | pub struct InterlacedRow<'data> { |
98 | data: &'data [u8], |
99 | interlace: InterlaceInfo, |
100 | } |
101 | |
102 | impl<'data> InterlacedRow<'data> { |
103 | pub fn data(&self) -> &'data [u8] { |
104 | self.data |
105 | } |
106 | |
107 | pub fn interlace(&self) -> &InterlaceInfo { |
108 | &self.interlace |
109 | } |
110 | } |
111 | |
112 | /// A row of data without interlace information. |
113 | #[derive (Clone, Copy, Debug)] |
114 | pub struct Row<'data> { |
115 | data: &'data [u8], |
116 | } |
117 | |
118 | impl<'data> Row<'data> { |
119 | pub fn data(&self) -> &'data [u8] { |
120 | self.data |
121 | } |
122 | } |
123 | |
124 | impl<R: Read> Decoder<R> { |
125 | /// Create a new decoder configuration with default limits. |
126 | pub fn new(r: R) -> Decoder<R> { |
127 | Decoder::new_with_limits(r, Limits::default()) |
128 | } |
129 | |
130 | /// Create a new decoder configuration with custom limits. |
131 | pub fn new_with_limits(r: R, limits: Limits) -> Decoder<R> { |
132 | let mut read_decoder = ReadDecoder::new(r); |
133 | read_decoder.set_limits(limits); |
134 | |
135 | Decoder { |
136 | read_decoder, |
137 | transform: Transformations::IDENTITY, |
138 | } |
139 | } |
140 | |
141 | /// Create a new decoder configuration with custom `DecodeOptions`. |
142 | pub fn new_with_options(r: R, decode_options: DecodeOptions) -> Decoder<R> { |
143 | let mut read_decoder = ReadDecoder::with_options(r, decode_options); |
144 | read_decoder.set_limits(Limits::default()); |
145 | |
146 | Decoder { |
147 | read_decoder, |
148 | transform: Transformations::IDENTITY, |
149 | } |
150 | } |
151 | |
152 | /// Limit resource usage. |
153 | /// |
154 | /// Note that your allocations, e.g. when reading into a pre-allocated buffer, are __NOT__ |
155 | /// considered part of the limits. Nevertheless, required intermediate buffers such as for |
156 | /// singular lines is checked against the limit. |
157 | /// |
158 | /// Note that this is a best-effort basis. |
159 | /// |
160 | /// ``` |
161 | /// use std::fs::File; |
162 | /// use png::{Decoder, Limits}; |
163 | /// // This image is 32×32, 1bit per pixel. The reader buffers one row which requires 4 bytes. |
164 | /// let mut limits = Limits::default(); |
165 | /// limits.bytes = 3; |
166 | /// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png" ).unwrap(), limits); |
167 | /// assert!(decoder.read_info().is_err()); |
168 | /// |
169 | /// // This image is 32x32 pixels, so the decoder will allocate less than 10Kib |
170 | /// let mut limits = Limits::default(); |
171 | /// limits.bytes = 10*1024; |
172 | /// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png" ).unwrap(), limits); |
173 | /// assert!(decoder.read_info().is_ok()); |
174 | /// ``` |
175 | pub fn set_limits(&mut self, limits: Limits) { |
176 | self.read_decoder.set_limits(limits); |
177 | } |
178 | |
179 | /// Read the PNG header and return the information contained within. |
180 | /// |
181 | /// Most image metadata will not be read until `read_info` is called, so those fields will be |
182 | /// None or empty. |
183 | pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { |
184 | self.read_decoder.read_header_info() |
185 | } |
186 | |
187 | /// Reads all meta data until the first IDAT chunk |
188 | pub fn read_info(mut self) -> Result<Reader<R>, DecodingError> { |
189 | self.read_header_info()?; |
190 | |
191 | let mut reader = Reader { |
192 | decoder: self.read_decoder, |
193 | bpp: BytesPerPixel::One, |
194 | subframe: SubframeInfo::not_yet_init(), |
195 | remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`. |
196 | unfiltering_buffer: UnfilteringBuffer::new(), |
197 | transform: self.transform, |
198 | transform_fn: None, |
199 | scratch_buffer: Vec::new(), |
200 | finished: false, |
201 | }; |
202 | |
203 | // Check if the decoding buffer of a single raw line has a valid size. |
204 | if reader.info().checked_raw_row_length().is_none() { |
205 | return Err(DecodingError::LimitsExceeded); |
206 | } |
207 | |
208 | // Check if the output buffer has a valid size. |
209 | let (width, height) = reader.info().size(); |
210 | let (color, depth) = reader.output_color_type(); |
211 | let rowlen = color |
212 | .checked_raw_row_length(depth, width) |
213 | .ok_or(DecodingError::LimitsExceeded)? |
214 | - 1; |
215 | let height: usize = |
216 | std::convert::TryFrom::try_from(height).map_err(|_| DecodingError::LimitsExceeded)?; |
217 | if rowlen.checked_mul(height).is_none() { |
218 | return Err(DecodingError::LimitsExceeded); |
219 | } |
220 | |
221 | reader.read_until_image_data()?; |
222 | |
223 | reader.remaining_frames = match reader.info().animation_control.as_ref() { |
224 | None => 1, // No `acTL` => only expecting `IDAT` frame. |
225 | Some(animation) => { |
226 | let mut num_frames = animation.num_frames as usize; |
227 | if reader.info().frame_control.is_none() { |
228 | // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but |
229 | // represents an *extra*, default frame for non-APNG-aware decoders. |
230 | num_frames += 1; |
231 | } |
232 | num_frames |
233 | } |
234 | }; |
235 | Ok(reader) |
236 | } |
237 | |
238 | /// Set the allowed and performed transformations. |
239 | /// |
240 | /// A transformation is a pre-processing on the raw image data modifying content or encoding. |
241 | /// Many options have an impact on memory or CPU usage during decoding. |
242 | pub fn set_transformations(&mut self, transform: Transformations) { |
243 | self.transform = transform; |
244 | } |
245 | |
246 | /// Set the decoder to ignore all text chunks while parsing. |
247 | /// |
248 | /// eg. |
249 | /// ``` |
250 | /// use std::fs::File; |
251 | /// use png::Decoder; |
252 | /// let mut decoder = Decoder::new(File::open("tests/pngsuite/basi0g01.png" ).unwrap()); |
253 | /// decoder.set_ignore_text_chunk(true); |
254 | /// assert!(decoder.read_info().is_ok()); |
255 | /// ``` |
256 | pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { |
257 | self.read_decoder.set_ignore_text_chunk(ignore_text_chunk); |
258 | } |
259 | |
260 | /// Set the decoder to ignore iccp chunks while parsing. |
261 | /// |
262 | /// eg. |
263 | /// ``` |
264 | /// use std::fs::File; |
265 | /// use png::Decoder; |
266 | /// let mut decoder = Decoder::new(File::open("tests/iccp/broken_iccp.png" ).unwrap()); |
267 | /// decoder.set_ignore_iccp_chunk(true); |
268 | /// assert!(decoder.read_info().is_ok()); |
269 | /// ``` |
270 | pub fn set_ignore_iccp_chunk(&mut self, ignore_iccp_chunk: bool) { |
271 | self.read_decoder.set_ignore_iccp_chunk(ignore_iccp_chunk); |
272 | } |
273 | |
274 | /// Set the decoder to ignore and not verify the Adler-32 checksum |
275 | /// and CRC code. |
276 | pub fn ignore_checksums(&mut self, ignore_checksums: bool) { |
277 | self.read_decoder.ignore_checksums(ignore_checksums); |
278 | } |
279 | } |
280 | |
281 | /// PNG reader (mostly high-level interface) |
282 | /// |
283 | /// Provides a high level that iterates over lines or whole images. |
284 | pub struct Reader<R: Read> { |
285 | decoder: ReadDecoder<R>, |
286 | bpp: BytesPerPixel, |
287 | subframe: SubframeInfo, |
288 | /// How many frames remain to be decoded. Decremented after each `IDAT` or `fdAT` sequence. |
289 | remaining_frames: usize, |
290 | /// Buffer with not-yet-`unfilter`-ed image rows |
291 | unfiltering_buffer: UnfilteringBuffer, |
292 | /// Output transformations |
293 | transform: Transformations, |
294 | /// Function that can transform decompressed, unfiltered rows into final output. |
295 | /// See the `transform.rs` module for more details. |
296 | transform_fn: Option<TransformFn>, |
297 | /// This buffer is only used so that `next_row` and `next_interlaced_row` can return reference |
298 | /// to a byte slice. In a future version of this library, this buffer will be removed and |
299 | /// `next_row` and `next_interlaced_row` will write directly into a user provided output buffer. |
300 | scratch_buffer: Vec<u8>, |
301 | /// Whether `ImageEnd` was already reached by `fn finish`. |
302 | finished: bool, |
303 | } |
304 | |
305 | /// The subframe specific information. |
306 | /// |
307 | /// In APNG the frames are constructed by combining previous frame and a new subframe (through a |
308 | /// combination of `dispose_op` and `overlay_op`). These sub frames specify individual dimension |
309 | /// information and reuse the global interlace options. This struct encapsulates the state of where |
310 | /// in a particular IDAT-frame or subframe we are. |
311 | struct SubframeInfo { |
312 | width: u32, |
313 | height: u32, |
314 | rowlen: usize, |
315 | current_interlace_info: Option<InterlaceInfo>, |
316 | interlace_info_iter: InterlaceInfoIter, |
317 | consumed_and_flushed: bool, |
318 | } |
319 | |
320 | impl<R: Read> Reader<R> { |
321 | /// Advances to the start of the next animation frame and |
322 | /// returns a reference to the `FrameControl` info that describes it. |
323 | /// Skips and discards the image data of the previous frame if necessary. |
324 | /// |
325 | /// Returns a [`ParameterError`] when there are no more animation frames. |
326 | /// To avoid this the caller can check if [`Info::animation_control`] exists |
327 | /// and consult [`AnimationControl::num_frames`]. |
328 | pub fn next_frame_info(&mut self) -> Result<&FrameControl, DecodingError> { |
329 | let remaining_frames = if self.subframe.consumed_and_flushed { |
330 | self.remaining_frames |
331 | } else { |
332 | // One remaining frame will be consumed by the `finish_decoding` call below. |
333 | self.remaining_frames - 1 |
334 | }; |
335 | if remaining_frames == 0 { |
336 | return Err(DecodingError::Parameter( |
337 | ParameterErrorKind::PolledAfterEndOfImage.into(), |
338 | )); |
339 | } |
340 | |
341 | if !self.subframe.consumed_and_flushed { |
342 | self.subframe.current_interlace_info = None; |
343 | self.finish_decoding()?; |
344 | } |
345 | self.read_until_image_data()?; |
346 | |
347 | // The PNG standard (and `StreamingDecoder `) guarantes that there is an `fcTL` chunk |
348 | // before the start of image data in a sequence of `fdAT` chunks. Therefore `unwrap` |
349 | // below is guaranteed to not panic. |
350 | Ok(self.info().frame_control.as_ref().unwrap()) |
351 | } |
352 | |
353 | /// Reads all meta data until the next frame data starts. |
354 | /// Requires IHDR before the IDAT and fcTL before fdAT. |
355 | fn read_until_image_data(&mut self) -> Result<(), DecodingError> { |
356 | self.decoder.read_until_image_data()?; |
357 | |
358 | self.subframe = SubframeInfo::new(self.info()); |
359 | self.bpp = self.info().bpp_in_prediction(); |
360 | self.unfiltering_buffer = UnfilteringBuffer::new(); |
361 | |
362 | // Allocate output buffer. |
363 | let buflen = self.output_line_size(self.subframe.width); |
364 | self.decoder.reserve_bytes(buflen)?; |
365 | |
366 | Ok(()) |
367 | } |
368 | |
369 | /// Get information on the image. |
370 | /// |
371 | /// The structure will change as new frames of an animated image are decoded. |
372 | pub fn info(&self) -> &Info<'static> { |
373 | self.decoder.info().unwrap() |
374 | } |
375 | |
376 | /// Decodes the next frame into `buf`. |
377 | /// |
378 | /// Note that this decodes raw subframes that need to be mixed according to blend-op and |
379 | /// dispose-op by the caller. |
380 | /// |
381 | /// The caller must always provide a buffer large enough to hold a complete frame (the APNG |
382 | /// specification restricts subframes to the dimensions given in the image header). The region |
383 | /// that has been written be checked afterwards by calling `info` after a successful call and |
384 | /// inspecting the `frame_control` data. This requirement may be lifted in a later version of |
385 | /// `png`. |
386 | /// |
387 | /// Output lines will be written in row-major, packed matrix with width and height of the read |
388 | /// frame (or subframe), all samples are in big endian byte order where this matters. |
389 | pub fn next_frame(&mut self, buf: &mut [u8]) -> Result<OutputInfo, DecodingError> { |
390 | if self.remaining_frames == 0 { |
391 | return Err(DecodingError::Parameter( |
392 | ParameterErrorKind::PolledAfterEndOfImage.into(), |
393 | )); |
394 | } else if self.subframe.consumed_and_flushed { |
395 | // Advance until the next `fdAT` |
396 | // (along the way we should encounter the fcTL for this frame). |
397 | self.read_until_image_data()?; |
398 | } |
399 | |
400 | if buf.len() < self.output_buffer_size() { |
401 | return Err(DecodingError::Parameter( |
402 | ParameterErrorKind::ImageBufferSize { |
403 | expected: buf.len(), |
404 | actual: self.output_buffer_size(), |
405 | } |
406 | .into(), |
407 | )); |
408 | } |
409 | |
410 | let (color_type, bit_depth) = self.output_color_type(); |
411 | let output_info = OutputInfo { |
412 | width: self.subframe.width, |
413 | height: self.subframe.height, |
414 | color_type, |
415 | bit_depth, |
416 | line_size: self.output_line_size(self.subframe.width), |
417 | }; |
418 | |
419 | if self.info().interlaced { |
420 | let stride = self.output_line_size(self.info().width); |
421 | let samples = color_type.samples() as u8; |
422 | let bits_pp = samples * (bit_depth as u8); |
423 | while let Some(InterlacedRow { |
424 | data: row, |
425 | interlace, |
426 | .. |
427 | }) = self.next_interlaced_row()? |
428 | { |
429 | // `unwrap` won't panic, because we checked `self.info().interlaced` above. |
430 | let adam7info = interlace.get_adam7_info().unwrap(); |
431 | adam7::expand_pass(buf, stride, row, adam7info, bits_pp); |
432 | } |
433 | } else { |
434 | let current_interlace_info = self.subframe.current_interlace_info.as_ref(); |
435 | let already_done_rows = current_interlace_info |
436 | .map(|info| info.line_number()) |
437 | .unwrap_or(self.subframe.height); |
438 | |
439 | for row in buf |
440 | .chunks_exact_mut(output_info.line_size) |
441 | .take(self.subframe.height as usize) |
442 | .skip(already_done_rows as usize) |
443 | { |
444 | self.next_interlaced_row_impl(self.subframe.rowlen, row)?; |
445 | } |
446 | } |
447 | |
448 | // Advance over the rest of data for this (sub-)frame. |
449 | self.finish_decoding()?; |
450 | |
451 | Ok(output_info) |
452 | } |
453 | |
454 | fn mark_subframe_as_consumed_and_flushed(&mut self) { |
455 | assert!(self.remaining_frames > 0); |
456 | self.remaining_frames -= 1; |
457 | |
458 | self.subframe.consumed_and_flushed = true; |
459 | } |
460 | |
461 | /// Advance over the rest of data for this (sub-)frame. |
462 | /// Called after decoding the last row of a frame. |
463 | fn finish_decoding(&mut self) -> Result<(), DecodingError> { |
464 | // Double-check that all rows of this frame have been decoded (i.e. that the potential |
465 | // `finish_decoding` call below won't be discarding any data). |
466 | assert!(self.subframe.current_interlace_info.is_none()); |
467 | |
468 | // Discard the remaining data in the current sequence of `IDAT` or `fdAT` chunks. |
469 | if !self.subframe.consumed_and_flushed { |
470 | self.decoder.finish_decoding_image_data()?; |
471 | self.mark_subframe_as_consumed_and_flushed(); |
472 | } |
473 | |
474 | Ok(()) |
475 | } |
476 | |
477 | /// Returns the next processed row of the image |
478 | pub fn next_row(&mut self) -> Result<Option<Row>, DecodingError> { |
479 | self.next_interlaced_row() |
480 | .map(|v| v.map(|v| Row { data: v.data })) |
481 | } |
482 | |
483 | /// Returns the next processed row of the image |
484 | pub fn next_interlaced_row(&mut self) -> Result<Option<InterlacedRow>, DecodingError> { |
485 | let interlace = match self.subframe.current_interlace_info.as_ref() { |
486 | None => { |
487 | self.finish_decoding()?; |
488 | return Ok(None); |
489 | } |
490 | Some(interlace) => *interlace, |
491 | }; |
492 | if interlace.line_number() == 0 { |
493 | self.unfiltering_buffer.reset_prev_row(); |
494 | } |
495 | let rowlen = match interlace { |
496 | InterlaceInfo::Null(_) => self.subframe.rowlen, |
497 | InterlaceInfo::Adam7(Adam7Info { width, .. }) => { |
498 | self.info().raw_row_length_from_width(width) |
499 | } |
500 | }; |
501 | let width = match interlace { |
502 | InterlaceInfo::Adam7(Adam7Info { width, .. }) => width, |
503 | InterlaceInfo::Null(_) => self.subframe.width, |
504 | }; |
505 | let output_line_size = self.output_line_size(width); |
506 | |
507 | // TODO: change the interface of `next_interlaced_row` to take an output buffer instead of |
508 | // making us return a reference to a buffer that we own. |
509 | let mut output_buffer = mem::take(&mut self.scratch_buffer); |
510 | output_buffer.resize(output_line_size, 0u8); |
511 | let ret = self.next_interlaced_row_impl(rowlen, &mut output_buffer); |
512 | self.scratch_buffer = output_buffer; |
513 | ret?; |
514 | |
515 | Ok(Some(InterlacedRow { |
516 | data: &self.scratch_buffer[..output_line_size], |
517 | interlace, |
518 | })) |
519 | } |
520 | |
521 | /// Read the rest of the image and chunks and finish up, including text chunks or others |
522 | /// 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`] |
523 | pub fn finish(&mut self) -> Result<(), DecodingError> { |
524 | if self.finished { |
525 | return Err(DecodingError::Parameter( |
526 | ParameterErrorKind::PolledAfterEndOfImage.into(), |
527 | )); |
528 | } |
529 | |
530 | self.remaining_frames = 0; |
531 | self.unfiltering_buffer = UnfilteringBuffer::new(); |
532 | self.decoder.read_until_end_of_input()?; |
533 | |
534 | self.finished = true; |
535 | Ok(()) |
536 | } |
537 | |
538 | /// Fetch the next interlaced row and filter it according to our own transformations. |
539 | fn next_interlaced_row_impl( |
540 | &mut self, |
541 | rowlen: usize, |
542 | output_buffer: &mut [u8], |
543 | ) -> Result<(), DecodingError> { |
544 | self.next_raw_interlaced_row(rowlen)?; |
545 | let row = self.unfiltering_buffer.prev_row(); |
546 | assert_eq!(row.len(), rowlen - 1); |
547 | |
548 | // Apply transformations and write resulting data to buffer. |
549 | let transform_fn = { |
550 | if self.transform_fn.is_none() { |
551 | self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?); |
552 | } |
553 | self.transform_fn.as_deref().unwrap() |
554 | }; |
555 | transform_fn(row, output_buffer, self.info()); |
556 | |
557 | self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next(); |
558 | Ok(()) |
559 | } |
560 | |
561 | /// Returns the color type and the number of bits per sample |
562 | /// of the data returned by `Reader::next_row` and Reader::frames`. |
563 | pub fn output_color_type(&self) -> (ColorType, BitDepth) { |
564 | use crate::common::ColorType::*; |
565 | let t = self.transform; |
566 | let info = self.info(); |
567 | if t == Transformations::IDENTITY { |
568 | (info.color_type, info.bit_depth) |
569 | } else { |
570 | let bits = match info.bit_depth as u8 { |
571 | 16 if t.intersects(Transformations::STRIP_16) => 8, |
572 | n if n < 8 |
573 | && (t.contains(Transformations::EXPAND) |
574 | || t.contains(Transformations::ALPHA)) => |
575 | { |
576 | 8 |
577 | } |
578 | n => n, |
579 | }; |
580 | let color_type = |
581 | if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) { |
582 | let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA); |
583 | match info.color_type { |
584 | Grayscale if has_trns => GrayscaleAlpha, |
585 | Rgb if has_trns => Rgba, |
586 | Indexed if has_trns => Rgba, |
587 | Indexed => Rgb, |
588 | ct => ct, |
589 | } |
590 | } else { |
591 | info.color_type |
592 | }; |
593 | (color_type, BitDepth::from_u8(bits).unwrap()) |
594 | } |
595 | } |
596 | |
597 | /// Returns the number of bytes required to hold a deinterlaced image frame |
598 | /// that is decoded using the given input transformations. |
599 | pub fn output_buffer_size(&self) -> usize { |
600 | let (width, height) = self.info().size(); |
601 | let size = self.output_line_size(width); |
602 | size * height as usize |
603 | } |
604 | |
605 | /// Returns the number of bytes required to hold a deinterlaced row. |
606 | pub fn output_line_size(&self, width: u32) -> usize { |
607 | let (color, depth) = self.output_color_type(); |
608 | color.raw_row_length_from_width(depth, width) - 1 |
609 | } |
610 | |
611 | /// Unfilter the next raw interlaced row into `self.unfiltering_buffer`. |
612 | fn next_raw_interlaced_row(&mut self, rowlen: usize) -> Result<(), DecodingError> { |
613 | // Read image data until we have at least one full row (but possibly more than one). |
614 | while self.unfiltering_buffer.curr_row_len() < rowlen { |
615 | if self.subframe.consumed_and_flushed { |
616 | return Err(DecodingError::Format( |
617 | FormatErrorInner::NoMoreImageData.into(), |
618 | )); |
619 | } |
620 | |
621 | match self |
622 | .decoder |
623 | .decode_image_data(self.unfiltering_buffer.as_mut_vec())? |
624 | { |
625 | ImageDataCompletionStatus::ExpectingMoreData => (), |
626 | ImageDataCompletionStatus::Done => self.mark_subframe_as_consumed_and_flushed(), |
627 | } |
628 | } |
629 | |
630 | self.unfiltering_buffer.unfilter_curr_row(rowlen, self.bpp) |
631 | } |
632 | } |
633 | |
634 | impl SubframeInfo { |
635 | fn not_yet_init() -> Self { |
636 | SubframeInfo { |
637 | width: 0, |
638 | height: 0, |
639 | rowlen: 0, |
640 | current_interlace_info: None, |
641 | interlace_info_iter: InterlaceInfoIter::empty(), |
642 | consumed_and_flushed: false, |
643 | } |
644 | } |
645 | |
646 | fn new(info: &Info) -> Self { |
647 | // The apng fctnl overrides width and height. |
648 | // All other data is set by the main info struct. |
649 | let (width, height) = if let Some(fc) = info.frame_control { |
650 | (fc.width, fc.height) |
651 | } else { |
652 | (info.width, info.height) |
653 | }; |
654 | |
655 | let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced); |
656 | let current_interlace_info = interlace_info_iter.next(); |
657 | SubframeInfo { |
658 | width, |
659 | height, |
660 | rowlen: info.raw_row_length_from_width(width), |
661 | current_interlace_info, |
662 | interlace_info_iter, |
663 | consumed_and_flushed: false, |
664 | } |
665 | } |
666 | } |
667 | |