Skip to main content

tiff/
error.rs

1use std::io;
2use std::str;
3use std::string;
4
5use quick_error::quick_error;
6
7use crate::decoder::ChunkType;
8use crate::tags::Type;
9use crate::tags::{
10    CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag,
11};
12use crate::ColorType;
13
14quick_error! {
15    /// Tiff error kinds.
16    #[derive(Debug)]
17    pub enum TiffError {
18        /// The Image is not formatted properly.
19        FormatError(err: TiffFormatError) {
20            display("format error: {err}")
21            from()
22            source(err)
23        }
24        /// The Decoder does not support features required by the image.
25        UnsupportedError(err: TiffUnsupportedError) {
26            display("unsupported error: {err}")
27            from()
28            source(err)
29        }
30        /// An I/O Error occurred while decoding the image.
31        IoError(err: io::Error) {
32            display("{err}")
33            from()
34            source(err)
35        }
36        /// The Limits of the Decoder is exceeded.
37        LimitsExceeded {
38            display("decoder limits exceeded")
39        }
40        /// An integer conversion to or from a platform size failed.
41        IntSizeError {
42            display("platform or format size limits exceeded")
43        }
44        /// The image does not support the requested operation
45        UsageError(err: UsageError) {
46            display("usage error: {err}")
47            from()
48            source(err)
49        }
50    }
51}
52
53quick_error! {
54    /// The image is not formatted properly.
55    ///
56    /// This indicates that the encoder producing the image might behave incorrectly or that the
57    /// input file has been corrupted.
58    #[derive(Debug, Clone, PartialEq)]
59    #[non_exhaustive]
60    pub enum TiffFormatError {
61        TiffSignatureNotFound {
62            display("TIFF signature not found")
63        }
64        TiffSignatureInvalid {
65            display("TIFF signature invalid")
66        }
67        ImageFileDirectoryNotFound {
68            display("image file directory not found")
69        }
70        InconsistentSizesEncountered {
71            display("inconsistent sizes encountered")
72        }
73        InvalidDimensions(width: u32, height: u32) {
74            display("invalid dimensions: {width}x{height}")
75        }
76        InvalidTag {
77            display("image contains invalid tag")
78        }
79        InvalidTagValueType(tag: Tag) {
80            display("tag `{tag:?}` did not have the expected value type")
81        }
82        RequiredTagNotFound(tag: Tag) {
83            display("required tag `{tag:?}` not found")
84        }
85        UnknownPredictor(pred: u16) {
86            display("unknown predictor “{pred}” encountered")
87        }
88        UnknownPlanarConfiguration(cfg: u16) {
89            display("unknown planar configuration “{cfg}”")
90        }
91        InvalidTypeForTag {
92            display("tag has invalid type")
93        }
94        InvalidCountForTag(tag: Tag, len: usize) {
95            display("tag `{tag:?}` with incorrect number of elements ({len}) encountered")
96        }
97        StripTileTagConflict {
98            display("file should contain either (StripByteCounts and StripOffsets) or (TileByteCounts and TileOffsets), other combination was found")
99        }
100        CycleInOffsets {
101            display("file contained a cycle in the list of IFDs")
102        }
103        SamplesPerPixelIsZero {
104            display("samples per pixel is zero")
105        }
106        CompressedDataCorrupt(message: String) {
107            display("compressed data is corrupt: {message}")
108        }
109    }
110}
111
112quick_error! {
113    /// The Decoder does not support features required by the image.
114    ///
115    /// This only captures known failures for which the standard either does not require support or an
116    /// implementation has been planned but not yet completed. Some variants may become unused over
117    /// time and will then get deprecated before being removed.
118    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
119    #[non_exhaustive]
120    pub enum TiffUnsupportedError {
121        FloatingPointPredictor(color_type: ColorType) {
122            display("floating point predictor for {color_type:?} is unsupported")
123        }
124        HorizontalPredictor(color_type: ColorType) {
125            display("horizontal predictor for {color_type:?} is unsupported")
126        }
127        InconsistentBitsPerSample(bits_per_sample: Vec<u8>) {
128            display("inconsistent bits per sample: {bits_per_sample:?}")
129        }
130        InterpretationWithBits(interpretation: PhotometricInterpretation, bits_per_sample: Vec<u8>) {
131            display("Photometric interpretation {interpretation:?} with bits per sample {bits_per_sample:?} is unsupported")
132        }
133        UnknownInterpretation {
134            display("unknown photometric interpretation")
135        }
136        UnknownCompressionMethod {
137            display("unknown compression method")
138        }
139        UnsupportedCompressionMethod(method: CompressionMethod) {
140            display("compression method {method:?} is unsupported")
141        }
142        UnsupportedSampleDepth(depth: u8) {
143            display("{depth} samples per pixel is unsupported")
144        }
145        UnsupportedSampleFormat(sample_format: Vec<SampleFormat>) {
146            display("sample format {sample_format:?} is unsupported")
147        }
148        UnsupportedColorType(color_type: ColorType) {
149            display("color type {color_type:?} is unsupported")
150        }
151        UnsupportedBitsPerChannel(bits_per_channel: u8) {
152            display("{bits_per_channel} bits per channel not supported")
153        }
154        UnsupportedPlanarConfig(planar: Option<PlanarConfiguration>) {
155            display("unsupported planar configuration “{planar:?}”")
156        }
157        UnsupportedDataType {
158            display("unsupported data type.")
159        }
160        UnsupportedInterpretation(interpretation: PhotometricInterpretation) {
161            display("unsupported photometric interpretation \"{interpretation:?}\"")
162        }
163        ChromaSubsampling {
164            display("chroma subsampling of YCbCr color is unsupported")
165        }
166        MisalignedTileBoundaries {
167            display("tile rows are not aligned to byte boundaries")
168        }
169    }
170}
171
172quick_error! {
173    /// User attempted to use the Decoder in a way that is incompatible with a specific image.
174    ///
175    /// For example: attempting to read a tile from a stripped image.
176    #[derive(Debug)]
177    #[non_exhaustive]
178    pub enum UsageError {
179        InvalidChunkType(expected: ChunkType, actual: ChunkType) {
180            display("requested operation is only valid for images with chunk encoding of type {expected:?} but got {actual:?}")
181        }
182        InvalidChunkIndex(index: u32) {
183            display("invalid chunk index ({index}) requested")
184        }
185        InvalidPlaneIndex(index: u16) {
186            display("invalid plane index ({index}) requested")
187        }
188        InvalidCodingUnit(index: u32, have: u32) {
189            display("out of bounds coding unit ({index}) requested, only {have} available")
190        }
191        PredictorCompressionMismatch {
192            display("requested predictor is not compatible with the requested compression")
193        }
194        PredictorIncompatible {
195            display("the requested predictor is not compatible with the image's format")
196        }
197        PredictorUnavailable {
198            display("the requested predictor is not available")
199        }
200        InsufficientOutputBufferSize { needed: usize, provided: usize } {
201            display("the borrowed output buffer is not large enough for the decoded data, needed {needed} but have {provided}")
202        }
203        InsufficientOutputRowStride { needed: usize, requested: usize } {
204            display("the provided output row stride would alias rows of decoded data, needed {needed} but have {requested}")
205        }
206        ZeroIfdPointer {
207            display("the offset 0 can not point to a valid IFD")
208        }
209        ReconfiguredAfterImageWrite {
210            display("attempted to reconfigure the encoder after image writing has started")
211        }
212        ByteOrderMismatch {
213            display("attempted to use data with a byte order that does not match the required one")
214        }
215        MismatchedEntryLength {ty: Type, found: usize } {
216            display("the length of data is not a multiple of the size of the type {ty:?}, found {found}")
217        }
218    }
219}
220
221impl From<str::Utf8Error> for TiffError {
222    fn from(_err: str::Utf8Error) -> TiffError {
223        TiffError::FormatError(TiffFormatError::InvalidTag)
224    }
225}
226
227impl From<string::FromUtf8Error> for TiffError {
228    fn from(_err: string::FromUtf8Error) -> TiffError {
229        TiffError::FormatError(TiffFormatError::InvalidTag)
230    }
231}
232
233impl From<std::num::TryFromIntError> for TiffError {
234    fn from(_err: std::num::TryFromIntError) -> TiffError {
235        TiffError::IntSizeError
236    }
237}
238
239#[cfg(feature = "lzw")]
240impl From<weezl::LzwError> for TiffError {
241    fn from(err: weezl::LzwError) -> TiffError {
242        TiffError::FormatError(TiffFormatError::CompressedDataCorrupt(err.to_string()))
243    }
244}
245
246#[cfg(feature = "jpeg")]
247impl From<zune_jpeg::errors::DecodeErrors> for TiffError {
248    fn from(err: zune_jpeg::errors::DecodeErrors) -> Self {
249        TiffError::FormatError(TiffFormatError::CompressedDataCorrupt(err.to_string()))
250    }
251}
252
253/// Result of an image decoding/encoding process
254pub type TiffResult<T> = Result<T, TiffError>;