libsixel_rs/
pixel_format.rs

1use crate::{color::Rgb, std::fmt, Error, Result};
2
3/// Represents the color format for a [PixelFormat].
4#[repr(i32)]
5#[derive(Copy, Clone, Debug, Default, PartialEq)]
6pub enum FormatType {
7    #[default]
8    Color = 0,
9    Grayscale = 1 << 6,
10    Palette = 1 << 7,
11}
12
13/// Represents pixel format modes (bpp = bits per pixel).
14#[repr(i32)]
15#[derive(Copy, Clone, Debug, Default, PartialEq)]
16pub enum PixelFormat {
17    /// 15bpp
18    Rgb555 = FormatType::Color as i32 | 0x01,
19    /// 16bpp
20    Rgb565 = FormatType::Color as i32 | 0x02,
21    /// 24bpp
22    #[default]
23    Rgb888 = FormatType::Color as i32 | 0x03,
24    /// 15bpp
25    Bgr555 = FormatType::Color as i32 | 0x04,
26    /// 16bpp
27    Bgr565 = FormatType::Color as i32 | 0x05,
28    /// 24bpp
29    Bgr888 = FormatType::Color as i32 | 0x06,
30    /// 32bpp
31    Argb8888 = FormatType::Color as i32 | 0x10,
32    /// 32bpp
33    Rgba8888 = FormatType::Color as i32 | 0x11,
34    /// 32bpp
35    Abgr8888 = FormatType::Color as i32 | 0x12,
36    /// 32bpp
37    Bgra8888 = FormatType::Color as i32 | 0x13,
38    /// 1bpp grayscale
39    G1 = FormatType::Grayscale as i32,
40    /// 2bpp grayscale
41    G2 = FormatType::Grayscale as i32 | 0x01,
42    /// 4bpp grayscale
43    G4 = FormatType::Grayscale as i32 | 0x02,
44    /// 8bpp grayscale
45    G8 = FormatType::Grayscale as i32 | 0x03,
46    /// 16bpp grayscale + alpha
47    Ag88 = FormatType::Grayscale as i32 | 0x13,
48    /// 16bpp grayscale + alpha
49    Ga88 = FormatType::Grayscale as i32 | 0x23,
50    /// 1bpp palette
51    Pal1 = FormatType::Palette as i32,
52    /// 2bpp palette
53    Pal2 = FormatType::Palette as i32 | 0x01,
54    /// 4bpp palette
55    Pal4 = FormatType::Palette as i32 | 0x02,
56    /// 8bpp palette
57    Pal8 = FormatType::Palette as i32 | 0x03,
58}
59
60impl PixelFormat {
61    /// Creates a new [PixelFormat].
62    pub const fn new() -> Self {
63        Self::Rgb888
64    }
65
66    /// Compute the pixel depth for the [PixelFormat].
67    pub fn compute_depth(&self) -> usize {
68        match self {
69            Self::Argb8888 | Self::Rgba8888 | Self::Abgr8888 | Self::Bgra8888 => 4,
70            Self::Rgb888 | Self::Bgr888 => 3,
71            Self::Rgb555 | Self::Rgb565 | Self::Bgr555 | Self::Bgr565 | Self::Ag88 | Self::Ga88 => {
72                2
73            }
74            Self::G1
75            | Self::G2
76            | Self::G4
77            | Self::G8
78            | Self::Pal1
79            | Self::Pal2
80            | Self::Pal4
81            | Self::Pal8 => 1,
82        }
83    }
84
85    /// Gets the [Rgb] values at the given depth from the provide data.
86    pub fn rgb(&self, data: &[u8], depth: usize) -> Result<Rgb> {
87        let mut pixels = 0u32;
88
89        let data_len = data.len();
90
91        if depth > data_len {
92            return Err(Error::PixelFormat(format!("invalid RGB depth larger than data length, data length: {data_len}, depth: {depth}")));
93        }
94
95        for &d in data.iter().take(depth) {
96            pixels = d as u32 | pixels << 8;
97        }
98
99        let ret = match self {
100            Self::Rgb555 => Rgb::create(
101                (((pixels >> 10) & 0x1f) << 3) as u8,
102                (((pixels >> 5) & 0x1f) << 3) as u8,
103                ((pixels & 0x1f) << 3) as u8,
104            ),
105            Self::Rgb565 => Rgb::create(
106                (((pixels >> 11) & 0x1f) << 3) as u8,
107                (((pixels >> 5) & 0x3f) << 2) as u8,
108                ((pixels & 0x1f) << 3) as u8,
109            ),
110            Self::Rgb888 => Rgb::create(
111                ((pixels >> 16) & 0xff) as u8,
112                ((pixels >> 8) & 0xff) as u8,
113                (pixels & 0xff) as u8,
114            ),
115            Self::Bgr555 => Rgb::create(
116                ((pixels & 0x1f) << 3) as u8,
117                (((pixels >> 5) & 0x1f) << 3) as u8,
118                (((pixels >> 10) & 0x1f) << 3) as u8,
119            ),
120            Self::Bgr565 => Rgb::create(
121                ((pixels & 0x1f) << 3) as u8,
122                (((pixels >> 5) & 0x3f) << 2) as u8,
123                (((pixels >> 11) & 0x1f) << 3) as u8,
124            ),
125            Self::Bgr888 => Rgb::create(
126                (pixels & 0xff) as u8,
127                ((pixels >> 8) & 0xff) as u8,
128                ((pixels >> 16) & 0xff) as u8,
129            ),
130            Self::Rgba8888 => Rgb::create(
131                ((pixels >> 24) & 0xff) as u8,
132                ((pixels >> 16) & 0xff) as u8,
133                ((pixels >> 8) & 0xff) as u8,
134            ),
135            Self::Argb8888 => Rgb::create(
136                ((pixels >> 16) & 0xff) as u8,
137                ((pixels >> 8) & 0xff) as u8,
138                (pixels & 0xff) as u8,
139            ),
140            Self::Bgra8888 => Rgb::create(
141                ((pixels >> 8) & 0xff) as u8,
142                ((pixels >> 16) & 0xff) as u8,
143                ((pixels >> 24) & 0xff) as u8,
144            ),
145            Self::Abgr8888 => Rgb::create(
146                (pixels & 0xff) as u8,
147                ((pixels >> 8) & 0xff) as u8,
148                ((pixels >> 16) & 0xff) as u8,
149            ),
150            Self::Ga88 => {
151                let color = ((pixels >> 8) & 0xff) as u8;
152                Rgb::create(color, color, color)
153            }
154            Self::G8 | Self::Ag88 => {
155                let color = (pixels & 0xff) as u8;
156                Rgb::create(color, color, color)
157            }
158            _ => Rgb::new(),
159        };
160
161        Ok(ret)
162    }
163
164    /// Expands the [PixelFormat] RGB data.
165    pub fn expand_rgb(
166        &self,
167        dst: &mut [u8],
168        src: &[u8],
169        width: usize,
170        height: usize,
171        depth: usize,
172    ) -> Result<()> {
173        let dst_len = dst.len();
174        let src_len = src.len();
175
176        for y in 0..height {
177            for x in 0..width {
178                let src_offset = depth.saturating_mul(y.saturating_mul(width).saturating_add(x));
179                let dst_offset = 3usize.saturating_mul(y.saturating_mul(width).saturating_add(x));
180
181                if src_offset >= src.len() {
182                    return Err(Error::PixelFormat(format!(
183                        "invalid depth, source length: {src_len}, source offset: {src_offset}"
184                    )));
185                }
186
187                let rgb = self.rgb(&src[src_offset..], depth)?;
188
189                if dst_offset + 2 >= dst.len() {
190                    return Err(Error::PixelFormat(format!(
191                        "invalid RGB depth, destination length: {dst_len}, destination offset: {}",
192                        dst_offset + 2
193                    )));
194                }
195
196                dst[dst_offset] = rgb.r();
197                dst[dst_offset + 1] = rgb.g();
198                dst[dst_offset + 2] = rgb.b();
199            }
200        }
201
202        Ok(())
203    }
204
205    /// Expands the Sixel color palette.
206    pub fn expand_palette(
207        &self,
208        dst: &mut [u8],
209        src: &[u8],
210        width: usize,
211        height: usize,
212    ) -> Result<()> {
213        // bit per plane
214        let mut bpp = 0;
215
216        let mut dst_view = dst;
217        let mut src_view = src;
218
219        match self {
220            PixelFormat::Pal1 | PixelFormat::G1 => {
221                bpp = 1;
222            }
223            PixelFormat::Pal2 | PixelFormat::G2 => {
224                bpp = 2;
225            }
226            PixelFormat::Pal4 | PixelFormat::G4 => {
227                bpp = 4;
228            }
229            PixelFormat::Pal8 | PixelFormat::G8 => {
230                let offset = width.saturating_mul(height).saturating_sub(1);
231                let (dst_len, src_len) = (dst_view.len(), src_view.len());
232
233                if offset >= dst_len || offset >= src_len {
234                    return Err(Error::PixelFormat(format!("width and height outside the bounds of the palette buffers, dst len: {dst_len}, src len: {src_len}, offset: {offset}")));
235                }
236
237                dst_view = &mut dst_view[offset..];
238                src_view = &src_view[offset..];
239            }
240            _ => {
241                return Err(Error::PixelFormat(format!("invalid pixel format: {self}")));
242            }
243        }
244
245        for _y in 0..height {
246            let upper_bound = width.saturating_mul(bpp).saturating_div(8);
247            for _x in 0..upper_bound {
248                for i in 0..8usize.saturating_div(bpp) {
249                    dst_view = &mut dst_view[1..];
250
251                    let shift = 8usize
252                        .saturating_div(bpp)
253                        .saturating_sub(1)
254                        .saturating_sub(i);
255                    let tail_shift = 1u32.overflowing_shl(bpp as u32).0.saturating_sub(1);
256
257                    dst_view[0] = ((src[0] as u32)
258                        .overflowing_shr(shift as u32)
259                        .0
260                        .saturating_mul(bpp as u32)
261                        & tail_shift) as u8;
262                }
263                src_view = &src_view[1..];
264            }
265
266            let x = width - upper_bound.saturating_mul(8).saturating_div(bpp);
267
268            if x > 0 {
269                for i in 0..x {
270                    dst_view = &mut dst_view[1..];
271
272                    let shift = 8usize.saturating_sub(i + 1).saturating_mul(bpp);
273                    let tail_shift = 1u32.overflowing_shl(bpp as u32).0.saturating_sub(1);
274
275                    dst_view[0] =
276                        ((src_view[0] as u32).overflowing_shr(shift as u32).0 & tail_shift) as u8;
277                }
278
279                src_view = &src_view[1..];
280            }
281        }
282
283        Ok(())
284    }
285
286    /// Normalizes the [PixelFormat].
287    pub fn normalize(
288        &mut self,
289        dst: &mut [u8],
290        src: &[u8],
291        width: usize,
292        height: usize,
293    ) -> Result<()> {
294        let format = match self {
295            PixelFormat::G8 => {
296                self.expand_rgb(dst, src, width, height, 1)?;
297
298                PixelFormat::Rgb888
299            }
300            PixelFormat::Rgb565
301            | PixelFormat::Rgb555
302            | PixelFormat::Bgr565
303            | PixelFormat::Bgr555
304            | PixelFormat::Ga88
305            | PixelFormat::Ag88 => {
306                self.expand_rgb(dst, src, width, height, 2)?;
307
308                PixelFormat::Rgb888
309            }
310            PixelFormat::Rgb888 | PixelFormat::Bgr888 => {
311                self.expand_rgb(dst, src, width, height, 3)?;
312
313                PixelFormat::Rgb888
314            }
315            PixelFormat::Rgba8888
316            | PixelFormat::Argb8888
317            | PixelFormat::Bgra8888
318            | PixelFormat::Abgr8888 => {
319                self.expand_rgb(dst, src, width, height, 4)?;
320
321                PixelFormat::Rgb888
322            }
323            PixelFormat::Pal1 | PixelFormat::Pal2 | PixelFormat::Pal4 => {
324                self.expand_palette(dst, src, width, height)?;
325
326                PixelFormat::Pal8
327            }
328            PixelFormat::G1 | PixelFormat::G2 | PixelFormat::G4 => {
329                self.expand_palette(dst, src, width, height)?;
330
331                PixelFormat::G8
332            }
333            PixelFormat::Pal8 => {
334                let len = width.saturating_mul(height);
335                dst[..len].copy_from_slice(src[..len].as_ref());
336
337                *self
338            }
339        };
340
341        *self = format;
342
343        Ok(())
344    }
345}
346
347impl From<i32> for PixelFormat {
348    fn from(val: i32) -> Self {
349        match val {
350            pf if pf == Self::Rgb555 as i32 => Self::Rgb555,
351            pf if pf == Self::Rgb565 as i32 => Self::Rgb565,
352            pf if pf == Self::Rgb888 as i32 => Self::Rgb888,
353            pf if pf == Self::Bgr555 as i32 => Self::Bgr555,
354            pf if pf == Self::Bgr565 as i32 => Self::Bgr565,
355            pf if pf == Self::Bgr888 as i32 => Self::Bgr888,
356            pf if pf == Self::Argb8888 as i32 => Self::Argb8888,
357            pf if pf == Self::Rgba8888 as i32 => Self::Rgba8888,
358            pf if pf == Self::Abgr8888 as i32 => Self::Abgr8888,
359            pf if pf == Self::Bgra8888 as i32 => Self::Bgra8888,
360            pf if pf == Self::G1 as i32 => Self::G1,
361            pf if pf == Self::G2 as i32 => Self::G2,
362            pf if pf == Self::G4 as i32 => Self::G4,
363            pf if pf == Self::G8 as i32 => Self::G8,
364            pf if pf == Self::Ag88 as i32 => Self::Ag88,
365            pf if pf == Self::Ga88 as i32 => Self::Ga88,
366            pf if pf == Self::Pal1 as i32 => Self::Pal1,
367            pf if pf == Self::Pal2 as i32 => Self::Pal2,
368            pf if pf == Self::Pal4 as i32 => Self::Pal4,
369            pf if pf == Self::Pal8 as i32 => Self::Pal8,
370            _ => Self::Rgb888,
371        }
372    }
373}
374
375impl From<PixelFormat> for i32 {
376    fn from(val: PixelFormat) -> Self {
377        val as i32
378    }
379}
380
381impl From<PixelFormat> for &'static str {
382    fn from(val: PixelFormat) -> Self {
383        match val {
384            PixelFormat::Rgb555 => "RGB555",
385            PixelFormat::Rgb565 => "RGB565",
386            PixelFormat::Rgb888 => "RGB888",
387            PixelFormat::Bgr555 => "BGR555",
388            PixelFormat::Bgr565 => "BGR565",
389            PixelFormat::Bgr888 => "BGR888",
390            PixelFormat::Argb8888 => "ARGB8888",
391            PixelFormat::Rgba8888 => "RGBA8888",
392            PixelFormat::Abgr8888 => "ABGR8888",
393            PixelFormat::Bgra8888 => "BGRA8888",
394            PixelFormat::G1 => "G1",
395            PixelFormat::G2 => "G2",
396            PixelFormat::G4 => "G4",
397            PixelFormat::G8 => "G8",
398            PixelFormat::Ag88 => "AG88",
399            PixelFormat::Ga88 => "GA88",
400            PixelFormat::Pal1 => "PAL1",
401            PixelFormat::Pal2 => "PAL2",
402            PixelFormat::Pal4 => "PAL4",
403            PixelFormat::Pal8 => "PAL8",
404        }
405    }
406}
407
408impl From<&PixelFormat> for &'static str {
409    fn from(val: &PixelFormat) -> Self {
410        (*val).into()
411    }
412}
413
414impl fmt::Display for PixelFormat {
415    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416        write!(f, "{}", <&str>::from(self))
417    }
418}
419
420#[cfg(test)]
421mod tests {
422    use super::*;
423
424    #[test]
425    fn test_1() -> Result<()> {
426        let mut dst = [0u8; 3];
427        let src = [0x46, 0xf3, 0xe5];
428
429        let exp_pixel_fmt = PixelFormat::Rgb888;
430        let mut pixel_fmt = PixelFormat::Rgb888;
431
432        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
433
434        assert_eq!(pixel_fmt, exp_pixel_fmt);
435        assert_eq!(dst, src);
436
437        Ok(())
438    }
439
440    #[test]
441    fn test_2() -> Result<()> {
442        let mut dst = [0u8; 3];
443        let src = [0x47, 0x9c];
444
445        let exp_pixel_fmt = PixelFormat::Rgb888;
446        let mut pixel_fmt = PixelFormat::Rgb555;
447
448        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
449
450        assert_eq!(pixel_fmt, exp_pixel_fmt);
451        assert_eq!(
452            ((dst[0] as u32 >> 3) << 10) | ((dst[1] as u32 >> 3) << 5) | (dst[2] as u32 >> 3),
453            (src[0] as u32) << 8 | src[1] as u32,
454        );
455
456        Ok(())
457    }
458
459    #[test]
460    fn test_3() -> Result<()> {
461        let mut dst = [0u8; 3];
462        let src = [0x47, 0x9c];
463
464        let exp_pixel_fmt = PixelFormat::Rgb888;
465        let mut pixel_fmt = PixelFormat::Rgb565;
466
467        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
468
469        assert_eq!(pixel_fmt, exp_pixel_fmt);
470        assert_eq!(
471            ((dst[0] as u32 >> 3) << 11) | ((dst[1] as u32 >> 2) << 5) | (dst[2] as u32 >> 3),
472            (src[0] as u32) << 8 | src[1] as u32,
473        );
474
475        Ok(())
476    }
477
478    #[test]
479    fn test_4() -> Result<()> {
480        let mut dst = [0u8; 3];
481        let src = [0x46, 0xf3, 0xe5];
482
483        let exp_pixel_fmt = PixelFormat::Rgb888;
484        let mut pixel_fmt = PixelFormat::Bgr888;
485
486        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
487
488        assert_eq!(pixel_fmt, exp_pixel_fmt);
489        assert_eq!(
490            ((dst[2] as u32) << 16) | ((dst[1] as u32) << 8) | (dst[0] as u32),
491            ((src[0] as u32) << 16) | ((src[1] as u32) << 8) | (src[2] as u32),
492        );
493
494        Ok(())
495    }
496
497    #[test]
498    fn test_5() -> Result<()> {
499        let mut dst = [0u8; 3];
500        let src = [0x23, 0xc8];
501
502        let exp_pixel_fmt = PixelFormat::Rgb888;
503        let mut pixel_fmt = PixelFormat::Bgr555;
504
505        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
506
507        assert_eq!(pixel_fmt, exp_pixel_fmt);
508        assert_eq!(
509            ((dst[2] as u32 >> 3) << 10) | ((dst[1] as u32 >> 3) << 5) | (dst[0] as u32 >> 3),
510            (src[0] as u32) << 8 | src[1] as u32,
511        );
512
513        Ok(())
514    }
515
516    #[test]
517    fn test_6() -> Result<()> {
518        let mut dst = [0u8; 3];
519        let src = [0x47, 0x88];
520
521        let exp_pixel_fmt = PixelFormat::Rgb888;
522        let mut pixel_fmt = PixelFormat::Bgr565;
523
524        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
525
526        assert_eq!(pixel_fmt, exp_pixel_fmt);
527        assert_eq!(
528            ((dst[2] as u32 >> 3) << 11) | ((dst[1] as u32 >> 2) << 5) | (dst[0] as u32 >> 3),
529            (src[0] as u32) << 8 | src[1] as u32,
530        );
531
532        Ok(())
533    }
534
535    #[test]
536    fn test_7() -> Result<()> {
537        let mut dst = [0u8; 3];
538        let src = [0x47, 0x88];
539
540        let exp_pixel_fmt = PixelFormat::Rgb888;
541        let mut pixel_fmt = PixelFormat::Ag88;
542
543        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
544
545        assert_eq!(pixel_fmt, exp_pixel_fmt);
546        assert_eq!(dst[0], src[1]);
547
548        Ok(())
549    }
550
551    #[test]
552    fn test_8() -> Result<()> {
553        let mut dst = [0u8; 3];
554        let src = [0x47, 0x88];
555
556        let exp_pixel_fmt = PixelFormat::Rgb888;
557        let mut pixel_fmt = PixelFormat::Ga88;
558
559        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
560
561        assert_eq!(pixel_fmt, exp_pixel_fmt);
562        assert_eq!(dst[0], src[0]);
563
564        Ok(())
565    }
566
567    #[test]
568    fn test_9() -> Result<()> {
569        let mut dst = [0u8; 3];
570        let src = [0x46, 0xf3, 0xe5, 0xf0];
571
572        let exp_pixel_fmt = PixelFormat::Rgb888;
573        let mut pixel_fmt = PixelFormat::Rgba8888;
574
575        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
576
577        assert_eq!(pixel_fmt, exp_pixel_fmt);
578        assert_eq!(dst.as_ref(), &src[..3]);
579
580        Ok(())
581    }
582
583    #[test]
584    fn test_10() -> Result<()> {
585        let mut dst = [0u8; 3];
586        let src = [0x46, 0xf3, 0xe5, 0xf0];
587
588        let exp_pixel_fmt = PixelFormat::Rgb888;
589        let mut pixel_fmt = PixelFormat::Argb8888;
590
591        pixel_fmt.normalize(dst.as_mut(), src.as_ref(), 1, 1)?;
592
593        assert_eq!(pixel_fmt, exp_pixel_fmt);
594        assert_eq!(dst.as_ref(), &src[1..]);
595
596        Ok(())
597    }
598}