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}