Coverage Report

Created: 2026-09-01 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/io/decoder.rs
Line
Count
Source
1
use crate::error::ImageResult;
2
use crate::io::DecoderPreparedImage;
3
use crate::metadata::{LoopCount, Orientation};
4
use crate::Delay;
5
6
/// The interface for `image` to utilize in reading image files.
7
///
8
/// Please carefully consider consuming this interface directly and prefer interaction with an
9
/// [`ImageReader`](crate::ImageReader). This is one directional of a protocol between `image` and format decoders. In
10
/// the general case, an implementation can expect calls to be made in the following order:
11
///
12
/// ```text,bnf
13
/// decoding sequence = configure, { decode image }, "finish", { metadata }
14
///
15
/// decode image =
16
///    "prepare_image", { metadata | "prepare_image" }, "read_image"
17
///
18
/// configure = "set_limits"
19
///
20
/// metadata = "xmp_metadata" | "icc_profile" | "exif_metadata" | "iptc_metadata"
21
/// ```
22
///
23
/// Deviation from this order can be treated as an error. Future changes to the protocol may
24
/// introduce additional methods. Decoders will indicate support for sequent variants in their
25
/// [`ImageDecoder::format_attributes`].
26
///
27
/// Metadata (`icc_profile`, `exif_metadata`, etc.) is handled different for different image
28
/// containers. The should apply to the previous image.
29
pub trait ImageDecoder {
30
    /// Set the decoder to have the specified limits. See [`Limits`] for the different kinds of
31
    /// limits that is possible to set.
32
    ///
33
    /// Note to implementors: make sure you call [`Limits::check_support`] so that
34
    /// decoding fails if any unsupported strict limits are set. Also make sure
35
    /// you call [`Limits::check_dimensions`] to check the `max_image_width` and
36
    /// `max_image_height` limits.
37
    ///
38
    /// **Note**: By default, _no_ limits are defined. This may be changed in future major version
39
    /// increases.
40
    ///
41
    /// [`Limits`]: crate::Limits
42
    /// [`Limits::check_support`]: crate::Limits::check_support
43
    /// [`Limits::check_dimensions`]: crate::Limits::check_dimensions
44
17.8k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
17.8k
        limits.check_support(&crate::LimitSupport::default())?;
46
17.8k
        let layout = self.prepare_image()?;
47
17.8k
        limits.check_layout_dimensions(&layout)?;
48
17.8k
        Ok(())
49
17.8k
    }
<image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
50
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
50
        limits.check_support(&crate::LimitSupport::default())?;
46
50
        let layout = self.prepare_image()?;
47
50
        limits.check_layout_dimensions(&layout)?;
48
50
        Ok(())
49
50
    }
<image::codecs::webp::decoder::WebPDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
8.83k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
8.83k
        limits.check_support(&crate::LimitSupport::default())?;
46
8.83k
        let layout = self.prepare_image()?;
47
8.83k
        limits.check_layout_dimensions(&layout)?;
48
8.83k
        Ok(())
49
8.83k
    }
<image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
1.32k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
1.32k
        limits.check_support(&crate::LimitSupport::default())?;
46
1.32k
        let layout = self.prepare_image()?;
47
1.32k
        limits.check_layout_dimensions(&layout)?;
48
1.32k
        Ok(())
49
1.32k
    }
<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
4.64k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
4.64k
        limits.check_support(&crate::LimitSupport::default())?;
46
4.64k
        let layout = self.prepare_image()?;
47
4.64k
        limits.check_layout_dimensions(&layout)?;
48
4.64k
        Ok(())
49
4.64k
    }
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
7
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
7
        limits.check_support(&crate::LimitSupport::default())?;
46
7
        let layout = self.prepare_image()?;
47
7
        limits.check_layout_dimensions(&layout)?;
48
7
        Ok(())
49
7
    }
<image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
2.86k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
2.86k
        limits.check_support(&crate::LimitSupport::default())?;
46
2.86k
        let layout = self.prepare_image()?;
47
2.86k
        limits.check_layout_dimensions(&layout)?;
48
2.86k
        Ok(())
49
2.86k
    }
<image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
44
98
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
45
98
        limits.check_support(&crate::LimitSupport::default())?;
46
98
        let layout = self.prepare_image()?;
