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 #[derive(Debug)]
17 pub enum TiffError {
18 FormatError(err: TiffFormatError) {
20 display("format error: {err}")
21 from()
22 source(err)
23 }
24 UnsupportedError(err: TiffUnsupportedError) {
26 display("unsupported error: {err}")
27 from()
28 source(err)
29 }
30 IoError(err: io::Error) {
32 display("{err}")
33 from()
34 source(err)
35 }
36 LimitsExceeded {
38 display("decoder limits exceeded")
39 }
40 IntSizeError {
42 display("platform or format size limits exceeded")
43 }
44 UsageError(err: UsageError) {
46 display("usage error: {err}")
47 from()
48 source(err)
49 }
50 }
51}
52
53quick_error! {
54 #[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 #[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 #[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
253pub type TiffResult<T> = Result<T, TiffError>;