1use std::error::Error;
2use std::fmt;
3use std::fmt::Display;
4use std::io;
5use std::str;
6use std::string;
7use std::sync::Arc;
8
9use jpeg::UnsupportedFeature;
10
11use crate::decoder::{ifd::Value, ChunkType};
12use crate::tags::{
13 CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag,
14};
15use crate::ColorType;
16
17use crate::weezl::LzwError;
18
19/// Tiff error kinds.
20#[derive(Debug)]
21pub enum TiffError {
22 /// The Image is not formatted properly.
23 FormatError(TiffFormatError),
24
25 /// The Decoder does not support features required by the image.
26 UnsupportedError(TiffUnsupportedError),
27
28 /// An I/O Error occurred while decoding the image.
29 IoError(io::Error),
30
31 /// The Limits of the Decoder is exceeded.
32 LimitsExceeded,
33
34 /// An integer conversion to or from a platform size failed, either due to
35 /// limits of the platform size or limits of the format.
36 IntSizeError,
37
38 /// The image does not support the requested operation
39 UsageError(UsageError),
40}
41
42/// The image is not formatted properly.
43///
44/// This indicates that the encoder producing the image might behave incorrectly or that the input
45/// file has been corrupted.
46///
47/// The list of variants may grow to incorporate errors of future features. Matching against this
48/// exhaustively is not covered by interface stability guarantees.
49#[derive(Debug, Clone, PartialEq)]
50#[non_exhaustive]
51pub enum TiffFormatError {
52 TiffSignatureNotFound,
53 TiffSignatureInvalid,
54 ImageFileDirectoryNotFound,
55 InconsistentSizesEncountered,
56 UnexpectedCompressedData {
57 actual_bytes: usize,
58 required_bytes: usize,
59 },
60 InconsistentStripSamples {
61 actual_samples: usize,
62 required_samples: usize,
63 },
64 InvalidDimensions(u32, u32),
65 InvalidTag,
66 InvalidTagValueType(Tag),
67 RequiredTagNotFound(Tag),
68 UnknownPredictor(u16),
69 UnknownPlanarConfiguration(u16),
70 ByteExpected(Value),
71 UnsignedIntegerExpected(Value),
72 SignedIntegerExpected(Value),
73 Format(String),
74 RequiredTagEmpty(Tag),
75 StripTileTagConflict,
76 CycleInOffsets,
77 JpegDecoder(JpegDecoderError),
78 SamplesPerPixelIsZero,
79}
80
81impl fmt::Display for TiffFormatError {
82 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
83 use self::TiffFormatError::*;
84 match *self {
85 TiffSignatureNotFound => write!(fmt, "TIFF signature not found."),
86 TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."),
87 ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."),
88 InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."),
89 UnexpectedCompressedData {
90 actual_bytes,
91 required_bytes,
92 } => {
93 write!(
94 fmt,
95 "Decompression returned different amount of bytes than expected: got {}, expected {}.",
96 actual_bytes, required_bytes
97 )
98 }
99 InconsistentStripSamples {
100 actual_samples,
101 required_samples,
102 } => {
103 write!(
104 fmt,
105 "Inconsistent elements in strip: got {}, expected {}.",
106 actual_samples, required_samples
107 )
108 }
109 InvalidDimensions(width, height) => write!(fmt, "Invalid dimensions: {}x{}.", width, height),
110 InvalidTag => write!(fmt, "Image contains invalid tag."),
111 InvalidTagValueType(ref tag) => {
112 write!(fmt, "Tag `{:?}` did not have the expected value type.", tag)
113 }
114 RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag),
115 UnknownPredictor(ref predictor) => {
116 write!(fmt, "Unknown predictor “{}” encountered", predictor)
117 }
118 UnknownPlanarConfiguration(ref planar_config) => {
119 write!(fmt, "Unknown planar configuration “{}” encountered", planar_config)
120 }
121 ByteExpected(ref val) => write!(fmt, "Expected byte, {:?} found.", val),
122 UnsignedIntegerExpected(ref val) => {
123 write!(fmt, "Expected unsigned integer, {:?} found.", val)
124 }
125 SignedIntegerExpected(ref val) => {
126 write!(fmt, "Expected signed integer, {:?} found.", val)
127 }
128 Format(ref val) => write!(fmt, "Invalid format: {:?}.", val),
129 RequiredTagEmpty(ref val) => write!(fmt, "Required tag {:?} was empty.", val),
130 StripTileTagConflict => write!(fmt, "File should contain either (StripByteCounts and StripOffsets) or (TileByteCounts and TileOffsets), other combination was found."),
131 CycleInOffsets => write!(fmt, "File contained a cycle in the list of IFDs"),
132 JpegDecoder(ref error) => write!(fmt, "{}", error),
133 SamplesPerPixelIsZero => write!(fmt, "Samples per pixel is zero"),
134 }
135 }
136}
137
138/// The Decoder does not support features required by the image.
139///
140/// This only captures known failures for which the standard either does not require support or an
141/// implementation has been planned but not yet completed. Some variants may become unused over
142/// time and will then get deprecated before being removed.
143///
144/// The list of variants may grow. Matching against this exhaustively is not covered by interface
145/// stability guarantees.
146#[derive(Debug, Clone, PartialEq, Eq, Hash)]
147#[non_exhaustive]
148pub enum TiffUnsupportedError {
149 FloatingPointPredictor(ColorType),
150 HorizontalPredictor(ColorType),
151 InconsistentBitsPerSample(Vec<u8>),
152 InterpretationWithBits(PhotometricInterpretation, Vec<u8>),
153 UnknownInterpretation,
154 UnknownCompressionMethod,
155 UnsupportedCompressionMethod(CompressionMethod),
156 UnsupportedSampleDepth(u8),
157 UnsupportedSampleFormat(Vec<SampleFormat>),
158 UnsupportedColorType(ColorType),
159 UnsupportedBitsPerChannel(u8),
160 UnsupportedPlanarConfig(Option<PlanarConfiguration>),
161 UnsupportedDataType,
162 UnsupportedInterpretation(PhotometricInterpretation),
163 UnsupportedJpegFeature(UnsupportedFeature),
164}
165
166impl fmt::Display for TiffUnsupportedError {
167 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
168 use self::TiffUnsupportedError::*;
169 match *self {
170 FloatingPointPredictor(color_type) => write!(
171 fmt,
172 "Floating point predictor for {:?} is unsupported.",
173 color_type
174 ),
175 HorizontalPredictor(color_type) => write!(
176 fmt,
177 "Horizontal predictor for {:?} is unsupported.",
178 color_type
179 ),
180 InconsistentBitsPerSample(ref bits_per_sample) => {
181 write!(fmt, "Inconsistent bits per sample: {:?}.", bits_per_sample)
182 }
183 InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => write!(
184 fmt,
185 "{:?} with {:?} bits per sample is unsupported",
186 photometric_interpretation, bits_per_sample
187 ),
188 UnknownInterpretation => write!(
189 fmt,
190 "The image is using an unknown photometric interpretation."
191 ),
192 UnknownCompressionMethod => write!(fmt, "Unknown compression method."),
193 UnsupportedCompressionMethod(method) => {
194 write!(fmt, "Compression method {:?} is unsupported", method)
195 }
196 UnsupportedSampleDepth(samples) => {
197 write!(fmt, "{} samples per pixel is unsupported.", samples)
198 }
199 UnsupportedSampleFormat(ref formats) => {
200 write!(fmt, "Sample format {:?} is unsupported.", formats)
201 }
202 UnsupportedColorType(color_type) => {
203 write!(fmt, "Color type {:?} is unsupported", color_type)
204 }
205 UnsupportedBitsPerChannel(bits) => {
206 write!(fmt, "{} bits per channel not supported", bits)
207 }
208 UnsupportedPlanarConfig(config) => {
209 write!(fmt, "Unsupported planar configuration “{:?}”.", config)
210 }
211 UnsupportedDataType => write!(fmt, "Unsupported data type."),
212 UnsupportedInterpretation(interpretation) => {
213 write!(
214 fmt,
215 "Unsupported photometric interpretation \"{:?}\".",
216 interpretation
217 )
218 }
219 UnsupportedJpegFeature(ref unsupported_feature) => {
220 write!(fmt, "Unsupported JPEG feature {:?}", unsupported_feature)
221 }
222 }
223 }
224}
225
226/// User attempted to use the Decoder in a way that is incompatible with a specific image.
227///
228/// For example: attempting to read a tile from a stripped image.
229#[derive(Debug)]
230pub enum UsageError {
231 InvalidChunkType(ChunkType, ChunkType),
232 InvalidChunkIndex(u32),
233}
234
235impl fmt::Display for UsageError {
236 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
237 use self::UsageError::*;
238 match *self {
239 InvalidChunkType(expected: ChunkType, actual: ChunkType) => {
240 write!(
241 fmt,
242 "Requested operation is only valid for images with chunk encoding of type: {:?}, got {:?}.",
243 expected, actual
244 )
245 }
246 InvalidChunkIndex(index: u32) => write!(fmt, "Image chunk index ({}) requested.", index),
247 }
248 }
249}
250
251impl fmt::Display for TiffError {
252 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
253 match *self {
254 TiffError::FormatError(ref e: &TiffFormatError) => write!(fmt, "Format error: {}", e),
255 TiffError::UnsupportedError(ref f: &TiffUnsupportedError) => write!(
256 fmt,
257 "The Decoder does not support the \
258 image format `{}`",
259 f
260 ),
261 TiffError::IoError(ref e: &Error) => e.fmt(fmt),
262 TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"),
263 TiffError::IntSizeError => write!(fmt, "Platform or format size limits exceeded"),
264 TiffError::UsageError(ref e: &UsageError) => write!(fmt, "Usage error: {}", e),
265 }
266 }
267}
268
269impl Error for TiffError {
270 fn description(&self) -> &str {
271 match *self {
272 TiffError::FormatError(..) => "Format error",
273 TiffError::UnsupportedError(..) => "Unsupported error",
274 TiffError::IoError(..) => "IO error",
275 TiffError::LimitsExceeded => "Decoder limits exceeded",
276 TiffError::IntSizeError => "Platform or format size limits exceeded",
277 TiffError::UsageError(..) => "Invalid usage",
278 }
279 }
280
281 fn cause(&self) -> Option<&dyn Error> {
282 match *self {
283 TiffError::IoError(ref e: &Error) => Some(e),
284 _ => None,
285 }
286 }
287}
288
289impl From<io::Error> for TiffError {
290 fn from(err: io::Error) -> TiffError {
291 TiffError::IoError(err)
292 }
293}
294
295impl From<str::Utf8Error> for TiffError {
296 fn from(_err: str::Utf8Error) -> TiffError {
297 TiffError::FormatError(TiffFormatError::InvalidTag)
298 }
299}
300
301impl From<string::FromUtf8Error> for TiffError {
302 fn from(_err: string::FromUtf8Error) -> TiffError {
303 TiffError::FormatError(TiffFormatError::InvalidTag)
304 }
305}
306
307impl From<TiffFormatError> for TiffError {
308 fn from(err: TiffFormatError) -> TiffError {
309 TiffError::FormatError(err)
310 }
311}
312
313impl From<TiffUnsupportedError> for TiffError {
314 fn from(err: TiffUnsupportedError) -> TiffError {
315 TiffError::UnsupportedError(err)
316 }
317}
318
319impl From<UsageError> for TiffError {
320 fn from(err: UsageError) -> TiffError {
321 TiffError::UsageError(err)
322 }
323}
324
325impl From<std::num::TryFromIntError> for TiffError {
326 fn from(_err: std::num::TryFromIntError) -> TiffError {
327 TiffError::IntSizeError
328 }
329}
330
331impl From<LzwError> for TiffError {
332 fn from(err: LzwError) -> TiffError {
333 match err {
334 LzwError::InvalidCode => TiffError::FormatError(TiffFormatError::Format(String::from(
335 "LZW compressed data corrupted",
336 ))),
337 }
338 }
339}
340
341#[derive(Debug, Clone)]
342pub struct JpegDecoderError {
343 inner: Arc<jpeg::Error>,
344}
345
346impl JpegDecoderError {
347 fn new(error: jpeg::Error) -> Self {
348 Self {
349 inner: Arc::new(data:error),
350 }
351 }
352}
353
354impl PartialEq for JpegDecoderError {
355 fn eq(&self, other: &Self) -> bool {
356 Arc::ptr_eq(&self.inner, &other.inner)
357 }
358}
359
360impl Display for JpegDecoderError {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 self.inner.fmt(f)
363 }
364}
365
366impl From<JpegDecoderError> for TiffError {
367 fn from(error: JpegDecoderError) -> Self {
368 TiffError::FormatError(TiffFormatError::JpegDecoder(error))
369 }
370}
371
372impl From<jpeg::Error> for TiffError {
373 fn from(error: jpeg::Error) -> Self {
374 JpegDecoderError::new(error).into()
375 }
376}
377
378/// Result of an image decoding/encoding process
379pub type TiffResult<T> = Result<T, TiffError>;
380