1#[cfg(feature = "std")]
2pub mod decode {
3 use core::fmt;
4
5 use azul_core::resources::{RawImage, RawImageFormat};
6 use azul_css::{impl_result, impl_result_inner, U8Vec};
7 use image::{
8 error::{ImageError, LimitError, LimitErrorKind},
9 DynamicImage,
10 };
11
12 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
13 #[repr(C)]
14 pub enum DecodeImageError {
15 InsufficientMemory,
16 DimensionError,
17 UnsupportedImageFormat,
18 Unknown,
19 }
20
21 impl fmt::Display for DecodeImageError {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23 match self {
24 DecodeImageError::InsufficientMemory => write!(
25 f,
26 "Error decoding image: Not enough memory available to perform encoding \
27 operation"
28 ),
29 DecodeImageError::DimensionError => {
30 write!(f, "Error decoding image: Wrong dimensions")
31 }
32 DecodeImageError::UnsupportedImageFormat => {
33 write!(f, "Error decoding image: Invalid data format")
34 }
35 DecodeImageError::Unknown => write!(f, "Error decoding image: Unknown error"),
36 }
37 }
38 }
39
40 fn translate_image_error_decode(i: ImageError) -> DecodeImageError {
41 match i {
42 ImageError::Limits(l) => match l.kind() {
43 LimitErrorKind::InsufficientMemory => DecodeImageError::InsufficientMemory,
44 LimitErrorKind::DimensionError => DecodeImageError::DimensionError,
45 _ => DecodeImageError::Unknown,
46 },
47 _ => DecodeImageError::Unknown,
48 }
49 }
50
51 impl_result!(
52 RawImage,
53 DecodeImageError,
54 ResultRawImageDecodeImageError,
55 copy = false,
56 [Debug, Clone]
57 );
58
59 pub fn decode_raw_image_from_any_bytes(image_bytes: &[u8]) -> ResultRawImageDecodeImageError {
60 use azul_core::resources::RawImageData;
61
62 let image_format = match image::guess_format(image_bytes) {
63 Ok(o) => o,
64 Err(e) => {
65 return ResultRawImageDecodeImageError::Err(translate_image_error_decode(e));
66 }
67 };
68
69 let decoded = match image::load_from_memory_with_format(image_bytes, image_format) {
70 Ok(o) => o,
71 Err(e) => {
72 return ResultRawImageDecodeImageError::Err(translate_image_error_decode(e));
73 }
74 };
75
76 let ((width, height), data_format, pixels) = match decoded {
77 DynamicImage::ImageLuma8(i) => (
78 i.dimensions(),
79 RawImageFormat::R8,
80 RawImageData::U8(i.into_vec().into()),
81 ),
82 DynamicImage::ImageLumaA8(i) => (
83 i.dimensions(),
84 RawImageFormat::RG8,
85 RawImageData::U8(i.into_vec().into()),
86 ),
87 DynamicImage::ImageRgb8(i) => (
88 i.dimensions(),
89 RawImageFormat::RGB8,
90 RawImageData::U8(i.into_vec().into()),
91 ),
92 DynamicImage::ImageRgba8(i) => (
93 i.dimensions(),
94 RawImageFormat::RGBA8,
95 RawImageData::U8(i.into_vec().into()),
96 ),
97 DynamicImage::ImageLuma16(i) => (
98 i.dimensions(),
99 RawImageFormat::R16,
100 RawImageData::U16(i.into_vec().into()),
101 ),
102 DynamicImage::ImageLumaA16(i) => (
103 i.dimensions(),
104 RawImageFormat::RG16,
105 RawImageData::U16(i.into_vec().into()),
106 ),
107 DynamicImage::ImageRgb16(i) => (
108 i.dimensions(),
109 RawImageFormat::RGB16,
110 RawImageData::U16(i.into_vec().into()),
111 ),
112 DynamicImage::ImageRgba16(i) => (
113 i.dimensions(),
114 RawImageFormat::RGBA16,
115 RawImageData::U16(i.into_vec().into()),
116 ),
117 DynamicImage::ImageRgb32F(i) => (
118 i.dimensions(),
119 RawImageFormat::RGBF32,
120 RawImageData::F32(i.into_vec().into()),
121 ),
122 DynamicImage::ImageRgba32F(i) => (
123 i.dimensions(),
124 RawImageFormat::RGBAF32,
125 RawImageData::F32(i.into_vec().into()),
126 ),
127 _ => {
128 return ResultRawImageDecodeImageError::Err(DecodeImageError::Unknown);
129 }
130 };
131
132 ResultRawImageDecodeImageError::Ok(RawImage {
133 tag: Vec::new().into(),
134 pixels,
135 width: width as usize,
136 height: height as usize,
137 premultiplied_alpha: false,
138 data_format,
139 })
140 }
141}
142#[cfg(feature = "std")]
143pub mod encode {
144 use alloc::vec::Vec;
145 use core::fmt;
146 use std::io::Cursor;
147
148 use azul_core::resources::{RawImage, RawImageFormat};
149 use azul_css::{impl_result, impl_result_inner, U8Vec};
150 #[cfg(feature = "bmp")]
151 use image::codecs::bmp::BmpEncoder;
152 #[cfg(feature = "gif")]
153 use image::codecs::gif::GifEncoder;
154 #[cfg(feature = "hdr")]
155 use image::codecs::hdr::HdrEncoder;
156 #[cfg(feature = "jpeg")]
157 use image::codecs::jpeg::JpegEncoder;
158 #[cfg(feature = "png")]
159 use image::codecs::png::PngEncoder;
160 #[cfg(feature = "pnm")]
161 use image::codecs::pnm::PnmEncoder;
162 #[cfg(feature = "tga")]
163 use image::codecs::tga::TgaEncoder;
164 #[cfg(feature = "tiff")]
165 use image::codecs::tiff::TiffEncoder;
166 use image::error::{ImageError, LimitError, LimitErrorKind};
167
168 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
169 #[repr(C)]
170 pub enum EncodeImageError {
171 EncoderNotAvailable,
173 InsufficientMemory,
174 DimensionError,
175 InvalidData,
176 Unknown,
177 }
178
179 impl fmt::Display for EncodeImageError {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 use self::EncodeImageError::*;
182 match self {
183 EncoderNotAvailable => write!(
184 f,
185 "Missing encoder (library was not compiled with given codec)"
186 ),
187 InsufficientMemory => write!(
188 f,
189 "Error encoding image: Not enough memory available to perform encoding \
190 operation"
191 ),
192 DimensionError => write!(f, "Error encoding image: Wrong dimensions"),
193 InvalidData => write!(f, "Error encoding image: Invalid data format"),
194 Unknown => write!(f, "Error encoding image: Unknown error"),
195 }
196 }
197 }
198
199 const fn translate_rawimage_colortype(i: RawImageFormat) -> image::ColorType {
200 match i {
201 RawImageFormat::R8 => image::ColorType::L8,
202 RawImageFormat::RG8 => image::ColorType::La8,
203 RawImageFormat::RGB8 => image::ColorType::Rgb8,
204 RawImageFormat::RGBA8 => image::ColorType::Rgba8,
205 RawImageFormat::BGR8 => image::ColorType::Rgb8, RawImageFormat::BGRA8 => image::ColorType::Rgba8, RawImageFormat::R16 => image::ColorType::L16,
208 RawImageFormat::RG16 => image::ColorType::La16,
209 RawImageFormat::RGB16 => image::ColorType::Rgb16,
210 RawImageFormat::RGBA16 => image::ColorType::Rgba16,
211 RawImageFormat::RGBF32 => image::ColorType::Rgb32F,
212 RawImageFormat::RGBAF32 => image::ColorType::Rgba32F,
213 }
214 }
215
216 fn translate_image_error_encode(i: ImageError) -> EncodeImageError {
217 match i {
218 ImageError::Limits(l) => match l.kind() {
219 LimitErrorKind::InsufficientMemory => EncodeImageError::InsufficientMemory,
220 LimitErrorKind::DimensionError => EncodeImageError::DimensionError,
221 _ => EncodeImageError::Unknown,
222 },
223 _ => EncodeImageError::Unknown,
224 }
225 }
226
227 impl_result!(
228 U8Vec,
229 EncodeImageError,
230 ResultU8VecEncodeImageError,
231 copy = false,
232 [Debug, Clone]
233 );
234
235 macro_rules! encode_func {
236 ($func:ident, $encoder:ident, $feature:expr) => {
237 #[cfg(feature = $feature)]
238 pub fn $func(image: &RawImage) -> ResultU8VecEncodeImageError {
239 let mut result = Vec::<u8>::new();
240
241 {
242 let mut cursor = Cursor::new(&mut result);
243 let mut encoder = $encoder::new(&mut cursor);
244 let pixels = match image.pixels.get_u8_vec_ref() {
245 Some(s) => s,
246 None => {
247 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
248 }
249 };
250
251 if let Err(e) = encoder.encode(
252 pixels.as_ref(),
253 image.width as u32,
254 image.height as u32,
255 translate_rawimage_colortype(image.data_format).into(),
256 ) {
257 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
258 }
259 }
260
261 ResultU8VecEncodeImageError::Ok(result.into())
262 }
263
264 #[cfg(not(feature = $feature))]
265 pub fn $func(image: &RawImage) -> ResultU8VecEncodeImageError {
266 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
267 }
268 };
269 }
270
271 encode_func!(encode_bmp, BmpEncoder, "bmp");
272 encode_func!(encode_tga, TgaEncoder, "tga");
273 encode_func!(encode_tiff, TiffEncoder, "tiff");
274 encode_func!(encode_gif, GifEncoder, "gif");
275 encode_func!(encode_pnm, PnmEncoder, "pnm");
276
277 #[cfg(feature = "png")]
278 pub fn encode_png(image: &RawImage) -> ResultU8VecEncodeImageError {
279 use image::ImageEncoder;
280
281 let mut result = Vec::<u8>::new();
282
283 {
284 let mut cursor = Cursor::new(&mut result);
285 let mut encoder = PngEncoder::new_with_quality(
286 &mut cursor,
287 image::codecs::png::CompressionType::Best,
288 image::codecs::png::FilterType::Adaptive,
289 );
290 let pixels = match image.pixels.get_u8_vec_ref() {
291 Some(s) => s,
292 None => {
293 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
294 }
295 };
296
297 if let Err(e) = encoder.write_image(
298 pixels.as_ref(),
299 image.width as u32,
300 image.height as u32,
301 translate_rawimage_colortype(image.data_format).into(),
302 ) {
303 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
304 }
305 }
306
307 ResultU8VecEncodeImageError::Ok(result.into())
308 }
309
310 #[cfg(not(feature = "png"))]
311 pub fn encode_png(image: &RawImage) -> ResultU8VecEncodeImageError {
312 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
313 }
314
315 #[cfg(feature = "jpeg")]
316 pub fn encode_jpeg(image: &RawImage, quality: u8) -> ResultU8VecEncodeImageError {
317 let mut result = Vec::<u8>::new();
318
319 {
320 let mut cursor = Cursor::new(&mut result);
321 let mut encoder = JpegEncoder::new_with_quality(&mut cursor, quality);
322 let pixels = match image.pixels.get_u8_vec_ref() {
323 Some(s) => s,
324 None => {
325 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
326 }
327 };
328
329 if let Err(e) = encoder.encode(
330 pixels.as_ref(),
331 image.width as u32,
332 image.height as u32,
333 translate_rawimage_colortype(image.data_format).into(),
334 ) {
335 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
336 }
337 }
338
339 ResultU8VecEncodeImageError::Ok(result.into())
340 }
341
342 #[cfg(not(feature = "jpeg"))]
343 pub fn encode_jpeg(image: &RawImage, quality: u8) -> ResultU8VecEncodeImageError {
344 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
345 }
346}