tiff/
error.rs

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, actual) => {
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) => 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) => write!(fmt, "Format error: {}", e),
255            TiffError::UnsupportedError(ref f) => write!(
256                fmt,
257                "The Decoder does not support the \
258                 image format `{}`",
259                f
260            ),
261            TiffError::IoError(ref e) => 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) => 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) => 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(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>;