1use std::collections::HashMap;
4use std::fmt::Debug;
5use std::io::{Cursor, Read};
6
7use bytes::Bytes;
8use flate2::bufread::ZlibDecoder;
9
10use crate::error::AsyncTiffResult;
11use crate::tiff::tags::{CompressionMethod, PhotometricInterpretation};
12use crate::tiff::{TiffError, TiffUnsupportedError};
13
14#[derive(Debug)]
19pub struct DecoderRegistry(HashMap<CompressionMethod, Box<dyn Decoder>>);
20
21impl DecoderRegistry {
22 pub fn new() -> Self {
24 Self(HashMap::new())
25 }
26}
27
28impl AsRef<HashMap<CompressionMethod, Box<dyn Decoder>>> for DecoderRegistry {
29 fn as_ref(&self) -> &HashMap<CompressionMethod, Box<dyn Decoder>> {
30 &self.0
31 }
32}
33
34impl AsMut<HashMap<CompressionMethod, Box<dyn Decoder>>> for DecoderRegistry {
35 fn as_mut(&mut self) -> &mut HashMap<CompressionMethod, Box<dyn Decoder>> {
36 &mut self.0
37 }
38}
39
40impl Default for DecoderRegistry {
41 fn default() -> Self {
42 let mut registry = HashMap::with_capacity(5);
43 registry.insert(CompressionMethod::None, Box::new(UncompressedDecoder) as _);
44 registry.insert(CompressionMethod::Deflate, Box::new(DeflateDecoder) as _);
45 registry.insert(CompressionMethod::OldDeflate, Box::new(DeflateDecoder) as _);
46 registry.insert(CompressionMethod::LZW, Box::new(LZWDecoder) as _);
47 registry.insert(CompressionMethod::ModernJPEG, Box::new(JPEGDecoder) as _);
48 Self(registry)
49 }
50}
51
52pub trait Decoder: Debug + Send + Sync {
54 fn decode_tile(
56 &self,
57 buffer: Bytes,
58 photometric_interpretation: PhotometricInterpretation,
59 jpeg_tables: Option<&[u8]>,
60 ) -> AsyncTiffResult<Bytes>;
61}
62
63#[derive(Debug, Clone)]
65pub struct DeflateDecoder;
66
67impl Decoder for DeflateDecoder {
68 fn decode_tile(
69 &self,
70 buffer: Bytes,
71 _photometric_interpretation: PhotometricInterpretation,
72 _jpeg_tables: Option<&[u8]>,
73 ) -> AsyncTiffResult<Bytes> {
74 let mut decoder = ZlibDecoder::new(Cursor::new(buffer));
75 let mut buf = Vec::new();
76 decoder.read_to_end(&mut buf)?;
77 Ok(buf.into())
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct JPEGDecoder;
84
85impl Decoder for JPEGDecoder {
86 fn decode_tile(
87 &self,
88 buffer: Bytes,
89 photometric_interpretation: PhotometricInterpretation,
90 jpeg_tables: Option<&[u8]>,
91 ) -> AsyncTiffResult<Bytes> {
92 decode_modern_jpeg(buffer, photometric_interpretation, jpeg_tables)
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct LZWDecoder;
99
100impl Decoder for LZWDecoder {
101 fn decode_tile(
102 &self,
103 buffer: Bytes,
104 _photometric_interpretation: PhotometricInterpretation,
105 _jpeg_tables: Option<&[u8]>,
106 ) -> AsyncTiffResult<Bytes> {
107 let mut decoder = weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
109 let decoded = decoder.decode(&buffer).expect("failed to decode LZW data");
110 Ok(decoded.into())
111 }
112}
113
114#[derive(Debug, Clone)]
116pub struct UncompressedDecoder;
117
118impl Decoder for UncompressedDecoder {
119 fn decode_tile(
120 &self,
121 buffer: Bytes,
122 _photometric_interpretation: PhotometricInterpretation,
123 _jpeg_tables: Option<&[u8]>,
124 ) -> AsyncTiffResult<Bytes> {
125 Ok(buffer)
126 }
127}
128
129fn decode_modern_jpeg(
131 buf: Bytes,
132 photometric_interpretation: PhotometricInterpretation,
133 jpeg_tables: Option<&[u8]>,
134) -> AsyncTiffResult<Bytes> {
135 let reader = Cursor::new(buf);
146
147 let jpeg_reader = match jpeg_tables {
148 Some(jpeg_tables) => {
149 let mut reader = reader;
150 reader.read_exact(&mut [0; 2])?;
151
152 Box::new(Cursor::new(&jpeg_tables[..jpeg_tables.len() - 2]).chain(reader))
153 as Box<dyn Read>
154 }
155 None => Box::new(reader),
156 };
157
158 let mut decoder = jpeg::Decoder::new(jpeg_reader);
159
160 match photometric_interpretation {
161 PhotometricInterpretation::RGB => decoder.set_color_transform(jpeg::ColorTransform::RGB),
162 PhotometricInterpretation::WhiteIsZero
163 | PhotometricInterpretation::BlackIsZero
164 | PhotometricInterpretation::TransparencyMask => {
165 decoder.set_color_transform(jpeg::ColorTransform::None)
166 }
167 PhotometricInterpretation::CMYK => decoder.set_color_transform(jpeg::ColorTransform::CMYK),
168 PhotometricInterpretation::YCbCr => {
169 decoder.set_color_transform(jpeg::ColorTransform::YCbCr)
170 }
171 photometric_interpretation => {
172 return Err(TiffError::UnsupportedError(
173 TiffUnsupportedError::UnsupportedInterpretation(photometric_interpretation),
174 )
175 .into());
176 }
177 }
178
179 let data = decoder.decode()?;
180 Ok(data.into())
181}