1 | use crate::{Bitmap, EncodedImageFormat, Pixmap}; |
2 | |
3 | pub mod jpeg_encoder; |
4 | pub mod png_encoder; |
5 | #[cfg (feature = "webp-encode" )] |
6 | pub mod webp_encoder; |
7 | |
8 | impl 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 | |
18 | impl 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 | |
28 | impl 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 | |
39 | pub 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 | |