1use super::{
12 DitherConf, PixelFormat, SixelEncodePolicy, SixelError, SixelMean, SixelOutput, SixelQuality,
13 SixelResult, SixelSplit,
14};
15use crate::{ConstDefault, Dither, String, ToString, Vec};
16
17#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
31pub struct Sixel<'a> {
32 pub bytes: Option<&'a [u8]>,
34 pub width: i32,
36 pub height: i32,
38 pub format: PixelFormat,
40 pub dither: Dither,
42 pub split: SixelSplit,
44 pub mean: SixelMean,
46 pub quality: SixelQuality,
48}
49
50impl ConstDefault for Sixel<'_> {
51 const DEFAULT: Self = Self {
52 bytes: None,
53 width: 0,
54 height: 0,
55 format: PixelFormat::DEFAULT,
56 dither: Dither::DEFAULT,
57 split: SixelSplit::DEFAULT,
58 mean: SixelMean::DEFAULT,
59 quality: SixelQuality::DEFAULT,
60 };
61}
62
63#[rustfmt::skip]
65impl<'bytes> Sixel<'bytes> {
66 #[must_use]
68 pub const fn new() -> Self { Self::DEFAULT }
69
70 #[must_use]
72 pub const fn with_bytes(bytes: &'bytes [u8]) -> Self {
73 Self::DEFAULT.bytes(bytes)
74 }
75
76 #[must_use]
78 pub const fn with_size(width: i32, height: i32) -> Self {
79 Self::DEFAULT.size(width, height)
80 }
81
82 #[must_use]
84 pub const fn with_bytes_size(bytes: &'bytes [u8], width: i32, height: i32) -> Self {
85 Self::DEFAULT.bytes(bytes).size(width, height)
86 }
87
88 pub fn build(self) -> SixelResult<String> {
98 if self.width == 0 || self.height == 0 {
99 return Err(SixelError::BadInput);
100 }
101 if let Some(bytes) = self.bytes {
102 if bytes.len() < self.format.required_bytes(self.width, self.height) {
103 Err(SixelError::BadInput)
104 } else {
105 sixel_string(bytes, self.width, self.height,
106 self.format, self.dither, self.split, self.mean, self.quality)
107 }
108 } else {
109 Err(SixelError::BadInput)
110 }
111 }
112
113 #[must_use]
117 pub const fn bytes(mut self, bytes: &'bytes [u8]) -> Self {
118 self.bytes = Some(bytes); self
119 }
120 #[must_use]
122 pub const fn width(mut self, width: i32) -> Self {
123 self.width = width; self
124 }
125 #[must_use]
127 pub const fn height(mut self, height: i32) -> Self {
128 self.height = height; self
129 }
130 #[must_use]
132 pub const fn size(mut self, width: i32, height: i32) -> Self {
133 self.width = width;
134 self.height = height;
135 self
136 }
137
138 #[must_use]
142 pub const fn format(mut self, format: PixelFormat) -> Self {
143 self.format = format; self
144 }
145 #[must_use]
147 pub const fn dither(mut self, dither: Dither) -> Self {
148 self.dither = dither; self
149 }
150 #[must_use]
152 pub const fn split(mut self, split: SixelSplit) -> Self {
153 self.split = split; self
154 }
155 #[must_use]
157 pub const fn mean(mut self, mean: SixelMean) -> Self {
158 self.mean = mean; self
159 }
160 #[must_use]
162 pub const fn quality(mut self, quality: SixelQuality) -> Self {
163 self.quality = quality; self
164 }
165}
166
167macro_rules! add_method {
168 ($fn:ident, $field:ident, $variant:expr) => {
169 #[doc = concat!["Sets the `", stringify!($field), "` field to [`", stringify!($variant), "`]."]]
170 #[must_use]
171 pub const fn $fn(mut self) -> Self {
172 self.$field = $variant;
173 self
174 }
175 };
176}
177#[rustfmt::skip]
179impl Sixel<'_> {
180 add_method![format_rgb555, format, PixelFormat::RGB555];
181 add_method![format_rgb565, format, PixelFormat::RGB565];
182 add_method![format_rgb888, format, PixelFormat::RGB888];
183 add_method![format_bgr555, format, PixelFormat::BGR555];
184
185 add_method![format_bgr565, format, PixelFormat::BGR565];
186 add_method![format_bgr888, format, PixelFormat::BGR888];
187 add_method![format_argb8888, format, PixelFormat::ARGB8888];
188 add_method![format_rgba8888, format, PixelFormat::RGBA8888];
189 add_method![format_abgr8888, format, PixelFormat::ABGR8888];
190 add_method![format_bgra8888, format, PixelFormat::BGRA8888];
191 add_method![format_g1, format, PixelFormat::G1];
192 add_method![format_g2, format, PixelFormat::G2];
193 add_method![format_g4, format, PixelFormat::G4];
194 add_method![format_g8, format, PixelFormat::G8];
195 add_method![format_ag88, format, PixelFormat::AG88];
196 add_method![format_ga88, format, PixelFormat::GA88];
197 add_method![format_pal1, format, PixelFormat::PAL1];
198 add_method![format_pal2, format, PixelFormat::PAL2];
199 add_method![format_pal4, format, PixelFormat::PAL4];
200 add_method![format_pal8, format, PixelFormat::PAL8];
201 add_method![split_auto, split, SixelSplit::Auto];
203 add_method![split_norm, split, SixelSplit::Norm];
204 add_method![split_lum, split, SixelSplit::Lum];
205 add_method![mean_auto, mean, SixelMean::Auto];
207 add_method![mean_center, mean, SixelMean::Center];
208 add_method![mean_colors, mean, SixelMean::Colors];
209 add_method![mean_pixels, mean, SixelMean::Pixels];
210 add_method![dither_auto, dither, Dither::Auto];
212 add_method![dither_none, dither, Dither::None];
213 add_method![dither_atkinson, dither, Dither::Atkinson];
214 add_method![dither_fs, dither, Dither::FS];
215 add_method![dither_jajuni, dither, Dither::JaJuNi];
216 add_method![dither_stucki, dither, Dither::Stucki];
217 add_method![dither_burkes, dither, Dither::Burkes];
218 add_method![dither_adither, dither, Dither::ADither];
219 add_method![dither_xdither, dither, Dither::XDither];
220 add_method![quality_auto, quality, SixelQuality::Auto];
222 add_method![quality_high, quality, SixelQuality::High];
223 add_method![quality_low, quality, SixelQuality::Low];
224 add_method![quality_full, quality, SixelQuality::Full];
225 add_method![quality_high_color, quality, SixelQuality::HighColor];
226}
227
228#[expect(clippy::too_many_arguments)]
247fn sixel_string(
248 bytes: &[u8],
249 width: i32,
250 height: i32,
251 pixel_format: PixelFormat,
252 dither: Dither,
253 split: SixelSplit,
254 mean: SixelMean,
255 quality: SixelQuality,
256) -> SixelResult<String> {
257 let mut sixel_data: Vec<u8> = Vec::new(); let mut sixel_output = SixelOutput::new(&mut sixel_data);
260 sixel_output.set_encode_policy(SixelEncodePolicy::Auto);
261 let mut dither_conf = DitherConf::new(256).unwrap();
262
263 dither_conf.set_optimize_palette(true);
264
265 dither_conf.initialize(bytes, width, height, pixel_format, split, mean, quality)?;
266 dither_conf.set_pixel_format(pixel_format);
267 dither_conf.set_diffusion_method(dither);
268
269 let mut bytes = bytes.to_vec();
270 sixel_output.encode(&mut bytes, width, height, 0, &mut dither_conf)?;
271
272 Ok(String::from_utf8_lossy(&sixel_data).to_string())
273}