47
98
        limits.check_layout_dimensions(&layout)?;
48
98
        Ok(())
49
98
    }
50
51
    /// Retrieve general information about the decoder / its format itself.
52
    ///
53
    /// This hints which methods should be called while decoding (a sequence of) images from this
54
    /// decoder, e.g. when metadata is available and when it will be overridden. It also provides
55
    /// basic capability information about the format. If, in the future, we added different basic
56
    /// methods of retrieving color data then the attributes would indicate the preferred and/or
57
    /// possible choices.
58
12.6k
    fn format_attributes(&self) -> FormatAttributes {
59
12.6k
        FormatAttributes::default()
60
12.6k
    }
<image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
2.21k
    fn format_attributes(&self) -> FormatAttributes {
59
2.21k
        FormatAttributes::default()
60
2.21k
    }
<image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
50
    fn format_attributes(&self) -> FormatAttributes {
59
50
        FormatAttributes::default()
60
50
    }
<image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
2.45k
    fn format_attributes(&self) -> FormatAttributes {
59
2.45k
        FormatAttributes::default()
60
2.45k
    }
<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
5.94k
    fn format_attributes(&self) -> FormatAttributes {
59
5.94k
        FormatAttributes::default()
60
5.94k
    }
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
<image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
17
    fn format_attributes(&self) -> FormatAttributes {
59
17
        FormatAttributes::default()
60
17
    }
<image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
58
2.01k
    fn format_attributes(&self) -> FormatAttributes {
59
2.01k
        FormatAttributes::default()
60
2.01k
    }
61
62
    /// Retrieve animation attributes.
63
    ///
64
    /// You should check [`FormatAttributes::supports_animation`] before calling this method. A
65
    /// value will only be available on animated images. Additionally, most file formats store the
66
    /// metadata in the header which might not be read until after calling
67
    /// [`ImageDecoder::prepare_image`].
68
    ///
69
    /// The value here is expected to remain constant when it is present.
