libsixel_rs/
dither.rs

1//! Types and functions for Sixel dither.
2
3use alloc::vec::Vec;
4
5use crate::{config::*, palette::*, pixel_format::PixelFormat, quant::*, Error, Result};
6
7pub mod method;
8
9/// Represents dither in a Sixel image.
10#[derive(Clone, Debug, Default, PartialEq)]
11#[repr(C)]
12pub struct SixelDither {
13    pub palette: Vec<u8>,
14    pub cache_table: Vec<u16>,
15    pub req_colors: usize,
16    pub ncolors: usize,
17    pub orig_colors: usize,
18    pub optimized: bool,
19    pub optimize_palette: bool,
20    pub complexion: i32,
21    pub body_only: bool,
22    pub method_for_largest: MethodForLargest,
23    pub method_for_rep: MethodForRep,
24    pub method_for_diffuse: MethodForDiffuse,
25    pub quality_mode: QualityMode,
26    pub key_color: i32,
27    pub pixel_format: PixelFormat,
28    pub height: usize,
29    pub width: usize,
30    pub depth: usize,
31}
32
33impl SixelDither {
34    /// Creates a new [SixelDither].
35    pub const fn new() -> Self {
36        Self {
37            palette: vec![],
38            cache_table: vec![],
39            req_colors: 256,
40            ncolors: 256,
41            orig_colors: 0,
42            key_color: -1,
43            optimized: false,
44            optimize_palette: false,
45            complexion: 1,
46            body_only: false,
47            method_for_largest: MethodForLargest::Norm,
48            method_for_rep: MethodForRep::CenterBox,
49            method_for_diffuse: MethodForDiffuse::Fs,
50            quality_mode: QualityMode::High,
51            pixel_format: PixelFormat::Rgb888,
52            height: 0,
53            width: 0,
54            depth: 0,
55        }
56    }
57
58    /// Creates a new [SixelDither] with the provided number of colors.
59    pub fn create(mut ncolors: i32) -> Result<Self> {
60        if ncolors == 0 || ncolors > 256 {
61            Err(Error::Dither(format!(
62                "sixel_dither_new: palette colors must be in range [1,256], have: {ncolors}"
63            )))
64        } else {
65            let quality_mode = if ncolors < 0 {
66                ncolors = 256;
67                QualityMode::HighColor
68            } else {
69                QualityMode::Low
70            };
71
72            Ok(Self {
73                palette: vec![],
74                cache_table: vec![],
75                req_colors: ncolors as usize,
76                ncolors: ncolors as usize,
77                orig_colors: 0,
78                key_color: -1,
79                optimized: false,
80                optimize_palette: false,
81                complexion: 1,
82                body_only: false,
83                method_for_largest: MethodForLargest::Norm,
84                method_for_rep: MethodForRep::CenterBox,
85                method_for_diffuse: MethodForDiffuse::Fs,
86                quality_mode,
87                pixel_format: PixelFormat::Rgb888,
88                height: 0,
89                width: 0,
90                depth: 0,
91            })
92        }
93    }
94
95    /// Creates a new [SixelDither] from a predefined palette.
96    pub fn get(builtin_dither: BuiltinPalette) -> Result<Self> {
97        let (ncolors, palette, key_color) = match builtin_dither {
98            BuiltinPalette::MonoDark => (2, PAL_MONO_DARK.as_ref(), 0),
99            BuiltinPalette::MonoLight => (2, PAL_MONO_LIGHT.as_ref(), 0),
100            BuiltinPalette::Xterm16 => (16, PAL_XTERM256.as_ref(), -1),
101            BuiltinPalette::Xterm256 => (256, PAL_XTERM256.as_ref(), -1),
102            BuiltinPalette::Vt340Mono => (16, PAL_VT340_MONO.as_ref(), -1),
103            BuiltinPalette::Vt340Color => (16, PAL_VT340_COLOR.as_ref(), -1),
104            BuiltinPalette::G1 => (2, PAL_GRAY_1BIT.as_ref(), -1),
105            BuiltinPalette::G2 => (4, PAL_GRAY_2BIT.as_ref(), -1),
106            BuiltinPalette::G4 => (16, PAL_GRAY_4BIT.as_ref(), -1),
107            BuiltinPalette::G8 => (256, PAL_GRAY_8BIT.as_ref(), -1),
108        };
109
110        let mut dither = Self::create(ncolors)?;
111
112        dither.palette = palette.into();
113        dither.key_color = key_color;
114        dither.optimized = true;
115        dither.optimize_palette = false;
116
117        Ok(dither)
118    }
119
120    /// Initializes the [SixelDither].
121    pub fn initialize(
122        &mut self,
123        data: &[u8],
124        width: usize,
125        height: usize,
126        palette_config: PaletteConfig,
127    ) -> Result<()> {
128        let mut normalized_pixels = vec![0u8; data.len()];
129
130        self.pixel_format = palette_config.pixel_format;
131
132        let input_pixels = match self.pixel_format {
133            PixelFormat::Rgb888 => data,
134            _ => {
135                self.pixel_format
136                    .normalize(normalized_pixels.as_mut(), data, width, height)?;
137
138                normalized_pixels.as_ref()
139            }
140        };
141
142        self.method_for_largest = palette_config.method_for_largest;
143        self.method_for_rep = palette_config.method_for_rep;
144        self.quality_mode = palette_config.quality_mode;
145
146        let buf = self.make_palette(input_pixels)?;
147
148        let palette_len = self.ncolors.saturating_mul(3);
149
150        let dither_palette_len = palette_len;
151        let buf_len = buf.len();
152
153        if palette_len > dither_palette_len || palette_len > buf_len {
154            Err(Error::Dither(format!("invalid palette length, palette: {dither_palette_len}, buffer: {buf_len}, have: {palette_len}")))
155        } else {
156            #[cfg(feature = "std")]
157            println!(
158                "palette len: {}, buf len: {}",
159                self.palette.len(),
160                buf.len()
161            );
162            self.palette[..palette_len].copy_from_slice(&buf[..palette_len]);
163            self.optimized = true;
164
165            if self.orig_colors <= self.ncolors {
166                self.method_for_diffuse = MethodForDiffuse::None;
167            }
168
169            Ok(())
170        }
171    }
172
173    /// Apply the palette to the [SixelDither].
174    pub fn apply_palette(&mut self, pixels: &[u8], width: usize, height: usize) -> Result<Vec<u8>> {
175        // if quality_mode is full, do not use palette caching
176        if self.quality_mode == QualityMode::Full {
177            self.optimized = false;
178        }
179
180        if self.cache_table.is_empty()
181            && self.optimized
182            && self.palette != PAL_MONO_DARK
183            && self.palette != PAL_MONO_LIGHT
184        {
185            self.cache_table = vec![0u16; 1 << (3 * 5)];
186        }
187
188        let mut input_pixels: Vec<u8> = if self.pixel_format != PixelFormat::Rgb888 {
189            let mut normalized_pixels = vec![0u8; width * height * 3];
190            self.pixel_format
191                .normalize(normalized_pixels.as_mut(), pixels, width, height)?;
192            normalized_pixels
193        } else {
194            pixels.into()
195        };
196
197        self.width = width;
198        self.height = height;
199        self.depth = 3;
200
201        #[cfg(feature = "std")]
202        println!("pixel len: {}", input_pixels.len());
203
204        self.quant_apply_palette(input_pixels.as_mut())
205    }
206}