1use std::io::{BufReader, Read, Seek};
2use std::path::Path;
3
4use crate::chunk::{self, Chunk};
5
6#[derive(Debug, thiserror::Error)]
7pub enum DecodingError {
8 #[error("I/O error: {0}")]
9 Io(#[from] std::io::Error),
10 #[error("Not a PNG")]
11 NotPng,
12 #[error("Invalid checksum")]
13 InvalidChecksum,
14 #[error("Failed to decode image")]
15 Image(#[from] image::ImageError),
16 #[error("Invalid chunk name {0:?}")]
17 Chunk(#[from] chunk::Error),
18 #[error("Invalid filename")]
19 Filename(#[from] std::str::Utf8Error),
20 #[error("Chunk not found")]
21 ChunkNotFound,
22}
23
24pub struct Decoder<R: Read + Seek> {
26 reader: R,
27}
28impl<R: Read + Seek> Decoder<R> {
29 pub fn from_reader(reader: R) -> Self {
30 Self { reader }
31 }
32}
33impl Decoder<BufReader<std::fs::File>> {
34 pub fn from_file(filename: impl AsRef<Path>) -> Result<Self, std::io::Error> {
36 let reader = std::fs::File::open(filename)?;
37 let reader = std::io::BufReader::new(reader);
38 Ok(Self::from_reader(reader))
39 }
40}
41impl<R: Read + Seek> Decoder<R> {
42 pub fn decode_ancillary_chunks(&mut self) -> Result<Vec<Chunk>, DecodingError> {
45 self.reader.seek(std::io::SeekFrom::Start(0))?;
46 let mut header = [0; 8];
48 self.reader.read_exact(&mut header)?;
49 if &header[1..4] != b"PNG" {
50 return Err(DecodingError::NotPng);
51 }
52 let mut chunks = vec![];
53 loop {
54 let c = Chunk::from_reader(&mut self.reader)?;
55 if c.chunk_type == png::chunk::IEND || c.chunk_type == png::chunk::IDAT {
56 break;
57 }
58 if !c.chunk_type.is_critical() {
59 chunks.push(c);
60 }
61 }
62 Ok(chunks)
63 }
64 pub fn decode_all(&mut self) -> Result<(image::DynamicImage, Vec<Chunk>), DecodingError> {
66 let chunks = self.decode_ancillary_chunks()?;
67 self.reader.seek(std::io::SeekFrom::Start(0))?;
70 let image = image::DynamicImage::from_decoder(image::codecs::png::PngDecoder::new(
71 &mut self.reader,
72 )?)?;
73 Ok((image, chunks))
74 }
75}