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