skia_safe/
encode_.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::{Bitmap, EncodedImageFormat, Pixmap};

pub mod jpeg_encoder;
pub mod png_encoder;
#[cfg(feature = "webp-encode")]
pub mod webp_encoder;

impl Pixmap<'_> {
    pub fn encode(
        &self,
        format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<Vec<u8>> {
        crate::encode::pixmap(self, format, quality)
    }
}

impl Bitmap {
    pub fn encode(
        &self,
        format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<Vec<u8>> {
        crate::encode::bitmap(self, format, quality)
    }
}

impl crate::Image {
    pub fn encode<'a>(
        &self,
        context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
        format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<crate::Data> {
        crate::encode::image(context, self, format, quality)
    }
}

pub mod encode {
    use super::{jpeg_encoder, png_encoder};
    use crate::{Bitmap, EncodedImageFormat, Pixmap};

    pub fn pixmap(
        bitmap: &Pixmap,
        format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<Vec<u8>> {
        let mut data = Vec::new();
        let quality = quality.into().unwrap_or(100).clamp(0, 100);
        match format {
            EncodedImageFormat::JPEG => {
                let opts = jpeg_encoder::Options {
                    quality,
                    ..jpeg_encoder::Options::default()
                };
                jpeg_encoder::encode(bitmap, &mut data, &opts)
            }
            EncodedImageFormat::PNG => {
                let opts = png_encoder::Options::default();
                png_encoder::encode(bitmap, &mut data, &opts)
            }
            #[cfg(feature = "webp-encode")]
            EncodedImageFormat::WEBP => {
                use super::webp_encoder;
                let mut opts = webp_encoder::Options::default();
                if quality == 100 {
                    opts.compression = webp_encoder::Compression::Lossless;
                    opts.quality = 75.0;
                } else {
                    opts.compression = webp_encoder::Compression::Lossy;
                    opts.quality = quality as _;
                }
                webp_encoder::encode(bitmap, &mut data, &opts)
            }
            _ => false,
        }
        .then_some(data)
    }

    pub fn bitmap(
        bitmap: &Bitmap,
        format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<Vec<u8>> {
        let pixels = bitmap.peek_pixels()?;
        pixmap(&pixels, format, quality)
    }

    pub fn image<'a>(
        context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
        image: &crate::Image,
        image_format: EncodedImageFormat,
        quality: impl Into<Option<u32>>,
    ) -> Option<crate::Data> {
        let quality = quality.into().unwrap_or(100).clamp(0, 100);
        match image_format {
            EncodedImageFormat::JPEG => {
                let opts = jpeg_encoder::Options {
                    quality,
                    ..jpeg_encoder::Options::default()
                };
                jpeg_encoder::encode_image(context, image, &opts)
            }
            EncodedImageFormat::PNG => {
                let opts = png_encoder::Options::default();
                png_encoder::encode_image(context, image, &opts)
            }
            #[cfg(feature = "webp-encode")]
            EncodedImageFormat::WEBP => {
                use super::webp_encoder;
                let mut opts = webp_encoder::Options::default();
                if quality == 100 {
                    opts.compression = webp_encoder::Compression::Lossless;
                    opts.quality = 75.0;
                } else {
                    opts.compression = webp_encoder::Compression::Lossy;
                    opts.quality = quality as _;
                }
                webp_encoder::encode_image(context, image, &opts)
            }
            _ => None,
        }
    }
}