sixel_image/
sixel_deserializer.rs1use std::iter;
2use std::collections::BTreeMap;
3use sixel_tokenizer::SixelEvent;
4
5use crate::{SixelColor, SixelImage, Pixel};
6
7#[derive(Debug, Clone)]
8pub struct SixelDeserializer {
9 color_registers: BTreeMap<u16, SixelColor>,
10 current_color: u16,
11 sixel_cursor_y: usize,
12 sixel_cursor_x: usize,
13 pixels: Vec<Vec<Pixel>>,
14 max_height: Option<usize>,
15 stop_parsing: bool,
16 got_dcs: bool,
17 transparent_background: bool,
18}
19
20impl SixelDeserializer {
21 pub fn new() -> Self {
22 SixelDeserializer {
23 color_registers: BTreeMap::new(),
24 current_color: 0, sixel_cursor_y: 0,
26 sixel_cursor_x: 0,
27 pixels: vec![vec![]], max_height: None,
29 stop_parsing: false,
30 got_dcs: false,
31 transparent_background: false,
32 }
33 }
34 pub fn max_height(mut self, max_height: usize) -> Self {
37 self.max_height = Some(max_height);
38 self
39 }
40 pub fn create_image(&mut self) -> Result<SixelImage, &'static str> {
42 if !self.got_dcs {
43 return Err("Corrupted image sequence");
44 }
45 let pixels = std::mem::take(&mut self.pixels);
46 let color_registers = std::mem::take(&mut self.color_registers);
47 Ok(SixelImage {
48 pixels,
49 color_registers,
50 })
51 }
52 pub fn handle_event(&mut self, event: SixelEvent) -> Result<(), &'static str> {
54 if !self.got_dcs && !matches!(event, SixelEvent::Dcs { .. }) {
55 return Err("Corrupted image sequence");
56 }
57 if self.stop_parsing {
58 return Ok(());
59 }
60 match event {
61 SixelEvent::ColorIntroducer { color_coordinate_system, color_number } => {
62 match color_coordinate_system {
63 Some(color_coordinate_system) => {
64 let color = SixelColor::from(color_coordinate_system);
66 self.color_registers.insert(color_number, color);
67 },
68 None => {
69 self.current_color = color_number;
71 }
72 }
73 }
74 SixelEvent::RasterAttribute { pan: _, pad: _, ph, pv } => {
75 if !self.transparent_background {
77 if let Some(pv) = pv {
78 self.pad_lines_vertically(pv);
79 }
80 if let Some(ph) = ph {
81 self.pad_lines_horizontally(ph);
82 }
83 }
84 }
85 SixelEvent::Data { byte } => {
86 self.make_sure_six_lines_exist_after_cursor();
87 self.add_sixel_byte(byte, 1);
88 self.sixel_cursor_x += 1;
89 }
90 SixelEvent::Repeat { repeat_count, byte_to_repeat } => {
91 self.make_sure_six_lines_exist_after_cursor();
92 self.add_sixel_byte(byte_to_repeat, repeat_count);
93 self.sixel_cursor_x += repeat_count;
94 }
95 SixelEvent::Dcs { macro_parameter: _, transparent_background, horizontal_pixel_distance: _ } => {
96 self.got_dcs = true;
97 if transparent_background == Some(1) {
98 self.transparent_background = true;
99 }
100 }
101 SixelEvent::GotoBeginningOfLine => {
102 self.sixel_cursor_x = 0;
103 }
104 SixelEvent::GotoNextLine => {
105 if let Some(max_height) = self.max_height {
106 if self.sixel_cursor_y + 12 > max_height { self.stop_parsing = true;
108 return Ok(());
109 }
110 }
111 self.sixel_cursor_y += 6;
112 self.sixel_cursor_x = 0;
113 }
114 SixelEvent::UnknownSequence(_) => {
115 return Err("Corrupted Sixel sequence");
116 }
117 SixelEvent::End => {}
118 }
119 Ok(())
120 }
121 fn make_sure_six_lines_exist_after_cursor(&mut self) {
122 let lines_to_add = (self.sixel_cursor_y + 6).saturating_sub(self.pixels.len());
123 for _ in 0..lines_to_add {
124 self.pixels.push(vec![]);
125 }
126 }
127 fn add_sixel_byte(&mut self, byte: u8, repeat_count: usize) {
128 let mut pixel_line_index_in_sixel = 0;
129 for bit in SixelPixelIterator::new(byte.saturating_sub(63)) {
130 let current_line = self.pixels.get_mut(self.sixel_cursor_y + pixel_line_index_in_sixel).unwrap();
131 let new_pixel = Pixel {
132 on: bit,
133 color: self.current_color
134 };
135 for i in 0..repeat_count {
136 match current_line.get_mut(self.sixel_cursor_x + i) {
137 Some(pixel_in_current_position) if bit => {
138 let _ = std::mem::replace(pixel_in_current_position, new_pixel);
139 },
140 None => {
141 current_line.push(new_pixel);
142 }
143 _ => {} }
145 }
146 pixel_line_index_in_sixel += 1;
147 }
148 }
149 fn pad_lines_vertically(&mut self, pad_until: usize) {
150 let empty_pixel = Pixel {
151 on: true,
152 color: self.current_color
153 };
154 if self.pixels.len() < pad_until {
155 let empty_line = vec![empty_pixel; pad_until];
156 let lines_to_pad = pad_until - self.pixels.len();
157 let line_padding = iter::repeat(empty_line).take(lines_to_pad);
158 self.pixels.extend(line_padding);
159 }
160 }
161 fn pad_lines_horizontally(&mut self, pad_until: usize) {
162 let empty_pixel = Pixel {
163 on: true,
164 color: self.current_color
165 };
166 for pixel_line in self.pixels.iter_mut() {
167 if pixel_line.len() < pad_until {
168 let pixel_count_to_pad = pad_until - pixel_line.len();
169 let pixel_padding = iter::repeat(empty_pixel).take(pixel_count_to_pad);
170 pixel_line.extend(pixel_padding);
171 }
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy)]
177struct SixelPixelIterator {
178 sixel_byte: u8,
179 current_mask: u8,
180}
181impl SixelPixelIterator {
182 pub fn new(sixel_byte: u8) -> Self {
183 SixelPixelIterator { sixel_byte, current_mask: 1 }
184 }
185}
186impl Iterator for SixelPixelIterator {
187 type Item = bool;
188 fn next(&mut self) -> Option<Self::Item> {
189 let bit = self.sixel_byte & self.current_mask == self.current_mask;
192 self.current_mask <<= 1;
193 if self.current_mask == 128 {
194 None
195 } else {
196 Some(bit)
197 }
198 }
199}
200