70
0
    fn animation_attributes(&mut self) -> Option<DecodedAnimationAttributes> {
71
0
        None
72
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::tiff::TiffDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::jpeg::decoder::JpegDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::animation_attributes
73
74
    /// Consume the header of the image, determining the (next) image's layout.
75
    ///
76
    /// This shall be called before a call to [`ImageDecoder::read_image`] to ensure that the
77
    /// initial metadata has been read. The returned layout indicates the expected buffer of
78
    /// [`ImageDecoder::read_image`]. The caller is responsible for passing a buffer of the
79
    /// appropriate size.
80
    ///
81
    /// This method should be idempotent on success, calling it multiple times in a row should
82
    /// produce equivalent results. The decoder must _not_ advance to another image descriptor when
83
    /// it is called when it has already reached one.
84
    ///
85
    /// In contrast to a constructor it can be called multiple times, even after reconfiguring
86
    /// limits and context which avoids resource issues for formats that buffer metadata.
87
    fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage>;
88
89
    /// Read all the bytes in the image into a buffer.
90
    ///
91
    /// This function takes a slice of bytes and writes the pixel data of the image into it.
92
    /// `buf` must not be assumed to be aligned to any byte boundaries. However,
93
    /// alignment to 2 or 4 byte boundaries may result in small performance
94
    /// improvements for certain decoder implementations.
95
    ///
96
    /// The returned pixel data will always be in native endian. This allows
97
    /// `[u16]` and `[f32]` slices to be cast to `[u8]` and used for this method.
98
    ///
99
    /// # Panics
100
    ///
101
    /// This function should panic if `buf.len() != self.prepare_image().total_bytes()`.
102
    ///
103
    /// # Examples
104
    ///
105
    /// ```
106
    /// # use image::ImageDecoder;
107
    /// fn read_16bit_image(mut decoder: impl ImageDecoder) -> Vec<u16> {
108
    ///     let layout = decoder.prepare_image().unwrap();
109
    ///     let mut buf: Vec<u16> = vec![0; (layout.total_bytes() / 2) as usize];
110
    ///     decoder.read_image(bytemuck::cast_slice_mut(&mut buf)).unwrap();
111
    ///     buf
112
    /// }
113
    /// ```
114
    fn read_image(&mut self, buf: &mut [u8]) -> ImageResult<DecodedImageAttributes>;
115
116
    /// Returns the ICC color profile embedded in the image, or `Ok(None)` if the image does not have one.
117
    ///
118
    /// For formats that don't support embedded profiles this function should always return
119
    /// `Ok(None)`. Decoders for formats with non-standard color profiles may create a synthetic
120
    /// profile, see our [`bmp`](`crate::codecs::bmp`) module for an example.
121
    ///
122
    /// A decoder that encounters tags which contain a color profile whose encoding it does not
123
    /// support should return [`UnsupportedError`](`crate::error::UnsupportedError`). This allows a
124
    /// reader to continue while differentiating from missing metadata.
125
0
    fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
126
0
        Ok(None)
127
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::icc_profile
128
129
    /// Returns the raw [Exif](https://en.wikipedia.org/wiki/Exif) chunk, if it is present.
130
    /// A third-party crate such as [`kamadak-exif`](https://docs.rs/kamadak-exif/) is required to actually parse it.
131
    ///
132
    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
133
    ///
134
    /// A decoder that encounters tags which contain XMP metadata whose encoding it does not
135
    /// support should return [`UnsupportedError`](crate::error::UnsupportedError). This allows a
136
    /// reader to continue while differentiating from missing metadata.
137
0
    fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
138
0
        Ok(None)
139
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::gif::GifDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::exif_metadata
140
141
    /// Returns the raw [XMP](https://en.wikipedia.org/wiki/Extensible_Metadata_Platform) chunk, if it is present.
142
    /// A third-party crate such as [`roxmltree`](https://docs.rs/roxmltree/) is required to actually parse it.
143
    ///
144
    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
145
    ///
146
    /// A decoder that encounters tags which contain XMP metadata whose encoding it does not
147
    /// support should return [`UnsupportedError`](crate::error::UnsupportedError). This allows a
148
    /// reader to continue while differentiating from missing metadata.
149
0
    fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
150
0
        Ok(None)
151
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::xmp_metadata
152
153
    /// Returns the raw [IPTC](https://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model) chunk, if it is present.
154
    ///
155
    /// For formats that don't support embedded profiles this function should always return `Ok(None)`.
156
    ///
157
    /// A decoder that encounters tags which contain XMP metadata whose encoding it does not
158
    /// support should return [`UnsupportedError`](crate::error::UnsupportedError). This allows a
159
    /// reader to continue while differentiating from missing metadata.
160
0
    fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
161
0
        Ok(None)
162
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::webp::decoder::WebPDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::gif::GifDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::iptc_metadata
163
164
    /// Called to determine if there may be more images to decode.
165
    ///
166
    /// This ends the decoding loop early when it indicates `None`. Otherwise, termination can only
167
    /// be handled through errors. See also
168
    /// [`ImageReader::into_frames`](crate::ImageReader::into_frames).
169
0
    fn more_images(&self) -> SequenceControl {
170
0
        SequenceControl::MaybeMore
171
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::gif::GifDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::jpeg::decoder::JpegDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::more_images
172
173
    /// Consume the rest of the file, including any trailer.
174
0
    fn finish(&mut self) -> ImageResult<()> {
175
0
        Ok(())
176
0
    }
Unexecuted instantiation: <image::codecs::hdr::decoder::HdrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::qoi::QoiDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::webp::decoder::WebPDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::tiff::TiffDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::pnm::decoder::PnmDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::gif::GifDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::jpeg::decoder::JpegDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
Unexecuted instantiation: <image::codecs::openexr::OpenExrDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::finish
177
}
178
179
/// Information meant to steer the protocol usage with the decoder.
180
#[derive(Clone, Debug, Default)]
181
#[non_exhaustive]
182
pub struct FormatAttributes {
183
    /// Could there be multiple images in this file that form an animation?
184
    pub supports_animation: bool,
185
    /// Could there be multiple images in this file, as an unrelated sequence?
186
    pub supports_sequence: bool,
187
    /// When should ICC profiles be retrieved.
188
    pub icc: DecodedMetadataHint,
189
    /// A hint for polling EXIF metadata.
190
    pub exif: DecodedMetadataHint,
191
    /// A hint for polling XMP metadata.
192
    pub xmp: DecodedMetadataHint,
193
    /// A hint for polling IPTC metadata.
194
    pub iptc: DecodedMetadataHint,
195
}
196
197
/// Additional attributes of animated image sequences.
198
#[derive(Clone, Debug)]
199
#[non_exhaustive]
200
pub struct DecodedAnimationAttributes {
201
    /// Loop count of the animated image.
202
    pub loop_count: LoopCount,
203
}
204
205
impl Default for DecodedAnimationAttributes {
206
0
    fn default() -> Self {
207
0
        Self {
208
0
            loop_count: LoopCount::Infinite,
209
0
        }
210
0
    }
211
}
212
213
/// Additional attributes of an image available after decoding.
214
///
215
/// The [`Default`] is implemented and returns a value suitable for very basic images from formats
216
/// that contain only one raster graphic.
217
#[derive(Clone, Debug, Default)]
218
#[non_exhaustive]
219
pub struct DecodedImageAttributes {
220
    /// The x-coordinate of the top-left rectangle of the image relative to canvas indicated by the
221
    /// sequence of frames.
222
    pub x: u32,
223
    /// The y-coordinate of the top-left rectangle of the image relative to canvas indicated by the
224
    /// sequence of frames.
225
    pub y: u32,
226
    /// A suggested presentation offset relative to the previous image.
227
    pub delay: Option<Delay>,
228
    /// Orientation of the image, not relayed through EXIF metadata.
229
    pub orientation: Option<Orientation>,
230
    /// Is the underlying data converted into a different pixel format or color model?
231
    ///
232
    /// This field is currently an optional hint for encoding. The authoritative source for the
233
    /// memory size required for [`ImageDecoder::read_image`][`crate::ImageDecoder`] remains the
234
    /// [`color`][`crate::ImageLayout::color`] field, you do not need to time travel this
235
    /// information.
236
    pub original_color_type: Option<crate::ExtendedColorType>,
237
}
238
239
/// A hint when metadata corresponding to the image is decoded.
240
///
241
/// Note that while this is a hint, different variants give contradictory indication on when they
242
/// should be polled. When a metadatum is tagged as [`DecodedMetadataHint::PerImage`] it MUST be
243
/// polled after each image to ensure all are retrieved, iterating to the next image without
244
/// polling MAY reset and skip some metadata.
245
///
246
/// # Design consideration
247
///
248
/// Each variant describes a way to fetch accurate and complete metadata for an individual image in
249
/// a file. This offloads some responsibility to the decoder, streamed formats that may contain
250
/// parts after the file need to be peek forwards to aggregate all metadata and then seek
251
/// backwards. During design we had a sequence that relied on [`ImageDecoder::finish`] but that did
252
/// not allow the reader to ensure all data was present. This call would also be destructive with
253
/// regards to the other kind of metadata.
254
#[derive(Clone, Debug, Default)]
255
#[non_exhaustive]
256
pub enum DecodedMetadataHint {
257
    /// The decoder does not support this datum. It will return `None` but there is no guarantee
258
    /// that the datum is truly absent in the file.
259
    ///
260
    /// This is the default.
261
    #[default]
262
    Unsupported,
263
    /// Metadata is available in the header and will be valid after the first call to
264
    /// [`ImageDecoder::prepare_image`] and will remain valid for all subsequent images.
265
    InHeader,
266
    /// Metadata exists for each image in this file, it must be retrieved between peeking the
267
    /// layout and reading the image.
268
    PerImage,
269
    /// There's no metadata of this type, the decoder would return `None` or an error.
270
    None,
271
}
272
273
/// Indicate if there may be more images to decode.
274
///
275
/// More concrete indications may be added in the future.
276
#[non_exhaustive]
277
#[derive(Default)]
278
pub enum SequenceControl {
279
    /// The format can not certainly say if there are more images. The caller should try to decode
280
    /// more images until an error occurs (specifically
281
    /// [`ParameterErrorKind::NoMoreData`](crate::error::ParameterErrorKind::NoMoreData)).
282
    #[default]
283
    MaybeMore,
284
    /// The decoder is sure that no more images are present.
285
    ///
286
    /// Further attempts to decode images should not be made, but no strong guarantee is made about
287
    /// returning an error in these cases. In particular, further attempts may further read the
288
    /// image file and check for errors in trailing data.
289
    None,
290
}
291
292
#[deny(clippy::missing_trait_methods)]
293
impl<T: ?Sized + ImageDecoder> ImageDecoder for Box<T> {
294
57.0k
    fn format_attributes(&self) -> FormatAttributes {
295
57.0k
        (**self).format_attributes()
296
57.0k
    }
<alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
294
53.4k
    fn format_attributes(&self) -> FormatAttributes {
295
53.4k
        (**self).format_attributes()
296
53.4k
    }
<alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::format_attributes
Line
Count
Source
294
3.61k
    fn format_attributes(&self) -> FormatAttributes {
295
3.61k
        (**self).format_attributes()
296
3.61k
    }
297
73.1k
    fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage> {
298
73.1k
        (**self).prepare_image()
299
73.1k
    }
<alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::prepare_image
Line
Count
Source
297
60.2k
    fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage> {
298
60.2k
        (**self).prepare_image()
299
60.2k
    }
<alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::prepare_image
Line
Count
Source
297
12.8k
    fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage> {
298
12.8k
        (**self).prepare_image()
299
12.8k
    }
300
0
    fn animation_attributes(&mut self) -> Option<DecodedAnimationAttributes> {
301
0
        (**self).animation_attributes()
302
0
    }
Unexecuted instantiation: <alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::animation_attributes
Unexecuted instantiation: <alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::animation_attributes
303
3.45k
    fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
304
3.45k
        (**self).icc_profile()
305
3.45k
    }
306
3.45k
    fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
307
3.45k
        (**self).exif_metadata()
308
3.45k
    }
