image/io/
decoder.rs

1use crate::animation::Frames;
2use crate::color::{ColorType, ExtendedColorType};
3use crate::error::ImageResult;
4use crate::metadata::Orientation;
5
6/// The trait that all decoders implement
7pub trait ImageDecoder {
8    /// Returns a tuple containing the width and height of the image
9    fn dimensions(&self) -> (u32, u32);
10
11    /// Returns the color type of the image data produced by this decoder
12    fn color_type(&self) -> ColorType;
13
14    /// Returns the color type of the image file before decoding
15    fn original_color_type(&self) -> ExtendedColorType {
16        self.color_type().into()
17    }
18
19    /// Returns the ICC color profile embedded in the image, or `Ok(None)` if the image does not have one.
20    ///
21    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
22    fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
23        Ok(None)
24    }
25
26    /// Returns the raw [Exif](https://en.wikipedia.org/wiki/Exif) chunk, if it is present.
27    /// A third-party crate such as [`kamadak-exif`](https://docs.rs/kamadak-exif/) is required to actually parse it.
28    ///
29    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
30    fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
31        Ok(None)
32    }
33
34    /// Returns the raw [XMP](https://en.wikipedia.org/wiki/Extensible_Metadata_Platform) chunk, if it is present.
35    /// A third-party crate such as [`roxmltree`](https://docs.rs/roxmltree/) is required to actually parse it.
36    ///
37    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
38    fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
39        Ok(None)
40    }
41
42    /// Returns the raw [IPTC](https://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model) chunk, if it is present.
43    ///
44    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
45    fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
46        Ok(None)
47    }
48
49    /// Returns the orientation of the image.
50    ///
51    /// This is usually obtained from the Exif metadata, if present. Formats that don't support
52    /// indicating orientation in their image metadata will return `Ok(Orientation::NoTransforms)`.
53    fn orientation(&mut self) -> ImageResult<Orientation> {
54        Ok(self
55            .exif_metadata()?
56            .and_then(|chunk| Orientation::from_exif_chunk(&chunk))
57            .unwrap_or(Orientation::NoTransforms))
58    }
59
60    /// Returns the total number of bytes in the decoded image.
61    ///
62    /// This is the size of the buffer that must be passed to `read_image` or
63    /// `read_image_with_progress`. The returned value may exceed `usize::MAX`, in
64    /// which case it isn't actually possible to construct a buffer to decode all the image data
65    /// into. If, however, the size does not fit in a u64 then `u64::MAX` is returned.
66    fn total_bytes(&self) -> u64 {
67        let dimensions = self.dimensions();
68        let total_pixels = u64::from(dimensions.0) * u64::from(dimensions.1);
69        let bytes_per_pixel = u64::from(self.color_type().bytes_per_pixel());
70        total_pixels.saturating_mul(bytes_per_pixel)
71    }
72
73    /// Returns all the bytes in the image.
74    ///
75    /// This function takes a slice of bytes and writes the pixel data of the image into it.
76    /// `buf` does not need to be aligned to any byte boundaries. However,
77    /// alignment to 2 or 4 byte boundaries may result in small performance
78    /// improvements for certain decoder implementations.
79    ///
80    /// The returned pixel data will always be in native endian. This allows
81    /// `[u16]` and `[f32]` slices to be cast to `[u8]` and used for this method.
82    ///
83    /// # Panics
84    ///
85    /// This function panics if `buf.len() != self.total_bytes()`.
86    ///
87    /// # Examples
88    ///
89    /// ```
90    /// # use image::ImageDecoder;
91    /// fn read_16bit_image(decoder: impl ImageDecoder) -> Vec<u16> {
92    ///     let mut buf: Vec<u16> = vec![0; (decoder.total_bytes() / 2) as usize];
93    ///     decoder.read_image(bytemuck::cast_slice_mut(&mut buf));
94    ///     buf
95    /// }
96    /// ```
97    fn read_image(self, buf: &mut [u8]) -> ImageResult<()>
98    where
99        Self: Sized;
100
101    /// Set the decoder to have the specified limits. See [`Limits`] for the different kinds of
102    /// limits that is possible to set.
103    ///
104    /// Note to implementors: make sure you call [`Limits::check_support`] so that
105    /// decoding fails if any unsupported strict limits are set. Also make sure
106    /// you call [`Limits::check_dimensions`] to check the `max_image_width` and
107    /// `max_image_height` limits.
108    ///
109    /// **Note**: By default, _no_ limits are defined. This may be changed in future major version
110    /// increases.
111    ///
112    /// [`Limits`]: ./io/struct.Limits.html
113    /// [`Limits::check_support`]: ./io/struct.Limits.html#method.check_support
114    /// [`Limits::check_dimensions`]: ./io/struct.Limits.html#method.check_dimensions
115    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
116        limits.check_support(&crate::LimitSupport::default())?;
117        let (width, height) = self.dimensions();
118        limits.check_dimensions(width, height)?;
119        Ok(())
120    }
121
122    /// Use `read_image` instead; this method is an implementation detail needed so the trait can
123    /// be object safe.
124    ///
125    /// Note to implementors: This method should be implemented by calling `read_image` on
126    /// the boxed decoder...
127    /// ```ignore
128    /// fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
129    ///     (*self).read_image(buf)
130    /// }
131    /// ```
132    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()>;
133}
134
135#[deny(clippy::missing_trait_methods)]
136impl<T: ?Sized + ImageDecoder> ImageDecoder for Box<T> {
137    fn dimensions(&self) -> (u32, u32) {
138        (**self).dimensions()
139    }
140    fn color_type(&self) -> ColorType {
141        (**self).color_type()
142    }
143    fn original_color_type(&self) -> ExtendedColorType {
144        (**self).original_color_type()
145    }
146    fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
147        (**self).icc_profile()
148    }
149    fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
150        (**self).exif_metadata()
151    }
152    fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
153        (**self).xmp_metadata()
154    }
155    fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
156        (**self).iptc_metadata()
157    }
158    fn orientation(&mut self) -> ImageResult<Orientation> {
159        (**self).orientation()
160    }
161    fn total_bytes(&self) -> u64 {
162        (**self).total_bytes()
163    }
164    fn read_image(self, buf: &mut [u8]) -> ImageResult<()>
165    where
166        Self: Sized,
167    {
168        T::read_image_boxed(self, buf)
169    }
170    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
171        T::read_image_boxed(*self, buf)
172    }
173    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
174        (**self).set_limits(limits)
175    }
176}
177
178/// Specialized image decoding not be supported by all formats
179pub trait ImageDecoderRect: ImageDecoder {
180    /// Decode a rectangular section of the image.
181    ///
182    /// This function takes a slice of bytes and writes the pixel data of the image into it.
183    /// The rectangle is specified by the x and y coordinates of the top left corner, the width
184    /// and height of the rectangle, and the row pitch of the buffer. The row pitch is the number
185    /// of bytes between the start of one row and the start of the next row. The row pitch must be
186    /// at least as large as the width of the rectangle in bytes.
187    fn read_rect(
188        &mut self,
189        x: u32,
190        y: u32,
191        width: u32,
192        height: u32,
193        buf: &mut [u8],
194        row_pitch: usize,
195    ) -> ImageResult<()>;
196}
197
198/// `AnimationDecoder` trait
199pub trait AnimationDecoder<'a> {
200    /// Consume the decoder producing a series of frames.
201    fn into_frames(self) -> Frames<'a>;
202}
203
204#[cfg(test)]
205mod tests {
206    use super::{ColorType, ImageDecoder, ImageResult};
207
208    #[test]
209    fn total_bytes_overflow() {
210        struct D;
211        impl ImageDecoder for D {
212            fn color_type(&self) -> ColorType {
213                ColorType::Rgb8
214            }
215            fn dimensions(&self) -> (u32, u32) {
216                (0xffff_ffff, 0xffff_ffff)
217            }
218            fn read_image(self, _buf: &mut [u8]) -> ImageResult<()> {
219                unimplemented!()
220            }
221            fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
222                (*self).read_image(buf)
223            }
224        }
225        assert_eq!(D.total_bytes(), u64::MAX);
226
227        let v: ImageResult<Vec<u8>> = crate::io::free_functions::decoder_to_vec(D);
228        assert!(v.is_err());
229    }
230}