azul_layout/image/
encode.rs1use alloc::vec::Vec;
2use core::fmt;
3use std::io::Cursor;
4
5use azul_core::app_resources::{RawImage, RawImageFormat};
6use azul_css::{impl_result, impl_result_inner, U8Vec};
7#[cfg(feature = "bmp")]
8use image::codecs::bmp::BmpEncoder;
9#[cfg(feature = "gif")]
10use image::codecs::gif::GifEncoder;
11#[cfg(feature = "hdr")]
12use image::codecs::hdr::HdrEncoder;
13#[cfg(feature = "jpeg")]
14use image::codecs::jpeg::JpegEncoder;
15#[cfg(feature = "png")]
16use image::codecs::png::PngEncoder;
17#[cfg(feature = "pnm")]
18use image::codecs::pnm::PnmEncoder;
19#[cfg(feature = "tga")]
20use image::codecs::tga::TgaEncoder;
21#[cfg(feature = "tiff")]
22use image::codecs::tiff::TiffEncoder;
23use image::error::{ImageError, LimitError, LimitErrorKind};
24
25#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
26#[repr(C)]
27pub enum EncodeImageError {
28 EncoderNotAvailable,
30 InsufficientMemory,
31 DimensionError,
32 InvalidData,
33 Unknown,
34}
35
36impl fmt::Display for EncodeImageError {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 use self::EncodeImageError::*;
39 match self {
40 EncoderNotAvailable => write!(
41 f,
42 "Missing encoder (library was not compiled with given codec)"
43 ),
44 InsufficientMemory => write!(
45 f,
46 "Error encoding image: Not enough memory available to perform encoding operation"
47 ),
48 DimensionError => write!(f, "Error encoding image: Wrong dimensions"),
49 InvalidData => write!(f, "Error encoding image: Invalid data format"),
50 Unknown => write!(f, "Error encoding image: Unknown error"),
51 }
52 }
53}
54
55const fn translate_rawimage_colortype(i: RawImageFormat) -> image::ColorType {
56 match i {
57 RawImageFormat::R8 => image::ColorType::L8,
58 RawImageFormat::RG8 => image::ColorType::La8,
59 RawImageFormat::RGB8 => image::ColorType::Rgb8,
60 RawImageFormat::RGBA8 => image::ColorType::Rgba8,
61 RawImageFormat::BGR8 => image::ColorType::Rgb8, RawImageFormat::BGRA8 => image::ColorType::Rgba8, RawImageFormat::R16 => image::ColorType::L16,
64 RawImageFormat::RG16 => image::ColorType::La16,
65 RawImageFormat::RGB16 => image::ColorType::Rgb16,
66 RawImageFormat::RGBA16 => image::ColorType::Rgba16,
67 RawImageFormat::RGBF32 => image::ColorType::Rgb32F,
68 RawImageFormat::RGBAF32 => image::ColorType::Rgba32F,
69 }
70}
71
72fn translate_image_error_encode(i: ImageError) -> EncodeImageError {
73 match i {
74 ImageError::Limits(l) => match l.kind() {
75 LimitErrorKind::InsufficientMemory => EncodeImageError::InsufficientMemory,
76 LimitErrorKind::DimensionError => EncodeImageError::DimensionError,
77 _ => EncodeImageError::Unknown,
78 },
79 _ => EncodeImageError::Unknown,
80 }
81}
82
83impl_result!(
84 U8Vec,
85 EncodeImageError,
86 ResultU8VecEncodeImageError,
87 copy = false,
88 [Debug, Clone]
89);
90
91macro_rules! encode_func {
92 ($func:ident, $encoder:ident, $feature:expr) => {
93 #[cfg(feature = $feature)]
94 pub fn $func(image: &RawImage) -> ResultU8VecEncodeImageError {
95 let mut result = Vec::<u8>::new();
96
97 {
98 let mut cursor = Cursor::new(&mut result);
99 let mut encoder = $encoder::new(&mut cursor);
100 let pixels = match image.pixels.get_u8_vec_ref() {
101 Some(s) => s,
102 None => {
103 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
104 }
105 };
106
107 if let Err(e) = encoder.encode(
108 pixels.as_ref(),
109 image.width as u32,
110 image.height as u32,
111 translate_rawimage_colortype(image.data_format).into(),
112 ) {
113 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
114 }
115 }
116
117 ResultU8VecEncodeImageError::Ok(result.into())
118 }
119
120 #[cfg(not(feature = $feature))]
121 pub fn $func(image: &RawImage) -> ResultU8VecEncodeImageError {
122 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
123 }
124 };
125}
126
127encode_func!(encode_bmp, BmpEncoder, "bmp");
128encode_func!(encode_tga, TgaEncoder, "tga");
129encode_func!(encode_tiff, TiffEncoder, "tiff");
130encode_func!(encode_gif, GifEncoder, "gif");
131encode_func!(encode_pnm, PnmEncoder, "pnm");
132
133#[cfg(feature = "png")]
134pub fn encode_png(image: &RawImage) -> ResultU8VecEncodeImageError {
135 use image::ImageEncoder;
136
137 let mut result = Vec::<u8>::new();
138
139 {
140 let mut cursor = Cursor::new(&mut result);
141 let mut encoder = PngEncoder::new_with_quality(
142 &mut cursor,
143 image::codecs::png::CompressionType::Best,
144 image::codecs::png::FilterType::Adaptive,
145 );
146 let pixels = match image.pixels.get_u8_vec_ref() {
147 Some(s) => s,
148 None => {
149 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
150 }
151 };
152
153 if let Err(e) = encoder.write_image(
154 pixels.as_ref(),
155 image.width as u32,
156 image.height as u32,
157 translate_rawimage_colortype(image.data_format).into(),
158 ) {
159 println!("{:?}", e);
160 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
161 }
162 }
163
164 ResultU8VecEncodeImageError::Ok(result.into())
165}
166
167#[cfg(not(feature = "png"))]
168pub fn encode_png(image: &RawImage) -> ResultU8VecEncodeImageError {
169 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
170}
171
172#[cfg(feature = "jpeg")]
173pub fn encode_jpeg(image: &RawImage, quality: u8) -> ResultU8VecEncodeImageError {
174 let mut result = Vec::<u8>::new();
175
176 {
177 let mut cursor = Cursor::new(&mut result);
178 let mut encoder = JpegEncoder::new_with_quality(&mut cursor, quality);
179 let pixels = match image.pixels.get_u8_vec_ref() {
180 Some(s) => s,
181 None => {
182 return ResultU8VecEncodeImageError::Err(EncodeImageError::InvalidData);
183 }
184 };
185
186 if let Err(e) = encoder.encode(
187 pixels.as_ref(),
188 image.width as u32,
189 image.height as u32,
190 translate_rawimage_colortype(image.data_format).into(),
191 ) {
192 println!("{:?}", e);
193 return ResultU8VecEncodeImageError::Err(translate_image_error_encode(e));
194 }
195 }
196
197 ResultU8VecEncodeImageError::Ok(result.into())
198}
199
200#[cfg(not(feature = "jpeg"))]
201pub fn encode_jpeg(image: &RawImage) -> ResultU8VecEncodeImageError {
202 ResultU8VecEncodeImageError::Err(EncodeImageError::EncoderNotAvailable)
203}