Line | Count | Source |
1 | | //! Contains detailed error representation. |
2 | | //! |
3 | | //! See the main [`ImageError`] which contains a variant for each specialized error type. The |
4 | | //! subtypes used in each variant are opaque by design. They can be roughly inspected through their |
5 | | //! respective `kind` methods which work similar to `std::io::Error::kind`. |
6 | | //! |
7 | | //! The error interface makes it possible to inspect the error of an underlying decoder or encoder, |
8 | | //! through the `Error::source` method. Note that this is not part of the stable interface and you |
9 | | //! may not rely on a particular error value for a particular operation. This means mainly that |
10 | | //! `image` does not promise to remain on a particular version of its underlying decoders but if |
11 | | //! you ensure to use the same version of the dependency (or at least of the error type) through |
12 | | //! external means then you could inspect the error type in slightly more detail. |
13 | | |
14 | | use std::collections::TryReserveError; |
15 | | use std::error::Error; |
16 | | use std::{fmt, io}; |
17 | | |
18 | | use crate::color::ExtendedColorType; |
19 | | use crate::{metadata::Cicp, ImageFormat}; |
20 | | |
21 | | /// The generic error type for image operations. |
22 | | /// |
23 | | /// This high level enum allows, by variant matching, a rough separation of concerns between |
24 | | /// underlying IO, the caller, format specifications, and the `image` implementation. |
25 | | #[derive(Debug)] |
26 | | pub enum ImageError { |
27 | | /// An error was encountered while decoding. |
28 | | /// |
29 | | /// This means that the input data did not conform to the specification of some image format, |
30 | | /// or that no format could be determined, or that it did not match format specific |
31 | | /// requirements set by the caller. |
32 | | Decoding(DecodingError), |
33 | | |
34 | | /// An error was encountered while encoding. |
35 | | /// |
36 | | /// The input image can not be encoded with the chosen format, for example because the |
37 | | /// specification has no representation for its color space or because a necessary conversion |
38 | | /// is ambiguous. In some cases it might also happen that the dimensions can not be used with |
39 | | /// the format. |
40 | | Encoding(EncodingError), |
41 | | |
42 | | /// An error was encountered in input arguments. |
43 | | /// |
44 | | /// This is a catch-all case for strictly internal operations such as scaling, conversions, |
45 | | /// etc. that involve no external format specifications. |
46 | | Parameter(ParameterError), |
47 | | |
48 | | /// Completing the operation would have required more resources than allowed. |
49 | | /// |
50 | | /// Errors of this type are limits set by the user or environment, *not* inherent in a specific |
51 | | /// format or operation that was executed. |
52 | | Limits(LimitError), |
53 | | |
54 | | /// An operation can not be completed by the chosen abstraction. |
55 | | /// |
56 | | /// This means that it might be possible for the operation to succeed in general but |
57 | | /// * it requires a disabled feature, |
58 | | /// * the implementation does not yet exist, or |
59 | | /// * no abstraction for a lower level could be found. |
60 | | Unsupported(UnsupportedError), |
61 | | |
62 | | /// An error occurred while interacting with the environment. |
63 | | IoError(io::Error), |
64 | | } |
65 | | |
66 | | /// The implementation for an operation was not provided. |
67 | | /// |
68 | | /// This is used as an opaque representation for the [`ImageError::Unsupported`] variant. See its |
69 | | /// documentation for more information. |
70 | | #[derive(Debug)] |
71 | | pub struct UnsupportedError { |
72 | | format: ImageFormatHint, |
73 | | kind: UnsupportedErrorKind, |
74 | | } |
75 | | |
76 | | /// Details what feature is not supported. |
77 | | #[derive(Clone, Debug, Hash, PartialEq)] |
78 | | #[non_exhaustive] |
79 | | pub enum UnsupportedErrorKind { |
80 | | /// The required color type can not be handled. |
81 | | Color(ExtendedColorType), |
82 | | /// Dealing with an intricate layout is not implemented for an algorithm. |
83 | | ColorLayout(ExtendedColorType), |
84 | | /// The colors or transfer function of the CICP are not supported. |
85 | | ColorspaceCicp(Cicp), |
86 | | /// An image format is not supported. |
87 | | Format(ImageFormatHint), |
88 | | /// Some feature specified by string. |
89 | | /// This is discouraged and is likely to get deprecated (but not removed). |
90 | | GenericFeature(String), |
91 | | } |
92 | | |
93 | | /// An error was encountered while encoding an image. |
94 | | /// |
95 | | /// This is used as an opaque representation for the [`ImageError::Encoding`] variant. See its |
96 | | /// documentation for more information. |
97 | | #[derive(Debug)] |
98 | | pub struct EncodingError { |
99 | | format: ImageFormatHint, |
100 | | underlying: Option<Box<dyn Error + Send + Sync>>, |
101 | | } |
102 | | |
103 | | /// An error was encountered in inputs arguments. |
104 | | /// |
105 | | /// This is used as an opaque representation for the [`ImageError::Parameter`] variant. See its |
106 | | /// documentation for more information. |
107 | | #[derive(Debug)] |
108 | | pub struct ParameterError { |
109 | | kind: ParameterErrorKind, |
110 | | underlying: Option<Box<dyn Error + Send + Sync>>, |
111 | | } |
112 | | |
113 | | /// Details how a parameter is malformed. |
114 | | #[derive(Clone, Debug, Hash, PartialEq)] |
115 | | #[non_exhaustive] |
116 | | pub enum ParameterErrorKind { |
117 | | /// The dimensions passed are wrong. |
118 | | DimensionMismatch, |
119 | | /// Repeated an operation for which error that could not be cloned was emitted already. |
120 | | FailedAlready, |
121 | | /// The cicp is required to be RGB-like but had other matrix transforms or narrow range. |
122 | | RgbCicpRequired(Cicp), |
123 | | /// A string describing the parameter. |
124 | | /// This is discouraged and is likely to get deprecated (but not removed). |
125 | | Generic(String), |
126 | | /// The end of the image has been reached. |
127 | | NoMoreData, |
128 | | /// Passed a buffer not sized according to a layout. |
129 | | BufferSizeMismatch, |
130 | | /// An operation expected a concrete color space but another was found. |
131 | | CicpMismatch { |
132 | | /// The cicp that was expected. |
133 | | expected: Cicp, |
134 | | /// The cicp that was found. |
135 | | found: Cicp, |
136 | | }, |
137 | | /// The operation is only applicable to pixels with an alpha channel. |
138 | | NoAlphaChannel, |
139 | | /// The operation is only applicable to Luma pixels, which can be used as a mask. |
140 | | NotAValidMask(ExtendedColorType), |
141 | | } |
142 | | |
143 | | /// An error was encountered while decoding an image. |
144 | | /// |
145 | | /// This is used as an opaque representation for the [`ImageError::Decoding`] variant. See its |
146 | | /// documentation for more information. |
147 | | #[derive(Debug)] |
148 | | pub struct DecodingError { |
149 | | format: ImageFormatHint, |
150 | | underlying: Option<Box<dyn Error + Send + Sync>>, |
151 | | } |
152 | | |
153 | | /// Completing the operation would have required more resources than allowed. |
154 | | /// |
155 | | /// This is used as an opaque representation for the [`ImageError::Limits`] variant. See its |
156 | | /// documentation for more information. |
157 | | #[derive(Debug)] |
158 | | pub struct LimitError { |
159 | | kind: LimitErrorKind, |
160 | | // do we need an underlying error? |
161 | | } |
162 | | |
163 | | /// Indicates the limit that prevented an operation from completing. |
164 | | /// |
165 | | /// Note that this enumeration is not exhaustive and may in the future be extended to provide more |
166 | | /// detailed information or to incorporate other resources types. |
167 | | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
168 | | #[non_exhaustive] |
169 | | #[allow(missing_copy_implementations)] // Might be non-Copy in the future. |
170 | | pub enum LimitErrorKind { |
171 | | /// The resulting image exceed dimension limits in either direction. |
172 | | DimensionError, |
173 | | /// The operation would have performed an allocation larger than allowed. |
174 | | InsufficientMemory, |
175 | | /// The specified strict limits are not supported for this operation |
176 | | Unsupported { |
177 | | /// The given limits |
178 | | limits: crate::Limits, |
179 | | /// The supported strict limits |
180 | | supported: crate::LimitSupport, |
181 | | }, |
182 | | } |
183 | | |
184 | | /// A best effort representation for image formats. |
185 | | #[derive(Clone, Debug, Hash, PartialEq)] |
186 | | #[non_exhaustive] |
187 | | pub enum ImageFormatHint { |
188 | | /// The format is known exactly. |
189 | | Exact(ImageFormat), |
190 | | |
191 | | /// The format can be identified by a name. |
192 | | Name(String), |
193 | | |
194 | | /// A common path extension for the format is known. |
195 | | PathExtension(std::path::PathBuf), |
196 | | |
197 | | /// The format is not known or could not be determined. |
198 | | Unknown, |
199 | | } |
200 | | |
201 | | impl UnsupportedError { |
202 | | /// Create an `UnsupportedError` for an image with details on the unsupported feature. |
203 | | /// |
204 | | /// If the operation was not connected to a particular image format then the hint may be |
205 | | /// `Unknown`. |
206 | | #[must_use] |
207 | 1.18k | pub fn from_format_and_kind(format: ImageFormatHint, kind: UnsupportedErrorKind) -> Self { |
208 | 1.18k | UnsupportedError { format, kind } |
209 | 1.18k | } |
210 | | |
211 | | /// Returns the corresponding `UnsupportedErrorKind` of the error. |
212 | | #[must_use] |
213 | 0 | pub fn kind(&self) -> UnsupportedErrorKind { |
214 | 0 | self.kind.clone() |
215 | 0 | } |
216 | | |
217 | | /// Returns the image format associated with this error. |
218 | | #[must_use] |
219 | 0 | pub fn format_hint(&self) -> ImageFormatHint { |
220 | 0 | self.format.clone() |
221 | 0 | } |
222 | | } |
223 | | |
224 | | impl DecodingError { |
225 | | /// Create a `DecodingError` that stems from an arbitrary error of an underlying decoder. |
226 | 30.2k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { |
227 | 30.2k | DecodingError { |
228 | 30.2k | format, |
229 | 30.2k | underlying: Some(err.into()), |
230 | 30.2k | } |
231 | 30.2k | } <image::error::DecodingError>::new::<tiff::error::TiffError> Line | Count | Source | 226 | 3.13k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 3.13k | DecodingError { | 228 | 3.13k | format, | 229 | 3.13k | underlying: Some(err.into()), | 230 | 3.13k | } | 231 | 3.13k | } |
Unexecuted instantiation: <image::error::DecodingError>::new::<zune_jpeg::errors::DecodeErrors> <image::error::DecodingError>::new::<image_webp::decoder::DecodingError> Line | Count | Source | 226 | 4.86k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 4.86k | DecodingError { | 228 | 4.86k | format, | 229 | 4.86k | underlying: Some(err.into()), | 230 | 4.86k | } | 231 | 4.86k | } |
Unexecuted instantiation: <image::error::DecodingError>::new::<qoi::error::Error> <image::error::DecodingError>::new::<alloc::string::FromUtf8Error> Line | Count | Source | 226 | 12 | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 12 | DecodingError { | 228 | 12 | format, | 229 | 12 | underlying: Some(err.into()), | 230 | 12 | } | 231 | 12 | } |
Unexecuted instantiation: <image::error::DecodingError>::new::<alloc::string::String> <image::error::DecodingError>::new::<gif::reader::decoder::DecodingError> Line | Count | Source | 226 | 2.76k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 2.76k | DecodingError { | 228 | 2.76k | format, | 229 | 2.76k | underlying: Some(err.into()), | 230 | 2.76k | } | 231 | 2.76k | } |
<image::error::DecodingError>::new::<png::decoder::stream::DecodingError> Line | Count | Source | 226 | 4.34k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 4.34k | DecodingError { | 228 | 4.34k | format, | 229 | 4.34k | underlying: Some(err.into()), | 230 | 4.34k | } | 231 | 4.34k | } |
<image::error::DecodingError>::new::<image::codecs::bmp::decoder::DecoderError> Line | Count | Source | 226 | 394 | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 394 | DecodingError { | 228 | 394 | format, | 229 | 394 | underlying: Some(err.into()), | 230 | 394 | } | 231 | 394 | } |
<image::error::DecodingError>::new::<image::codecs::hdr::decoder::DecoderError> Line | Count | Source | 226 | 3.98k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 3.98k | DecodingError { | 228 | 3.98k | format, | 229 | 3.98k | underlying: Some(err.into()), | 230 | 3.98k | } | 231 | 3.98k | } |
<image::error::DecodingError>::new::<image::codecs::ico::decoder::DecoderError> Line | Count | Source | 226 | 8.93k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 8.93k | DecodingError { | 228 | 8.93k | format, | 229 | 8.93k | underlying: Some(err.into()), | 230 | 8.93k | } | 231 | 8.93k | } |
<image::error::DecodingError>::new::<image::codecs::pnm::decoder::DecoderError> Line | Count | Source | 226 | 1.51k | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 1.51k | DecodingError { | 228 | 1.51k | format, | 229 | 1.51k | underlying: Some(err.into()), | 230 | 1.51k | } | 231 | 1.51k | } |
Unexecuted instantiation: <image::error::DecodingError>::new::<<image::error::ImageError as core::convert::From<image::images::flat::Error>>::from::NormalFormRequiredError> <image::error::DecodingError>::new::<&str> Line | Count | Source | 226 | 277 | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { | 227 | 277 | DecodingError { | 228 | 277 | format, | 229 | 277 | underlying: Some(err.into()), | 230 | 277 | } | 231 | 277 | } |
|
232 | | |
233 | | /// Create a `DecodingError` for an image format. |
234 | | /// |
235 | | /// The error will not contain any further information but is very easy to create. |
236 | | #[must_use] |
237 | 0 | pub fn from_format_hint(format: ImageFormatHint) -> Self { |
238 | 0 | DecodingError { |
239 | 0 | format, |
240 | 0 | underlying: None, |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | /// Returns the image format associated with this error. |
245 | | #[must_use] |
246 | 0 | pub fn format_hint(&self) -> ImageFormatHint { |
247 | 0 | self.format.clone() |
248 | 0 | } |
249 | | } |
250 | | |
251 | | impl EncodingError { |
252 | | /// Create an `EncodingError` that stems from an arbitrary error of an underlying encoder. |
253 | 0 | pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self { |
254 | 0 | EncodingError { |
255 | 0 | format, |
256 | 0 | underlying: Some(err.into()), |
257 | 0 | } |
258 | 0 | } Unexecuted instantiation: <image::error::EncodingError>::new::<alloc::boxed::Box<png::encoder::EncodingError>> Unexecuted instantiation: <image::error::EncodingError>::new::<tiff::error::TiffError> Unexecuted instantiation: <image::error::EncodingError>::new::<gif::encoder::EncodingError> Unexecuted instantiation: <image::error::EncodingError>::new::<image_webp::encoder::EncodingError> Unexecuted instantiation: <image::error::EncodingError>::new::<qoi::error::Error> Unexecuted instantiation: <image::error::EncodingError>::new::<image::codecs::tga::encoder::EncoderError> Unexecuted instantiation: <image::error::EncodingError>::new::<image::codecs::jpeg::encoder::EncoderError> Unexecuted instantiation: <image::error::EncodingError>::new::<&str> Unexecuted instantiation: <image::error::EncodingError>::new::<jpeg_encoder::error::EncodingError> Unexecuted instantiation: <image::error::EncodingError>::new::<ravif::error::Error> |
259 | | |
260 | | /// Create an `EncodingError` for an image format. |
261 | | /// |
262 | | /// The error will not contain any further information but is very easy to create. |
263 | | #[must_use] |
264 | 0 | pub fn from_format_hint(format: ImageFormatHint) -> Self { |
265 | 0 | EncodingError { |
266 | 0 | format, |
267 | 0 | underlying: None, |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | | /// Return the image format associated with this error. |
272 | | #[must_use] |
273 | 0 | pub fn format_hint(&self) -> ImageFormatHint { |
274 | 0 | self.format.clone() |
275 | 0 | } |
276 | | } |
277 | | |
278 | | impl ParameterError { |
279 | | /// Construct a `ParameterError` directly from a corresponding kind. |
280 | | #[must_use] |
281 | 17 | pub fn from_kind(kind: ParameterErrorKind) -> Self { |
282 | 17 | ParameterError { |
283 | 17 | kind, |
284 | 17 | underlying: None, |
285 | 17 | } |
286 | 17 | } |
287 | | |
288 | | /// Returns the corresponding `ParameterErrorKind` of the error. |
289 | | #[must_use] |
290 | 0 | pub fn kind(&self) -> ParameterErrorKind { |
291 | 0 | self.kind.clone() |
292 | 0 | } |
293 | | } |
294 | | |
295 | | impl LimitError { |
296 | | /// Construct a generic `LimitError` directly from a corresponding kind. |
297 | | #[must_use] |
298 | 8.85k | pub fn from_kind(kind: LimitErrorKind) -> Self { |
299 | 8.85k | LimitError { kind } |
300 | 8.85k | } |
301 | | |
302 | | /// Returns the corresponding `LimitErrorKind` of the error. |
303 | | #[must_use] |
304 | 0 | pub fn kind(&self) -> LimitErrorKind { |
305 | 0 | self.kind.clone() |
306 | 0 | } |
307 | | } |
308 | | |
309 | | impl From<LimitErrorKind> for LimitError { |
310 | 0 | fn from(kind: LimitErrorKind) -> Self { |
311 | 0 | Self { kind } |
312 | 0 | } |
313 | | } |
314 | | |
315 | | impl From<io::Error> for ImageError { |
316 | 5.76k | fn from(err: io::Error) -> ImageError { |
317 | 5.76k | ImageError::IoError(err) |
318 | 5.76k | } |
319 | | } |
320 | | |
321 | | impl From<TryReserveError> for ImageError { |
322 | 0 | fn from(_: TryReserveError) -> ImageError { |
323 | 0 | ImageError::Limits(LimitErrorKind::InsufficientMemory.into()) |
324 | 0 | } |
325 | | } |
326 | | |
327 | | impl From<ImageFormat> for ImageFormatHint { |
328 | 31.3k | fn from(format: ImageFormat) -> Self { |
329 | 31.3k | ImageFormatHint::Exact(format) |
330 | 31.3k | } |
331 | | } |
332 | | |
333 | | impl From<&'_ std::path::Path> for ImageFormatHint { |
334 | 0 | fn from(path: &'_ std::path::Path) -> Self { |
335 | 0 | match path.extension() { |
336 | 0 | Some(ext) => ImageFormatHint::PathExtension(ext.into()), |
337 | 0 | None => ImageFormatHint::Unknown, |
338 | | } |
339 | 0 | } |
340 | | } |
341 | | |
342 | | impl From<ImageFormatHint> for UnsupportedError { |
343 | 0 | fn from(hint: ImageFormatHint) -> Self { |
344 | 0 | UnsupportedError { |
345 | 0 | format: hint.clone(), |
346 | 0 | kind: UnsupportedErrorKind::Format(hint), |
347 | 0 | } |
348 | 0 | } |
349 | | } |
350 | | |
351 | | /// Result of an image decoding/encoding process |
352 | | pub type ImageResult<T> = Result<T, ImageError>; |
353 | | |
354 | | impl fmt::Display for ImageError { |
355 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
356 | 0 | match self { |
357 | 0 | ImageError::IoError(err) => err.fmt(fmt), |
358 | 0 | ImageError::Decoding(err) => err.fmt(fmt), |
359 | 0 | ImageError::Encoding(err) => err.fmt(fmt), |
360 | 0 | ImageError::Parameter(err) => err.fmt(fmt), |
361 | 0 | ImageError::Limits(err) => err.fmt(fmt), |
362 | 0 | ImageError::Unsupported(err) => err.fmt(fmt), |
363 | | } |
364 | 0 | } |
365 | | } |
366 | | |
367 | | impl Error for ImageError { |
368 | 0 | fn source(&self) -> Option<&(dyn Error + 'static)> { |
369 | 0 | match self { |
370 | 0 | ImageError::IoError(err) => err.source(), |
371 | 0 | ImageError::Decoding(err) => err.source(), |
372 | 0 | ImageError::Encoding(err) => err.source(), |
373 | 0 | ImageError::Parameter(err) => err.source(), |
374 | 0 | ImageError::Limits(err) => err.source(), |
375 | 0 | ImageError::Unsupported(err) => err.source(), |
376 | | } |
377 | 0 | } |
378 | | } |
379 | | |
380 | | impl fmt::Display for UnsupportedError { |
381 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
382 | 0 | match &self.kind { |
383 | | UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => { |
384 | 0 | write!(fmt, "The image format could not be determined",) |
385 | | } |
386 | 0 | UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!( |
387 | 0 | fmt, |
388 | 0 | "The file extension {format} was not recognized as an image format", |
389 | | ), |
390 | 0 | UnsupportedErrorKind::Format(format) => { |
391 | 0 | write!(fmt, "The image format {format} is not supported",) |
392 | | } |
393 | 0 | UnsupportedErrorKind::Color(color) => write!( |
394 | 0 | fmt, |
395 | 0 | "The encoder or decoder for {} does not support the color type `{:?}`", |
396 | | self.format, color, |
397 | | ), |
398 | 0 | UnsupportedErrorKind::ColorLayout(layout) => write!( |
399 | 0 | fmt, |
400 | 0 | "Converting with the texel memory layout {layout:?} is not supported", |
401 | | ), |
402 | 0 | UnsupportedErrorKind::ColorspaceCicp(color) => write!( |
403 | 0 | fmt, |
404 | 0 | "The colorimetric interpretation of a CICP color space is not supported for `{color:?}`", |
405 | | ), |
406 | 0 | UnsupportedErrorKind::GenericFeature(message) => match &self.format { |
407 | 0 | ImageFormatHint::Unknown => write!( |
408 | 0 | fmt, |
409 | 0 | "The decoder does not support the format feature {message}", |
410 | | ), |
411 | 0 | other => write!( |
412 | 0 | fmt, |
413 | 0 | "The decoder for {other} does not support the format features {message}", |
414 | | ), |
415 | | }, |
416 | | } |
417 | 0 | } |
418 | | } |
419 | | |
420 | | impl Error for UnsupportedError {} |
421 | | |
422 | | impl fmt::Display for ParameterError { |
423 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
424 | 0 | match &self.kind { |
425 | 0 | ParameterErrorKind::DimensionMismatch => write!( |
426 | 0 | fmt, |
427 | 0 | "The Image's dimensions are either too \ |
428 | 0 | small or too large" |
429 | | ), |
430 | 0 | ParameterErrorKind::FailedAlready => write!( |
431 | 0 | fmt, |
432 | 0 | "The end the image stream has been reached due to a previous error" |
433 | | ), |
434 | 0 | ParameterErrorKind::RgbCicpRequired(cicp) => { |
435 | 0 | write!(fmt, "The CICP {cicp:?} can not be used for RGB images",) |
436 | | } |
437 | | |
438 | 0 | ParameterErrorKind::Generic(message) => { |
439 | 0 | write!(fmt, "The parameter is malformed: {message}",) |
440 | | } |
441 | 0 | ParameterErrorKind::NoMoreData => write!(fmt, "The end of the image has been reached",), |
442 | | ParameterErrorKind::BufferSizeMismatch => { |
443 | 0 | write!(fmt, "The buffer length is incorrect",) |
444 | | } |
445 | 0 | ParameterErrorKind::CicpMismatch { expected, found } => { |
446 | 0 | write!( |
447 | 0 | fmt, |
448 | 0 | "The color space {found:?} does not match the expected {expected:?}", |
449 | | ) |
450 | | } |
451 | | ParameterErrorKind::NoAlphaChannel => { |
452 | 0 | write!( |
453 | 0 | fmt, |
454 | 0 | "The operation requires an alpha channel but the pixel type does not have one", |
455 | | ) |
456 | | } |
457 | 0 | ParameterErrorKind::NotAValidMask(c) => { |
458 | 0 | write!( |
459 | 0 | fmt, |
460 | 0 | "The operation requires a luma image as a mask but the input has color {c:?}", |
461 | | ) |
462 | | } |
463 | 0 | }?; |
464 | | |
465 | 0 | if let Some(underlying) = &self.underlying { |
466 | 0 | write!(fmt, "\n{underlying}")?; |
467 | 0 | } |
468 | | |
469 | 0 | Ok(()) |
470 | 0 | } |
471 | | } |
472 | | |
473 | | impl Error for ParameterError { |
474 | 0 | fn source(&self) -> Option<&(dyn Error + 'static)> { |
475 | 0 | match &self.underlying { |
476 | 0 | None => None, |
477 | 0 | Some(source) => Some(&**source), |
478 | | } |
479 | 0 | } |
480 | | } |
481 | | |
482 | | impl fmt::Display for EncodingError { |
483 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
484 | 0 | match &self.underlying { |
485 | 0 | Some(underlying) => write!( |
486 | 0 | fmt, |
487 | 0 | "Format error encoding {}:\n{}", |
488 | | self.format, underlying, |
489 | | ), |
490 | 0 | None => write!(fmt, "Format error encoding {}", self.format,), |
491 | | } |
492 | 0 | } |
493 | | } |
494 | | |
495 | | impl Error for EncodingError { |
496 | 0 | fn source(&self) -> Option<&(dyn Error + 'static)> { |
497 | 0 | match &self.underlying { |
498 | 0 | None => None, |
499 | 0 | Some(source) => Some(&**source), |
500 | | } |
501 | 0 | } |
502 | | } |
503 | | |
504 | | impl fmt::Display for DecodingError { |
505 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
506 | 0 | match &self.underlying { |
507 | 0 | None => match self.format { |
508 | 0 | ImageFormatHint::Unknown => write!(fmt, "Format error"), |
509 | 0 | _ => write!(fmt, "Format error decoding {}", self.format), |
510 | | }, |
511 | 0 | Some(underlying) => { |
512 | 0 | write!(fmt, "Format error decoding {}: {}", self.format, underlying) |
513 | | } |
514 | | } |
515 | 0 | } |
516 | | } |
517 | | |
518 | | impl Error for DecodingError { |
519 | 0 | fn source(&self) -> Option<&(dyn Error + 'static)> { |
520 | 0 | match &self.underlying { |
521 | 0 | None => None, |
522 | 0 | Some(source) => Some(&**source), |
523 | | } |
524 | 0 | } |
525 | | } |
526 | | |
527 | | impl fmt::Display for LimitError { |
528 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
529 | 0 | match self.kind { |
530 | 0 | LimitErrorKind::InsufficientMemory => write!(fmt, "Memory limit exceeded"), |
531 | 0 | LimitErrorKind::DimensionError => write!(fmt, "Image size exceeds limit"), |
532 | | LimitErrorKind::Unsupported { .. } => { |
533 | 0 | write!(fmt, "The following strict limits are specified but not supported by the opertation: ")?; |
534 | 0 | Ok(()) |
535 | | } |
536 | | } |
537 | 0 | } |
538 | | } |
539 | | |
540 | | impl Error for LimitError {} |
541 | | |
542 | | impl fmt::Display for ImageFormatHint { |
543 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
544 | 0 | match self { |
545 | 0 | ImageFormatHint::Exact(format) => write!(fmt, "{format:?}"), |
546 | 0 | ImageFormatHint::Name(name) => write!(fmt, "`{name}`"), |
547 | 0 | ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{ext:?}`"), |
548 | 0 | ImageFormatHint::Unknown => write!(fmt, "`Unknown`"), |
549 | | } |
550 | 0 | } |
551 | | } |
552 | | |
553 | | /// Converting [`ExtendedColorType`] to [`ColorType`][`crate::ColorType`] failed. |
554 | | /// |
555 | | /// This type is convertible to [`ImageError`] as [`ImageError::Unsupported`]. |
556 | | #[derive(Clone)] |
557 | | #[allow(missing_copy_implementations)] |
558 | | pub struct TryFromExtendedColorError { |
559 | | pub(crate) was: ExtendedColorType, |
560 | | } |
561 | | |
562 | | impl fmt::Debug for TryFromExtendedColorError { |
563 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
564 | 0 | write!(f, "{}", self) |
565 | 0 | } |
566 | | } |
567 | | |
568 | | impl fmt::Display for TryFromExtendedColorError { |
569 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
570 | 0 | write!( |
571 | 0 | f, |
572 | 0 | "The pixel layout {:?} is not supported as a buffer ColorType", |
573 | | self.was |
574 | | ) |
575 | 0 | } |
576 | | } |
577 | | |
578 | | impl Error for TryFromExtendedColorError {} |
579 | | |
580 | | impl From<TryFromExtendedColorError> for ImageError { |
581 | 0 | fn from(err: TryFromExtendedColorError) -> ImageError { |
582 | 0 | ImageError::Unsupported(UnsupportedError::from_format_and_kind( |
583 | 0 | ImageFormatHint::Unknown, |
584 | 0 | UnsupportedErrorKind::Color(err.was), |
585 | 0 | )) |
586 | 0 | } |
587 | | } |
588 | | |
589 | | #[cfg(test)] |
590 | | mod tests { |
591 | | use super::*; |
592 | | use std::mem::size_of; |
593 | | |
594 | | #[allow(dead_code)] |
595 | | // This will fail to compile if the size of this type is large. |
596 | | const ASSERT_SMALLISH: usize = [0][(size_of::<ImageError>() >= 200) as usize]; |
597 | | |
598 | | #[test] |
599 | | fn test_send_sync_stability() { |
600 | | fn assert_send_sync<T: Send + Sync>() {} |
601 | | |
602 | | assert_send_sync::<ImageError>(); |
603 | | } |
604 | | } |