| 1 | use std::error::Error; |
| 2 | use std::fmt; |
| 3 | use std::fmt::Display; |
| 4 | use std::io; |
| 5 | use std::str; |
| 6 | use std::string; |
| 7 | use std::sync::Arc; |
| 8 | |
| 9 | use jpeg::UnsupportedFeature; |
| 10 | |
| 11 | use crate::decoder::{ifd::Value, ChunkType}; |
| 12 | use crate::tags::{ |
| 13 | CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag, |
| 14 | }; |
| 15 | use crate::ColorType; |
| 16 | |
| 17 | use crate::weezl::LzwError; |
| 18 | |
| 19 | /// Tiff error kinds. |
| 20 | #[derive (Debug)] |
| 21 | pub 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 ] |
| 51 | pub 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 | |
| 81 | impl 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 ] |
| 148 | pub 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 | |
| 166 | impl 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)] |
| 230 | pub enum UsageError { |
| 231 | InvalidChunkType(ChunkType, ChunkType), |
| 232 | InvalidChunkIndex(u32), |
| 233 | } |
| 234 | |
| 235 | impl 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 | |
| 251 | impl 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 | |
| 269 | impl 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 | |
| 289 | impl From<io::Error> for TiffError { |
| 290 | fn from(err: io::Error) -> TiffError { |
| 291 | TiffError::IoError(err) |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | impl From<str::Utf8Error> for TiffError { |
| 296 | fn from(_err: str::Utf8Error) -> TiffError { |
| 297 | TiffError::FormatError(TiffFormatError::InvalidTag) |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | impl From<string::FromUtf8Error> for TiffError { |
| 302 | fn from(_err: string::FromUtf8Error) -> TiffError { |
| 303 | TiffError::FormatError(TiffFormatError::InvalidTag) |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | impl From<TiffFormatError> for TiffError { |
| 308 | fn from(err: TiffFormatError) -> TiffError { |
| 309 | TiffError::FormatError(err) |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | impl From<TiffUnsupportedError> for TiffError { |
| 314 | fn from(err: TiffUnsupportedError) -> TiffError { |
| 315 | TiffError::UnsupportedError(err) |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | impl From<UsageError> for TiffError { |
| 320 | fn from(err: UsageError) -> TiffError { |
| 321 | TiffError::UsageError(err) |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | impl From<std::num::TryFromIntError> for TiffError { |
| 326 | fn from(_err: std::num::TryFromIntError) -> TiffError { |
| 327 | TiffError::IntSizeError |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | impl 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)] |
| 342 | pub struct JpegDecoderError { |
| 343 | inner: Arc<jpeg::Error>, |
| 344 | } |
| 345 | |
| 346 | impl JpegDecoderError { |
| 347 | fn new(error: jpeg::Error) -> Self { |
| 348 | Self { |
| 349 | inner: Arc::new(data:error), |
| 350 | } |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | impl PartialEq for JpegDecoderError { |
| 355 | fn eq(&self, other: &Self) -> bool { |
| 356 | Arc::ptr_eq(&self.inner, &other.inner) |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | impl Display for JpegDecoderError { |
| 361 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 362 | self.inner.fmt(f) |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | impl From<JpegDecoderError> for TiffError { |
| 367 | fn from(error: JpegDecoderError) -> Self { |
| 368 | TiffError::FormatError(TiffFormatError::JpegDecoder(error)) |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | impl 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 |
| 379 | pub type TiffResult<T> = Result<T, TiffError>; |
| 380 | |