Coverage Report

Created: 2026-01-09 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/io/encoder.rs
Line
Count
Source
1
use crate::error::{ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind};
2
use crate::{ColorType, DynamicImage, ExtendedColorType};
3
4
/// Nominally public but DO NOT expose this type.
5
///
6
/// To be somewhat sure here's a compile fail test:
7
///
8
/// ```compile_fail
9
/// use image::MethodSealedToImage;
10
/// ```
11
///
12
/// ```compile_fail
13
/// use image::io::MethodSealedToImage;
14
/// ```
15
///
16
/// The same implementation strategy for a partially public trait is used in the standard library,
17
/// for the different effect of forbidding `Error::type_id` overrides thus making them reliable for
18
/// their calls through the `dyn` version of the trait.
19
///
20
/// Read more: <https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/>
21
#[derive(Clone, Copy)]
22
pub struct MethodSealedToImage;
23
24
/// The trait all encoders implement
25
pub trait ImageEncoder {
26
    /// Writes all the bytes in an image to the encoder.
27
    ///
28
    /// This function takes a slice of bytes of the pixel data of the image and encodes them. Just
29
    /// like for [`ImageDecoder::read_image`](crate::ImageDecoder), no particular alignment is
30
    /// required and data is expected to be in native endian. The implementation will reorder the
31
    /// endianness as necessary for the target encoding format.
32
    ///
33
    /// # Panics
34
    ///
35
    /// Panics if `width * height * color_type.bytes_per_pixel() != buf.len()`.
36
    fn write_image(
37
        self,
38
        buf: &[u8],
39
        width: u32,
40
        height: u32,
41
        color_type: ExtendedColorType,
42
    ) -> ImageResult<()>;
43
44
    /// Set the ICC profile to use for the image.
45
    ///
46
    /// This function is a no-op for formats that don't support ICC profiles.
47
    /// For formats that do support ICC profiles, the profile will be embedded
48
    /// in the image when it is saved.
49
    ///
50
    /// # Errors
51
    ///
52
    /// This function returns an error if the format does not support ICC profiles.
53
0
    fn set_icc_profile(&mut self, icc_profile: Vec<u8>) -> Result<(), UnsupportedError> {
54
0
        let _ = icc_profile;
55
0
        Err(UnsupportedError::from_format_and_kind(
56
0
            ImageFormatHint::Unknown,
57
0
            UnsupportedErrorKind::GenericFeature(
58
0
                "ICC profiles are not supported for this format".into(),
59
0
            ),
60
0
        ))
61
0
    }
Unexecuted instantiation: <_ as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::avif::encoder::AvifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::tiff::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::qoi::QoiEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::bmp::encoder::BmpEncoder<std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::hdr::encoder::HdrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::ico::encoder::IcoEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::gif::GifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::openexr::OpenExrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::tga::encoder::TgaEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
Unexecuted instantiation: <image::codecs::pnm::encoder::PnmEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_icc_profile
62
63
    /// Set the EXIF metadata to use for the image.
64
    ///
65
    /// This function is a no-op for formats that don't support EXIF metadata.
66
    /// For formats that do support EXIF metadata, the metadata will be embedded
67
    /// in the image when it is saved.
68
    ///
69
    /// # Errors
70
    ///
71
    /// This function returns an error if the format does not support EXIF metadata or if the
72
    /// encoder doesn't implement saving EXIF metadata yet.
73
0
    fn set_exif_metadata(&mut self, exif: Vec<u8>) -> Result<(), UnsupportedError> {
74
0
        let _ = exif;
75
0
        Err(UnsupportedError::from_format_and_kind(
76
0
            ImageFormatHint::Unknown,
77
0
            UnsupportedErrorKind::GenericFeature(
78
0
                "EXIF metadata is not supported for this format".into(),
79
0
            ),
80
0
        ))
81
0
    }
Unexecuted instantiation: <_ as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::avif::encoder::AvifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::tiff::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::qoi::QoiEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::bmp::encoder::BmpEncoder<std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::hdr::encoder::HdrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::ico::encoder::IcoEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::gif::GifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::openexr::OpenExrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::tga::encoder::TgaEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
Unexecuted instantiation: <image::codecs::pnm::encoder::PnmEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::set_exif_metadata
82
83
    /// Convert the image to a compatible format for the encoder. This is used by the encoding
84
    /// methods on `DynamicImage`.
85
    ///
86
    /// Note that this is method is sealed to the crate and effectively pub(crate) due to the
87
    /// argument type not being nameable.
88
    #[doc(hidden)]
89
0
    fn make_compatible_img(
90
0
        &self,
91
0
        _: MethodSealedToImage,
92
0
        _input: &DynamicImage,
93
0
    ) -> Option<DynamicImage> {
94
0
        None
95
0
    }
Unexecuted instantiation: <_ as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::avif::encoder::AvifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::tiff::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::qoi::QoiEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::png::PngEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::hdr::encoder::HdrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::ico::encoder::IcoEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::gif::GifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::openexr::OpenExrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
Unexecuted instantiation: <image::codecs::pnm::encoder::PnmEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoder>::make_compatible_img
96
}
97
98
pub(crate) trait ImageEncoderBoxed: ImageEncoder {
99
    fn write_image(
100
        self: Box<Self>,
101
        buf: &'_ [u8],
102
        width: u32,
103
        height: u32,
104
        color: ExtendedColorType,
105
    ) -> ImageResult<()>;
106
}
107
impl<T: ImageEncoder> ImageEncoderBoxed for T {
108
1.83k
    fn write_image(
109
1.83k
        self: Box<Self>,
110
1.83k
        buf: &'_ [u8],
111
1.83k
        width: u32,
112
1.83k
        height: u32,
113
1.83k
        color: ExtendedColorType,
114
1.83k
    ) -> ImageResult<()> {
115
1.83k
        (*self).write_image(buf, width, height, color)
116
1.83k
    }
Unexecuted instantiation: <_ as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::avif::encoder::AvifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::farbfeld::FarbfeldEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::tiff::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::qoi::QoiEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::png::PngEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::jpeg::encoder::JpegEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::bmp::encoder::BmpEncoder<std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::hdr::encoder::HdrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::ico::encoder::IcoEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::gif::GifEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::openexr::OpenExrEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Unexecuted instantiation: <image::codecs::tga::encoder::TgaEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
<image::codecs::webp::encoder::WebPEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
Line
Count
Source
108
1.83k
    fn write_image(
109
1.83k
        self: Box<Self>,
110
1.83k
        buf: &'_ [u8],
111
1.83k
        width: u32,
112
1.83k
        height: u32,
113
1.83k
        color: ExtendedColorType,
114
1.83k
    ) -> ImageResult<()> {
115
1.83k
        (*self).write_image(buf, width, height, color)
116
1.83k
    }
Unexecuted instantiation: <image::codecs::pnm::encoder::PnmEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>> as image::io::encoder::ImageEncoderBoxed>::write_image
117
}
118
119
/// Implement `dynimage_conversion_sequence` for the common case of supporting only 8-bit colors
120
/// (with and without alpha).
121
#[allow(unused)]
122
0
pub(crate) fn dynimage_conversion_8bit(img: &DynamicImage) -> Option<DynamicImage> {
123
    use ColorType::*;
124
125
0
    match img.color() {
126
0
        Rgb8 | Rgba8 | L8 | La8 => None,
127
0
        L16 => Some(img.to_luma8().into()),
128
0
        La16 => Some(img.to_luma_alpha8().into()),
129
0
        Rgb16 | Rgb32F => Some(img.to_rgb8().into()),
130
0
        Rgba16 | Rgba32F => Some(img.to_rgba8().into()),
131
    }
132
0
}