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