309
3.45k
    fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
310
3.45k
        (**self).xmp_metadata()
311
3.45k
    }
312
3.45k
    fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
313
3.45k
        (**self).iptc_metadata()
314
3.45k
    }
315
3.33k
    fn read_image(&mut self, buf: &mut [u8]) -> ImageResult<DecodedImageAttributes> {
316
3.33k
        (**self).read_image(buf)
317
3.33k
    }
Unexecuted instantiation: <alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::read_image
<alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::read_image
Line
Count
Source
315
3.33k
    fn read_image(&mut self, buf: &mut [u8]) -> ImageResult<DecodedImageAttributes> {
316
3.33k
        (**self).read_image(buf)
317
3.33k
    }
318
69.9k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
319
69.9k
        (**self).set_limits(limits)
320
69.9k
    }
<alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
318
63.8k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
319
63.8k
        (**self).set_limits(limits)
320
63.8k
    }
<alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::set_limits
Line
Count
Source
318
6.16k
    fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
319
6.16k
        (**self).set_limits(limits)
320
6.16k
    }
321
0
    fn more_images(&self) -> SequenceControl {
322
0
        (**self).more_images()
323
0
    }
Unexecuted instantiation: <alloc::boxed::Box<dyn image::io::decoder::ImageDecoder> as image::io::decoder::ImageDecoder>::more_images
Unexecuted instantiation: <alloc::boxed::Box<image::codecs::png::PngDecoder<std::io::cursor::Cursor<&[u8]>>> as image::io::decoder::ImageDecoder>::more_images
324
0
    fn finish(&mut self) -> ImageResult<()> {
325
0
        (**self).finish()
326
0
    }
327
}
328
329
#[cfg(test)]
330
mod tests {
331
    use super::{DecodedImageAttributes, DecoderPreparedImage, ImageDecoder, ImageResult};
332
    use crate::ColorType;
333
334
    #[test]
335
    fn total_bytes_overflow() {
336
        struct D;
337
338
        impl ImageDecoder for D {
339
            fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage> {
340
                Ok(DecoderPreparedImage::new(
341
                    0xffff_ffff,
342
                    0xffff_ffff,
343
                    ColorType::Rgb8,
344
                ))
345
            }
346
347
            fn read_image(&mut self, _buf: &mut [u8]) -> ImageResult<DecodedImageAttributes> {
348
                unreachable!("Must not be called in this test")
349
            }
350
        }
351
352
        assert_eq!(D.prepare_image().unwrap().total_bytes(), u64::MAX);
353
        let v = crate::DynamicImage::from_decoder(D);
354
        assert!(v.is_err());
355
    }
356
}