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