1use crate::{Bitmap, EncodedImageFormat, Pixmap};
2
3pub mod jpeg_encoder;
4pub mod png_encoder;
5#[cfg(feature = "webp-encode")]
6pub mod webp_encoder;
7
8impl Pixmap<'_> {
9 pub fn encode(
10 &self,
11 format: EncodedImageFormat,
12 quality: impl Into<Option<u32>>,
13 ) -> Option<Vec<u8>> {
14 crate::encode::pixmap(self, format, quality)
15 }
16}
17
18impl Bitmap {
19 pub fn encode(
20 &self,
21 format: EncodedImageFormat,
22 quality: impl Into<Option<u32>>,
23 ) -> Option<Vec<u8>> {
24 crate::encode::bitmap(self, format, quality)
25 }
26}
27
28impl crate::Image {
29 pub fn encode<'a>(
30 &self,
31 context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
32 format: EncodedImageFormat,
33 quality: impl Into<Option<u32>>,
34 ) -> Option<crate::Data> {
35 crate::encode::image(context, self, image_format:format, quality)
36 }
37}
38
39pub mod encode {
40 use super::{jpeg_encoder, png_encoder};
41 use crate::{Bitmap, EncodedImageFormat, Pixmap};
42
43 pub fn pixmap(
44 bitmap: &Pixmap,
45 format: EncodedImageFormat,
46 quality: impl Into<Option<u32>>,
47 ) -> Option<Vec<u8>> {
48 let mut data = Vec::new();
49 let quality = quality.into().unwrap_or(100).clamp(0, 100);
50 match format {
51 EncodedImageFormat::JPEG => {
52 let opts = jpeg_encoder::Options {
53 quality,
54 ..jpeg_encoder::Options::default()
55 };
56 jpeg_encoder::encode(bitmap, &mut data, &opts)
57 }
58 EncodedImageFormat::PNG => {
59 let opts = png_encoder::Options::default();
60 png_encoder::encode(bitmap, &mut data, &opts)
61 }
62 #[cfg(feature = "webp-encode")]
63 EncodedImageFormat::WEBP => {
64 use super::webp_encoder;
65 let mut opts = webp_encoder::Options::default();
66 if quality == 100 {
67 opts.compression = webp_encoder::Compression::Lossless;
68 opts.quality = 75.0;
69 } else {
70 opts.compression = webp_encoder::Compression::Lossy;
71 opts.quality = quality as _;
72 }
73 webp_encoder::encode(bitmap, &mut data, &opts)
74 }
75 _ => false,
76 }
77 .then_some(data)
78 }
79
80 pub fn bitmap(
81 bitmap: &Bitmap,
82 format: EncodedImageFormat,
83 quality: impl Into<Option<u32>>,
84 ) -> Option<Vec<u8>> {
85 let pixels = bitmap.peek_pixels()?;
86 pixmap(&pixels, format, quality)
87 }
88
89 pub fn image<'a>(
90 context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
91 image: &crate::Image,
92 image_format: EncodedImageFormat,
93 quality: impl Into<Option<u32>>,
94 ) -> Option<crate::Data> {
95 let quality = quality.into().unwrap_or(100).clamp(0, 100);
96 match image_format {
97 EncodedImageFormat::JPEG => {
98 let opts = jpeg_encoder::Options {
99 quality,
100 ..jpeg_encoder::Options::default()
101 };
102 jpeg_encoder::encode_image(context, image, &opts)
103 }
104 EncodedImageFormat::PNG => {
105 let opts = png_encoder::Options::default();
106 png_encoder::encode_image(context, image, &opts)
107 }
108 #[cfg(feature = "webp-encode")]
109 EncodedImageFormat::WEBP => {
110 use super::webp_encoder;
111 let mut opts = webp_encoder::Options::default();
112 if quality == 100 {
113 opts.compression = webp_encoder::Compression::Lossless;
114 opts.quality = 75.0;
115 } else {
116 opts.compression = webp_encoder::Compression::Lossy;
117 opts.quality = quality as _;
118 }
119 webp_encoder::encode_image(context, image, &opts)
120 }
121 _ => None,
122 }
123 }
124}
125