1use otf_pixels_core::{
26 Codec, DecodeCapability, Decoder, Format, ImageDescriptor, Limits, Orientation, PixelFormat,
27 PixelsError, Result, Source,
28};
29
30use crate::format::{
31 ChunkReader, ChunkStream, ColorType, Filter, Header, SIGNATURE, adam7_pass_size,
32 adam7_position, unfilter,
33};
34use otf_pixels_compress::{ZlibStream, zlib_decompress};
35
36const MAX_PLTE: usize = 256 * 3;
38const MAX_TRNS: usize = 256;
40const READ_CHUNK: usize = 64 * 1024;
42const EXIF_PREFIX: usize = 64 * 1024;
48
49const MAX_ICC: usize = 4 << 20;
53
54#[derive(Debug, Clone)]
56enum Transparency {
57 Gray(u16),
59 Rgb(u16, u16, u16),
61 Palette(Vec<u8>),
63}
64
65fn parse_iccp(data: &[u8]) -> Option<Vec<u8>> {
68 let nul = data
69 .iter()
70 .position(|&b| b == 0)
71 .filter(|&n| (1..=79).contains(&n))?;
72 let (&method, compressed) = data.get(nul + 1..)?.split_first()?;
73 if method != 0 {
74 return None;
75 }
76 zlib_decompress(compressed, MAX_ICC).ok()
77}
78
79#[derive(Debug)]
81pub struct PngDecoder<S: Source> {
82 header: Header,
83 descriptor: ImageDescriptor,
84 prelude: Option<Prelude<S>>,
86 orientation: Orientation,
87 icc: Option<Vec<u8>>,
89 raster: Option<Vec<u8>>,
94 stream: Option<Box<Streaming<S>>>,
96 row: u32,
97}
98
99#[derive(Debug)]
101struct Prelude<S: Source> {
102 chunks: ChunkStream<S>,
104 palette: Option<Vec<[u8; 3]>>,
105 transparency: Option<Transparency>,
106}
107
108#[derive(Debug)]
114struct Streaming<S: Source> {
115 chunks: ChunkStream<S>,
116 zlib: ZlibStream,
117 filtered: Vec<u8>,
119 at: usize,
121 previous: Vec<u8>,
123 palette: Option<Vec<[u8; 3]>>,
124 transparency: Option<Transparency>,
125 input_done: bool,
127}
128
129impl<S: Source> PngDecoder<S> {
130 pub fn new(mut source: S, limits: Limits) -> Result<Self> {
138 let mut prefix = vec![0_u8; 33];
140 source.read_exact(&mut prefix)?;
141
142 let mut reader = ChunkReader::new(&prefix)?;
143 let chunk = reader.next_chunk()?;
144 if !chunk.is(b"IHDR") {
145 return Err(PixelsError::malformed(
146 "png",
147 format!("first chunk must be IHDR, got `{}`", chunk.name()),
148 ));
149 }
150 let header = Header::parse(&chunk.data, &limits)?;
151
152 let mut chunks = ChunkStream::new(source);
153 let mut palette: Option<Vec<[u8; 3]>> = None;
154 let mut transparency: Option<Transparency> = None;
155 let mut orientation = None;
156 let mut icc = None;
157 loop {
158 let kind = chunks.open_next()?;
159 match &kind {
160 b"IHDR" => {
161 return Err(PixelsError::malformed("png", "more than one IHDR"));
162 }
163 b"PLTE" => {
164 let data = chunks.read_payload_to_end(MAX_PLTE)?;
165 palette = Some(parse_plte(&data)?);
166 chunks.close()?;
167 }
168 b"tRNS" => {
169 let data = chunks.read_payload_to_end(MAX_TRNS)?;
170 transparency = Some(parse_trns(&data, header.color_type)?);
171 chunks.close()?;
172 }
173 b"eXIf" => {
174 let mut exif = vec![0_u8; EXIF_PREFIX];
175 let mut filled = 0;
176 while let Some(rest) = exif.get_mut(filled..) {
177 match chunks.read_payload(rest)? {
178 0 => break,
179 n => filled += n,
180 }
181 }
182 exif.truncate(filled);
183 chunks.skip_payload()?;
184 chunks.close()?;
185 orientation = orientation.or_else(|| Orientation::from_exif_block(&exif));
187 }
188 b"iCCP" => {
189 let mut data = vec![0_u8; MAX_ICC + 1];
191 let mut filled = 0;
192 while let Some(rest) = data.get_mut(filled..).filter(|r| !r.is_empty()) {
193 match chunks.read_payload(rest)? {
194 0 => break,
195 n => filled += n,
196 }
197 }
198 data.truncate(filled);
199 chunks.skip_payload()?;
200 chunks.close()?;
201 if filled <= MAX_ICC {
204 icc = icc.or_else(|| parse_iccp(&data));
205 }
206 }
207 b"IDAT" => break,
208 b"IEND" => {
209 return Err(PixelsError::malformed("png", "no IDAT data"));
210 }
211 _ => {
212 if !chunks.is_ancillary() {
213 return Err(PixelsError::malformed(
214 "png",
215 format!("unknown critical chunk `{}`", chunks.name()),
216 ));
217 }
218 chunks.skip_payload()?;
219 chunks.close()?;
220 }
221 }
222 }
223
224 if header.color_type == ColorType::Palette && palette.is_none() {
225 return Err(PixelsError::malformed(
226 "png",
227 "palette image has no PLTE chunk",
228 ));
229 }
230 let descriptor = header.descriptor(transparency.is_some(), &limits)?;
231
232 Ok(Self {
233 header,
234 descriptor,
235 prelude: Some(Prelude {
236 chunks,
237 palette,
238 transparency,
239 }),
240 orientation: orientation.unwrap_or_default(),
241 icc,
242 raster: None,
243 stream: None,
244 row: 0,
245 })
246 }
247
248 #[must_use]
250 pub const fn header(&self) -> Header {
251 self.header
252 }
253
254 fn begin_streaming(&mut self) -> Result<Streaming<S>> {
256 let Some(Prelude {
257 chunks,
258 palette,
259 transparency,
260 }) = self.prelude.take()
261 else {
262 return Err(PixelsError::graph("png source was already consumed"));
263 };
264
265 let row_bytes = self.header.row_bytes(self.header.width);
266 Ok(Streaming {
267 chunks,
268 zlib: ZlibStream::new(self.header.filtered_size()),
271 filtered: Vec::new(),
272 at: 0,
273 previous: vec![0_u8; row_bytes],
274 palette,
275 transparency,
276 input_done: false,
277 })
278 }
279
280 fn decode_image(&mut self) -> Result<Vec<u8>> {
282 let Some(Prelude {
283 mut chunks,
284 palette,
285 transparency,
286 }) = self.prelude.take()
287 else {
288 return Err(PixelsError::graph("png source was already consumed"));
289 };
290
291 let mut compressed: Vec<u8> = Vec::new();
294 let mut buffer = vec![0_u8; READ_CHUNK];
295 loop {
296 loop {
297 let read = chunks.read_payload(&mut buffer)?;
298 if read == 0 {
299 break;
300 }
301 compressed.extend_from_slice(buffer.get(..read).unwrap_or(&[]));
302 }
303 chunks.close()?;
304 match &chunks.open_next()? {
305 b"IDAT" => {}
306 b"IEND" => {
307 chunks.skip_payload()?;
308 chunks.close()?;
309 break;
310 }
311 _ => {
312 if !chunks.is_ancillary() {
315 return Err(PixelsError::malformed(
316 "png",
317 format!("unknown critical chunk `{}`", chunks.name()),
318 ));
319 }
320 chunks.skip_payload()?;
321 }
322 }
323 }
324
325 let filtered = zlib_decompress(&compressed, self.header.filtered_size())
328 .map_err(crate::compress_error)?;
329 let samples = self.unfilter_all(&filtered)?;
330 self.expand(&samples, palette.as_deref(), transparency.as_ref())
331 }
332
333 fn unfilter_all(&self, filtered: &[u8]) -> Result<Vec<u8>> {
338 let stride = self.header.filter_stride();
339 let full_row = self.header.row_bytes(self.header.width);
340
341 if !self.header.interlaced {
342 let mut out = vec![0_u8; self.header.height as usize * full_row];
343 let mut previous = vec![0_u8; full_row];
344 let mut at = 0;
345 for y in 0..self.header.height as usize {
346 let filter_byte = filtered
347 .get(at)
348 .copied()
349 .ok_or_else(|| PixelsError::malformed("png", "raster ends early"))?;
350 let filter = Filter::from_byte(filter_byte)?;
351 at += 1;
352 let row = filtered
353 .get(at..at + full_row)
354 .ok_or_else(|| PixelsError::malformed("png", "scanline ends early"))?;
355 at += full_row;
356
357 let mut current = row.to_vec();
358 unfilter(filter, &mut current, &previous, stride)?;
359 let start = y * full_row;
360 if let Some(slot) = out.get_mut(start..start + full_row) {
361 slot.copy_from_slice(¤t);
362 }
363 previous = current;
364 }
365 return Ok(out);
366 }
367
368 let mut out = vec![0_u8; self.header.height as usize * full_row];
371 let mut at = 0;
372 for pass in 0..7 {
373 let (pass_width, pass_height) =
374 adam7_pass_size(pass, self.header.width, self.header.height);
375 if pass_width == 0 || pass_height == 0 {
376 continue;
377 }
378 let pass_row = self.header.row_bytes(pass_width);
379 let mut previous = vec![0_u8; pass_row];
380 for y in 0..pass_height {
381 let filter_byte = filtered.get(at).copied().ok_or_else(|| {
382 PixelsError::malformed("png", format!("pass {pass} ends early"))
383 })?;
384 let filter = Filter::from_byte(filter_byte)?;
385 at += 1;
386 let row = filtered.get(at..at + pass_row).ok_or_else(|| {
387 PixelsError::malformed("png", format!("pass {pass} scanline ends early"))
388 })?;
389 at += pass_row;
390
391 let mut current = row.to_vec();
392 unfilter(filter, &mut current, &previous, stride)?;
393 for x in 0..pass_width {
394 let (image_x, image_y) = adam7_position(pass, x, y);
395 copy_pixel_bits(
396 ¤t,
397 x as usize,
398 &mut out,
399 image_y as usize * full_row,
400 image_x as usize,
401 self.header.bits_per_pixel(),
402 );
403 }
404 previous = current;
405 }
406 }
407 Ok(out)
408 }
409
410 fn expand(
412 &self,
413 samples: &[u8],
414 palette: Option<&[[u8; 3]]>,
415 transparency: Option<&Transparency>,
416 ) -> Result<Vec<u8>> {
417 let height = self.header.height as usize;
418 let row_bytes = self.header.row_bytes(self.header.width);
419 let out_row = self.descriptor.row_bytes();
420 let mut out = vec![0_u8; height * out_row];
421
422 for y in 0..height {
423 let row = samples
424 .get(y * row_bytes..(y + 1) * row_bytes)
425 .ok_or_else(|| PixelsError::malformed("png", "sample row missing"))?;
426 let Some(slot) = out.get_mut(y * out_row..(y + 1) * out_row) else {
427 return Err(PixelsError::graph("output row is missing"));
428 };
429 self.expand_row(row, palette, transparency, slot)?;
430 }
431 Ok(out)
432 }
433
434 fn expand_row(
441 &self,
442 samples: &[u8],
443 palette: Option<&[[u8; 3]]>,
444 transparency: Option<&Transparency>,
445 out: &mut [u8],
446 ) -> Result<()> {
447 let format = self.descriptor.pixel;
448 let width = self.header.width as usize;
449 let depth = self.header.bit_depth;
450 let channels = self.header.color_type.channels();
451 let max = ((1_u32 << depth) - 1) as u16;
452
453 let mut at = 0;
454 for x in 0..width {
455 let mut channel = [0_u16; 4];
456 for (c, slot) in channel.iter_mut().take(channels).enumerate() {
457 *slot = read_sample(samples, x * channels + c, depth);
458 }
459 write_pixel(
460 out,
461 &mut at,
462 format,
463 self.header.color_type,
464 &channel,
465 depth,
466 max,
467 palette,
468 transparency,
469 )?;
470 }
471 Ok(())
472 }
473
474 fn read_row_buffered(&mut self, out: &mut [u8]) -> Result<()> {
476 if self.raster.is_none() {
477 self.raster = Some(self.decode_image()?);
478 }
479 let Some(raster) = self.raster.as_ref() else {
480 return Err(PixelsError::graph("raster vanished after decoding"));
481 };
482 if self.row >= self.descriptor.height {
483 return Err(PixelsError::invalid_argument(
484 "out",
485 format!("all {} rows have already been read", self.descriptor.height),
486 ));
487 }
488 let row_bytes = self.descriptor.row_bytes();
489 if out.len() != row_bytes {
490 return Err(PixelsError::invalid_argument(
491 "out",
492 format!("row buffer is {} bytes, expected {row_bytes}", out.len()),
493 ));
494 }
495 let start = self.row as usize * row_bytes;
496 let row = raster
497 .get(start..start + row_bytes)
498 .ok_or_else(|| PixelsError::malformed("png", "decoded raster is short"))?;
499 out.copy_from_slice(row);
500 self.row += 1;
501 Ok(())
502 }
503}
504
505impl<S: Source> Streaming<S> {
506 fn refill(&mut self) -> Result<bool> {
511 if self.input_done {
512 return Ok(false);
513 }
514 let mut buffer = vec![0_u8; READ_CHUNK];
515
516 loop {
520 if self.chunks.payload_done() {
521 self.chunks.close()?;
522 loop {
524 let kind = self.chunks.open_next()?;
525 match &kind {
526 b"IDAT" => break,
527 b"IEND" => {
528 self.chunks.skip_payload()?;
532 self.chunks.close()?;
533 self.input_done = true;
534 let tail = self.zlib.finish().map_err(crate::compress_error)?;
535 self.filtered.extend_from_slice(&tail);
536 return Ok(!tail.is_empty());
537 }
538 _ => {
539 if !self.chunks.is_ancillary() {
540 return Err(PixelsError::malformed(
541 "png",
542 format!("unknown critical chunk `{}`", self.chunks.name()),
543 ));
544 }
545 self.chunks.skip_payload()?;
546 self.chunks.close()?;
547 }
548 }
549 }
550 }
551
552 let read = self.chunks.read_payload(&mut buffer)?;
553 if read == 0 {
554 continue;
555 }
556 let produced = self
557 .zlib
558 .push(buffer.get(..read).unwrap_or(&[]))
559 .map_err(crate::compress_error)?;
560 if !produced.is_empty() {
561 self.filtered.extend_from_slice(&produced);
562 return Ok(true);
563 }
564 }
565 }
566
567 fn finalize(&mut self) -> Result<()> {
574 while self.refill()? {}
575 if !self.input_done {
576 return Err(PixelsError::malformed(
577 "png",
578 "stream ends without an IEND chunk",
579 ));
580 }
581 Ok(())
582 }
583
584 fn next_scanline(&mut self, row_bytes: usize, stride: usize) -> Result<Vec<u8>> {
586 let want = row_bytes + 1;
587 while self.filtered.len() - self.at < want {
588 if !self.refill()? {
589 return Err(PixelsError::malformed(
590 "png",
591 "image data ends before the last scanline",
592 ));
593 }
594 }
595
596 let filter_byte = self
597 .filtered
598 .get(self.at)
599 .copied()
600 .ok_or_else(|| PixelsError::malformed("png", "scanline ends early"))?;
601 let filter = Filter::from_byte(filter_byte)?;
602 let start = self.at + 1;
603 let mut current = self
604 .filtered
605 .get(start..start + row_bytes)
606 .ok_or_else(|| PixelsError::malformed("png", "scanline ends early"))?
607 .to_vec();
608 self.at = start + row_bytes;
609
610 if self.at >= self.filtered.len() {
613 self.filtered.clear();
614 self.at = 0;
615 } else if self.at > READ_CHUNK {
616 self.filtered.drain(..self.at);
617 self.at = 0;
618 }
619
620 unfilter(filter, &mut current, &self.previous, stride)?;
621 self.previous.clear();
622 self.previous.extend_from_slice(¤t);
623 Ok(current)
624 }
625}
626
627fn parse_plte(data: &[u8]) -> Result<Vec<[u8; 3]>> {
629 if data.len() % 3 != 0 || data.is_empty() {
630 return Err(PixelsError::malformed(
631 "png",
632 format!("PLTE length {} is not a positive multiple of 3", data.len()),
633 ));
634 }
635 if data.len() / 3 > 256 {
636 return Err(PixelsError::malformed(
637 "png",
638 "PLTE has more than 256 entries",
639 ));
640 }
641 Ok(data
642 .chunks_exact(3)
643 .map(|rgb| {
644 [
645 rgb.first().copied().unwrap_or(0),
646 rgb.get(1).copied().unwrap_or(0),
647 rgb.get(2).copied().unwrap_or(0),
648 ]
649 })
650 .collect())
651}
652
653fn copy_pixel_bits(
655 source_row: &[u8],
656 source_x: usize,
657 out: &mut [u8],
658 row_start: usize,
659 dest_x: usize,
660 bits_per_pixel: usize,
661) {
662 if bits_per_pixel >= 8 {
663 let bytes = bits_per_pixel / 8;
664 for byte in 0..bytes {
665 let value = source_row
666 .get(source_x * bytes + byte)
667 .copied()
668 .unwrap_or(0);
669 if let Some(slot) = out.get_mut(row_start + dest_x * bytes + byte) {
670 *slot = value;
671 }
672 }
673 return;
674 }
675 let value = read_bits(source_row, source_x, bits_per_pixel);
677 write_bits(out, row_start, dest_x, bits_per_pixel, value);
678}
679
680fn read_bits(row: &[u8], index: usize, bits: usize) -> u8 {
682 let per_byte = 8 / bits;
683 let byte = row.get(index / per_byte).copied().unwrap_or(0);
684 let shift = 8 - bits * (index % per_byte + 1);
685 (byte >> shift) & ((1 << bits) - 1) as u8
686}
687
688fn write_bits(out: &mut [u8], row_start: usize, index: usize, bits: usize, value: u8) {
690 let per_byte = 8 / bits;
691 let offset = row_start + index / per_byte;
692 let shift = 8 - bits * (index % per_byte + 1);
693 let mask = ((1 << bits) - 1) as u8;
694 if let Some(slot) = out.get_mut(offset) {
695 *slot = (*slot & !(mask << shift)) | ((value & mask) << shift);
696 }
697}
698
699fn read_sample(row: &[u8], index: usize, depth: u8) -> u16 {
701 match depth {
702 16 => {
703 let high = row.get(index * 2).copied().unwrap_or(0);
705 let low = row.get(index * 2 + 1).copied().unwrap_or(0);
706 u16::from_be_bytes([high, low])
707 }
708 8 => u16::from(row.get(index).copied().unwrap_or(0)),
709 bits => u16::from(read_bits(row, index, bits as usize)),
710 }
711}
712
713const fn scale8(value: u16, max: u16) -> u8 {
718 if max == 0 {
719 return 0;
720 }
721 ((value as u32 * 255 + max as u32 / 2) / max as u32) as u8
722}
723
724#[allow(
726 clippy::too_many_arguments,
727 reason = "one pixel conversion needs all of it"
728)]
729fn write_pixel(
730 out: &mut [u8],
731 at: &mut usize,
732 format: PixelFormat,
733 color_type: ColorType,
734 channel: &[u16; 4],
735 depth: u8,
736 max: u16,
737 palette: Option<&[[u8; 3]]>,
738 transparency: Option<&Transparency>,
739) -> Result<()> {
740 fn push(out: &mut [u8], at: &mut usize, value: u8) {
742 if let Some(slot) = out.get_mut(*at) {
743 *slot = value;
744 }
745 *at += 1;
746 }
747 fn push16(out: &mut [u8], at: &mut usize, value: u16) {
749 for byte in value.to_ne_bytes() {
750 push(out, at, byte);
751 }
752 }
753
754 match color_type {
755 ColorType::Palette => {
756 let index = channel[0] as usize;
757 let entries = palette
758 .ok_or_else(|| PixelsError::malformed("png", "palette image without a palette"))?;
759 let rgb = entries.get(index).copied().ok_or_else(|| {
760 PixelsError::malformed(
761 "png",
762 format!(
763 "palette index {index} is beyond the {}-entry palette",
764 entries.len()
765 ),
766 )
767 })?;
768 push(out, at, rgb[0]);
769 push(out, at, rgb[1]);
770 push(out, at, rgb[2]);
771 if format == PixelFormat::Rgba8 {
772 let alpha = match transparency {
773 Some(Transparency::Palette(alphas)) => {
774 alphas.get(index).copied().unwrap_or(255)
776 }
777 _ => 255,
778 };
779 push(out, at, alpha);
780 }
781 }
782 ColorType::Grayscale => {
783 let transparent =
784 matches!(transparency, Some(Transparency::Gray(key)) if *key == channel[0]);
785 match format {
786 PixelFormat::Gray8 => push(out, at, scale8(channel[0], max)),
787 PixelFormat::Gray16 => push16(out, at, channel[0]),
788 PixelFormat::GrayA8 => {
789 push(out, at, scale8(channel[0], max));
790 push(out, at, if transparent { 0 } else { 255 });
791 }
792 PixelFormat::Rgba16 => {
793 let value = if depth == 16 {
794 channel[0]
795 } else {
796 channel[0] * 257
797 };
798 push16(out, at, value);
799 push16(out, at, value);
800 push16(out, at, value);
801 push16(out, at, if transparent { 0 } else { u16::MAX });
802 }
803 other => {
804 return Err(PixelsError::unsupported(format!(
805 "greyscale cannot be written as {other}"
806 )));
807 }
808 }
809 }
810 ColorType::GrayscaleAlpha => match format {
811 PixelFormat::GrayA8 => {
812 push(out, at, scale8(channel[0], max));
813 push(out, at, scale8(channel[1], max));
814 }
815 PixelFormat::Rgba16 => {
816 push16(out, at, channel[0]);
817 push16(out, at, channel[0]);
818 push16(out, at, channel[0]);
819 push16(out, at, channel[1]);
820 }
821 other => {
822 return Err(PixelsError::unsupported(format!(
823 "grey+alpha cannot be written as {other}"
824 )));
825 }
826 },
827 ColorType::Rgb => {
828 let transparent = matches!(
829 transparency,
830 Some(Transparency::Rgb(r, g, b))
831 if *r == channel[0] && *g == channel[1] && *b == channel[2]
832 );
833 match format {
834 PixelFormat::Rgb8 => {
835 for &value in channel.iter().take(3) {
836 push(out, at, scale8(value, max));
837 }
838 }
839 PixelFormat::Rgb16 => {
840 for &value in channel.iter().take(3) {
841 push16(out, at, value);
842 }
843 }
844 PixelFormat::Rgba8 => {
845 for &value in channel.iter().take(3) {
846 push(out, at, scale8(value, max));
847 }
848 push(out, at, if transparent { 0 } else { 255 });
849 }
850 PixelFormat::Rgba16 => {
851 for &value in channel.iter().take(3) {
852 push16(out, at, value);
853 }
854 push16(out, at, if transparent { 0 } else { u16::MAX });
855 }
856 other => {
857 return Err(PixelsError::unsupported(format!(
858 "RGB cannot be written as {other}"
859 )));
860 }
861 }
862 }
863 ColorType::Rgba => match format {
864 PixelFormat::Rgba8 => {
865 for &value in channel {
866 push(out, at, scale8(value, max));
867 }
868 }
869 PixelFormat::Rgba16 => {
870 for &value in channel {
871 push16(out, at, value);
872 }
873 }
874 other => {
875 return Err(PixelsError::unsupported(format!(
876 "RGBA cannot be written as {other}"
877 )));
878 }
879 },
880 }
881 Ok(())
882}
883
884fn parse_trns(data: &[u8], color_type: ColorType) -> Result<Transparency> {
886 fn be16(data: &[u8], offset: usize) -> u16 {
888 u16::from_be_bytes([
889 data.get(offset).copied().unwrap_or(0),
890 data.get(offset + 1).copied().unwrap_or(0),
891 ])
892 }
893 match color_type {
894 ColorType::Grayscale => {
895 if data.len() != 2 {
896 return Err(PixelsError::malformed(
897 "png",
898 format!("greyscale tRNS must be 2 bytes, got {}", data.len()),
899 ));
900 }
901 Ok(Transparency::Gray(be16(data, 0)))
902 }
903 ColorType::Rgb => {
904 if data.len() != 6 {
905 return Err(PixelsError::malformed(
906 "png",
907 format!("RGB tRNS must be 6 bytes, got {}", data.len()),
908 ));
909 }
910 Ok(Transparency::Rgb(
911 be16(data, 0),
912 be16(data, 2),
913 be16(data, 4),
914 ))
915 }
916 ColorType::Palette => {
917 if data.len() > 256 {
918 return Err(PixelsError::malformed(
919 "png",
920 format!(
921 "palette tRNS has {} entries, over the 256 maximum",
922 data.len()
923 ),
924 ));
925 }
926 Ok(Transparency::Palette(data.to_vec()))
927 }
928 ColorType::GrayscaleAlpha | ColorType::Rgba => Err(PixelsError::malformed(
930 "png",
931 "tRNS is not allowed for colour types that already carry alpha",
932 )),
933 }
934}
935
936impl<S: Source + std::fmt::Debug> Decoder for PngDecoder<S> {
937 fn descriptor(&self) -> ImageDescriptor {
938 self.descriptor
939 }
940
941 fn orientation(&self) -> Orientation {
944 self.orientation
945 }
946
947 fn icc_profile(&self) -> Option<&[u8]> {
949 self.icc.as_deref()
950 }
951
952 fn capability(&self) -> DecodeCapability {
953 DecodeCapability::Sequential
958 }
959
960 fn read_row(&mut self, out: &mut [u8]) -> Result<()> {
961 if self.header.interlaced {
964 return self.read_row_buffered(out);
965 }
966 if self.stream.is_none() {
967 let started = self.begin_streaming()?;
968 self.stream = Some(Box::new(started));
969 }
970 if self.row >= self.descriptor.height {
971 return Err(PixelsError::invalid_argument(
972 "out",
973 format!("all {} rows have already been read", self.descriptor.height),
974 ));
975 }
976 let row_bytes = self.descriptor.row_bytes();
977 if out.len() != row_bytes {
978 return Err(PixelsError::invalid_argument(
979 "out",
980 format!("row buffer is {} bytes, expected {row_bytes}", out.len()),
981 ));
982 }
983
984 let sample_bytes = self.header.row_bytes(self.header.width);
985 let stride = self.header.filter_stride();
986 let Some(stream) = self.stream.as_mut() else {
987 return Err(PixelsError::graph("png stream vanished after starting"));
988 };
989 let samples = stream.next_scanline(sample_bytes, stride)?;
990 let palette = stream.palette.clone();
991 let transparency = stream.transparency.clone();
992
993 self.expand_row(&samples, palette.as_deref(), transparency.as_ref(), out)?;
994 self.row += 1;
995
996 if self.row == self.descriptor.height {
999 if let Some(stream) = self.stream.as_mut() {
1000 stream.finalize()?;
1001 }
1002 }
1003 Ok(())
1004 }
1005}
1006
1007#[must_use]
1011pub fn probe(prefix: &[u8]) -> bool {
1012 prefix.get(..8) == Some(&SIGNATURE[..])
1013}
1014
1015#[derive(Debug, Clone, Copy, Default)]
1021pub struct PngCodec;
1022
1023impl Codec for PngCodec {
1024 fn format(&self) -> Format {
1025 Format::Png
1026 }
1027
1028 fn magic_len(&self) -> usize {
1029 SIGNATURE.len()
1030 }
1031
1032 fn probe(&self, prefix: &[u8]) -> bool {
1033 probe(prefix)
1034 }
1035}