1use crate::encode::{Encoder, try_alloc_vec};
27use crate::error::Result;
28use imgref::ImgRef;
29use rgb::{Gray, RGB, RGBA};
30
31pub trait EncodeablePixel: Copy {
37 const IS_GRAYSCALE: bool;
39
40 fn to_gray(&self) -> u8;
42
43 fn to_rgb(&self) -> (u8, u8, u8);
45}
46
47impl EncodeablePixel for RGB<u8> {
48 const IS_GRAYSCALE: bool = false;
49
50 #[inline]
51 fn to_gray(&self) -> u8 {
52 ((self.r as u32 * 77 + self.g as u32 * 150 + self.b as u32 * 29) >> 8) as u8
54 }
55
56 #[inline]
57 fn to_rgb(&self) -> (u8, u8, u8) {
58 (self.r, self.g, self.b)
59 }
60}
61
62impl EncodeablePixel for RGBA<u8> {
63 const IS_GRAYSCALE: bool = false;
64
65 #[inline]
66 fn to_gray(&self) -> u8 {
67 ((self.r as u32 * 77 + self.g as u32 * 150 + self.b as u32 * 29) >> 8) as u8
68 }
69
70 #[inline]
71 fn to_rgb(&self) -> (u8, u8, u8) {
72 (self.r, self.g, self.b)
73 }
74}
75
76impl EncodeablePixel for Gray<u8> {
77 const IS_GRAYSCALE: bool = true;
78
79 #[inline]
80 fn to_gray(&self) -> u8 {
81 *self.as_ref()
82 }
83
84 #[inline]
85 fn to_rgb(&self) -> (u8, u8, u8) {
86 let v = *self.as_ref();
87 (v, v, v)
88 }
89}
90
91impl EncodeablePixel for [u8; 3] {
92 const IS_GRAYSCALE: bool = false;
93
94 #[inline]
95 fn to_gray(&self) -> u8 {
96 ((self[0] as u32 * 77 + self[1] as u32 * 150 + self[2] as u32 * 29) >> 8) as u8
97 }
98
99 #[inline]
100 fn to_rgb(&self) -> (u8, u8, u8) {
101 (self[0], self[1], self[2])
102 }
103}
104
105impl EncodeablePixel for [u8; 4] {
106 const IS_GRAYSCALE: bool = false;
107
108 #[inline]
109 fn to_gray(&self) -> u8 {
110 ((self[0] as u32 * 77 + self[1] as u32 * 150 + self[2] as u32 * 29) >> 8) as u8
111 }
112
113 #[inline]
114 fn to_rgb(&self) -> (u8, u8, u8) {
115 (self[0], self[1], self[2])
116 }
117}
118
119impl EncodeablePixel for u8 {
120 const IS_GRAYSCALE: bool = true;
121
122 #[inline]
123 fn to_gray(&self) -> u8 {
124 *self
125 }
126
127 #[inline]
128 fn to_rgb(&self) -> (u8, u8, u8) {
129 (*self, *self, *self)
130 }
131}
132
133impl Encoder {
134 pub fn encode_imgref<P: EncodeablePixel>(&self, img: ImgRef<'_, P>) -> Result<Vec<u8>> {
163 let width = img.width() as u32;
164 let height = img.height() as u32;
165
166 if P::IS_GRAYSCALE {
167 let mut gray_data = try_alloc_vec(0u8, (width * height) as usize)?;
169 for (y, row) in img.rows().enumerate() {
170 for (x, pixel) in row.iter().enumerate() {
171 gray_data[y * width as usize + x] = pixel.to_gray();
172 }
173 }
174 self.encode_gray(&gray_data, width, height)
175 } else {
176 let mut rgb_data = try_alloc_vec(0u8, (width * height * 3) as usize)?;
178 for (y, row) in img.rows().enumerate() {
179 for (x, pixel) in row.iter().enumerate() {
180 let (r, g, b) = pixel.to_rgb();
181 let i = (y * width as usize + x) * 3;
182 rgb_data[i] = r;
183 rgb_data[i + 1] = g;
184 rgb_data[i + 2] = b;
185 }
186 }
187 self.encode_rgb(&rgb_data, width, height)
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use crate::Preset;
196 use imgref::ImgVec;
197 use rgb::{Gray, RGB8, RGBA8};
198
199 #[test]
200 fn test_encode_imgref_rgb8() {
201 let pixels: Vec<RGB8> = (0..64 * 48)
202 .map(|i| {
203 RGB8::new(
204 (i % 256) as u8,
205 ((i * 2) % 256) as u8,
206 ((i * 3) % 256) as u8,
207 )
208 })
209 .collect();
210 let img = ImgVec::new(pixels, 64, 48);
211
212 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
213 let jpeg = encoder.encode_imgref(img.as_ref()).unwrap();
214
215 assert!(jpeg.len() > 100);
217 assert_eq!(&jpeg[0..2], &[0xFF, 0xD8]); let mut decoder = jpeg_decoder::Decoder::new(&jpeg[..]);
221 let decoded = decoder.decode().unwrap();
222 let info = decoder.info().unwrap();
223 assert_eq!(info.width, 64);
224 assert_eq!(info.height, 48);
225 assert_eq!(info.pixel_format, jpeg_decoder::PixelFormat::RGB24);
226 assert_eq!(decoded.len(), 64 * 48 * 3);
227 }
228
229 #[test]
230 fn test_encode_imgref_rgba8() {
231 let pixels: Vec<RGBA8> = (0..64 * 48)
232 .map(|i| {
233 RGBA8::new(
234 (i % 256) as u8,
235 ((i * 2) % 256) as u8,
236 ((i * 3) % 256) as u8,
237 255,
238 )
239 })
240 .collect();
241 let img = ImgVec::new(pixels, 64, 48);
242
243 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
244 let jpeg = encoder.encode_imgref(img.as_ref()).unwrap();
245
246 assert!(jpeg.len() > 100);
248 assert_eq!(&jpeg[0..2], &[0xFF, 0xD8]);
249
250 let mut decoder = jpeg_decoder::Decoder::new(&jpeg[..]);
252 decoder.decode().unwrap();
253 let info = decoder.info().unwrap();
254 assert_eq!(info.pixel_format, jpeg_decoder::PixelFormat::RGB24);
255 }
256
257 #[test]
258 fn test_encode_imgref_gray() {
259 let pixels: Vec<Gray<u8>> = (0..64 * 48).map(|i| Gray::new((i % 256) as u8)).collect();
260 let img = ImgVec::new(pixels, 64, 48);
261
262 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
263 let jpeg = encoder.encode_imgref(img.as_ref()).unwrap();
264
265 assert!(jpeg.len() > 100);
267 assert_eq!(&jpeg[0..2], &[0xFF, 0xD8]);
268
269 let mut decoder = jpeg_decoder::Decoder::new(&jpeg[..]);
271 decoder.decode().unwrap();
272 let info = decoder.info().unwrap();
273 assert_eq!(info.pixel_format, jpeg_decoder::PixelFormat::L8);
274 }
275
276 #[test]
277 fn test_encode_imgref_u8_slice() {
278 let pixels: Vec<u8> = (0..64 * 48).map(|i| (i % 256) as u8).collect();
279 let img = ImgVec::new(pixels, 64, 48);
280
281 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
282 let jpeg = encoder.encode_imgref(img.as_ref()).unwrap();
283
284 let mut decoder = jpeg_decoder::Decoder::new(&jpeg[..]);
286 decoder.decode().unwrap();
287 let info = decoder.info().unwrap();
288 assert_eq!(info.pixel_format, jpeg_decoder::PixelFormat::L8);
289 }
290
291 #[test]
292 fn test_encode_imgref_with_stride() {
293 let full_width = 128;
295 let full_height = 96;
296 let mut full_pixels: Vec<RGB8> = vec![RGB8::new(0, 0, 0); full_width * full_height];
297
298 for y in 0..48 {
300 for x in 0..64 {
301 let i = (y + 8) * full_width + (x + 16);
302 full_pixels[i] = RGB8::new((x * 4) as u8, (y * 5) as u8, 128);
303 }
304 }
305
306 let full_img = ImgVec::new(full_pixels, full_width, full_height);
307 let sub_img = full_img.sub_image(16, 8, 64, 48);
308
309 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
311 let jpeg = encoder.encode_imgref(sub_img).unwrap();
312
313 let mut decoder = jpeg_decoder::Decoder::new(&jpeg[..]);
315 decoder.decode().unwrap();
316 let info = decoder.info().unwrap();
317 assert_eq!(info.width, 64);
318 assert_eq!(info.height, 48);
319 }
320
321 #[test]
322 fn test_encode_imgref_matches_encode_rgb() {
323 let pixels: Vec<RGB8> = (0..64 * 48)
324 .map(|i| {
325 RGB8::new(
326 (i % 256) as u8,
327 ((i * 2) % 256) as u8,
328 ((i * 3) % 256) as u8,
329 )
330 })
331 .collect();
332 let img = ImgVec::new(pixels.clone(), 64, 48);
333
334 let rgb_bytes: Vec<u8> = pixels.iter().flat_map(|p| [p.r, p.g, p.b]).collect();
336
337 let encoder = Encoder::new(Preset::BaselineBalanced).quality(85);
338 let jpeg_imgref = encoder.encode_imgref(img.as_ref()).unwrap();
339 let jpeg_rgb = encoder.encode_rgb(&rgb_bytes, 64, 48).unwrap();
340
341 assert_eq!(jpeg_imgref, jpeg_rgb);
343 }
344}