1use std::io::{self, Write};
16use nom::{self, IResult, Needed, digit};
17use {Format, CSI};
18use util::number;
19
20#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)]
21pub struct Map(pub u8);
22
23impl Map {
24 #[inline]
25 pub fn is_empty(&self) -> bool {
26 self.0 == 0
27 }
28
29 #[inline]
30 pub fn get(&self, index: u8) -> bool {
31 self.0 >> index & 1 == 1
32 }
33
34 #[inline]
35 pub fn set(&mut self, index: u8, value: bool) {
36 if value {
37 self.0 |= 1 << index;
38 }
39 else {
40 self.0 &= !(1 << index);
41 }
42 }
43}
44
45impl Format for Map {
46 #[inline]
47 fn fmt<W: Write>(&self, mut f: W) -> io::Result<()> {
48 f.write_all(&[self.0 + 0x3F])
49 }
50}
51
52#[derive(Eq, PartialEq, Copy, Clone, Debug)]
53pub struct Header {
54 pub aspect: (u32, u32),
55 pub background: bool,
56 pub grid: Option<u32>,
57}
58
59named!(pub header<Header>,
60 do_parse!(
61 args: call!(CSI::parameters) >>
62 char!('q') >>
63
64 (Header {
65 aspect: match arg!(args[0] => 0) {
66 1 => (2, 1),
67 2 => (5, 1),
68 3 | 4 => (3, 1),
69 5 | 6 => (2, 1),
70 7 | 8 | 9 => (1, 1),
71 _ => (2, 1),
72 },
73
74 background: match arg!(args[1] => 1) {
75 1 => false,
76 2 | _ => true,
77 },
78
79 grid: arg!(args[2])
80 })));
81
82impl Format for Header {
83 fn fmt<W: Write>(&self, mut f: W) -> io::Result<()> {
84 if self.aspect != (2, 1) {
85 try!(f.write_all(&[match self.aspect {
86 (5, 1) => b'2',
87 (3, 1) => b'3',
88 (1, 1) => b'9',
89 _ => b'0',
90 }]));
91 }
92
93 if !self.background {
94 try!(f.write_all(b";1"));
95 }
96
97 if let Some(grid) = self.grid {
98 if self.background {
99 try!(f.write_all(b";"));
100 }
101
102 try!(write!(f, "{}", grid));
103 }
104
105 f.write_all(b"q")
106 }
107}
108
109#[derive(Eq, PartialEq, Clone, Debug)]
110pub enum Sixel {
111 Value(Map),
112 Repeat(u32, Map),
113
114 Raster {
115 aspect: (u32, u32),
116 size: (u32, u32),
117 },
118
119 Enable(u32),
120 Define(u32, Color),
121 CarriageReturn,
122 LineFeed,
123}
124
125#[derive(Eq, PartialEq, Copy, Clone, Debug)]
126pub enum Color {
127 Hsl(u16, u8, u8),
128 Rgb(u8, u8, u8),
129 Rgba(u8, u8, u8, u8),
130}
131
132impl Format for Sixel {
133 fn fmt<W: Write>(&self, mut f: W) -> io::Result<()> {
134 match *self {
135 Sixel::Value(value) => {
136 try!(value.fmt(f.by_ref()));
137 }
138
139 Sixel::Repeat(times, value) => {
140 try!(write!(f, "!{}", times));
141 try!(value.fmt(f.by_ref()));
142 }
143
144 Sixel::Raster { aspect, size } => {
145 try!(write!(f, "\"{};{};{};{}", aspect.0, aspect.1, size.0, size.1));
146 }
147
148 Sixel::Enable(id) => {
149 try!(write!(f, "#{}", id));
150 }
151
152 Sixel::Define(id, color) => {
153 try!(write!(f, "#{};", id));
154
155 match color {
156 Color::Hsl(h, s, l) => {
157 try!(write!(f, "1;{};{};{}", h, l, s));
158 }
159
160 Color::Rgb(r, g, b) => {
161 try!(write!(f, "2;{};{};{}",
162 (r as f32 / 255.0 * 100.0) as u8,
163 (g as f32 / 255.0 * 100.0) as u8,
164 (b as f32 / 255.0 * 100.0) as u8));
165 }
166
167 Color::Rgba(r, g, b, a) => {
168 try!(write!(f, "3;{};{};{};{}", r, g, b, a));
169 }
170 }
171 }
172
173 Sixel::CarriageReturn => {
174 try!(f.write_all(b"$"));
175 }
176
177 Sixel::LineFeed => {
178 try!(f.write_all(b"-"));
179 }
180 }
181
182 Ok(())
183 }
184}
185
186pub fn parse(i: &[u8]) -> IResult<&[u8], Sixel> {
187 if let IResult::Done(rest, value) = value(i) {
188 IResult::Done(rest, Sixel::Value(value))
189 }
190 else {
191 inner(i)
192 }
193}
194
195named!(inner<Sixel>,
196 alt!(repeat | color | cr | lf | raster));
197
198fn value(i: &[u8]) -> IResult<&[u8], Map> {
199 const TABLE: [u8; 256] = [
200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
202 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
204 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
205 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
206 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
207 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
215 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
216 ];
217
218 if i.is_empty() {
219 return IResult::Incomplete(Needed::Size(1));
220 }
221
222 if TABLE[i[0] as usize] == 1 {
223 IResult::Done(&i[1..], Map(i[0] - 0x3F))
224 }
225 else {
226 IResult::Error(nom::ErrorKind::Custom(0))
227 }
228}
229
230named!(repeat<Sixel>,
231 do_parse!(
232 char!('!') >>
233 count: digit >>
234 value: value >>
235
236 (Sixel::Repeat(number(count), value))));
237
238named!(raster<Sixel>,
239 do_parse!(
240 char!('"') >>
241 args: call!(CSI::parameters) >>
242
243 (Sixel::Raster {
244 aspect: (arg!(args[0] => 0), arg!(args[1] => 0)),
245 size: (arg!(args[2] => 0), arg!(args[3] => 0)),
246 })));
247
248named!(color<Sixel>,
249 do_parse!(
250 char!('#') >>
251 id: digit >>
252
253 color: opt!(switch!(take!(3),
254 b";1;" => do_parse!(
255 h: digit >>
256 char!(';') >>
257 l: digit >>
258 char!(';') >>
259 s: digit >>
260
261 (Color::Hsl(number(h) as u16, number(s) as u8, number(l) as u8))) |
262
263 b";2;" => do_parse!(
264 r: digit >>
265 char!(';') >>
266 g: digit >>
267 char!(';') >>
268 b: digit >>
269
270 (Color::Rgb(
271 (number(r) as f32 / 100.0 * 255.0) as u8,
272 (number(g) as f32 / 100.0 * 255.0) as u8,
273 (number(b) as f32 / 100.0 * 255.0) as u8))) |
274
275 b";3;" => do_parse!(
276 r: digit >>
277 char!(';') >>
278 g: digit >>
279 char!(';') >>
280 b: digit >>
281 char!(';') >>
282 a: digit >>
283
284 (Color::Rgba(number(r) as u8, number(g) as u8, number(b) as u8, number(a) as u8))))) >>
285
286 (if let Some(color) = color {
287 Sixel::Define(number(id), color)
288 }
289 else {
290 Sixel::Enable(number(id))
291 })));
292
293named!(cr<Sixel>,
294 value!(Sixel::CarriageReturn, char!('$')));
295
296named!(lf<Sixel>,
297 value!(Sixel::LineFeed, char!('-')));
298
299pub mod shim {
300 pub use super::Sixel as T;
301 pub use super::Sixel::*;
302 pub use super::{Header, Map, Color};
303 pub use super::{parse, header};
304}
305
306#[cfg(test)]
307mod test {
308 mod parse {
309 use DEC::SIXEL::{self, parse, header};
310
311 macro_rules! test {
312 ($string:expr => $item:expr) => (
313 assert_eq!($item,
314 parse($string).unwrap().1);
315 );
316
317 ($ident:ident $string:expr => $item:expr) => (
318 assert_eq!($item,
319 $ident($string).unwrap().1);
320 );
321 }
322
323 #[test]
324 fn start() {
325 test!(header b"q" =>
326 SIXEL::Header { aspect: (2, 1), background: false, grid: None });
327
328 test!(header b"0q" =>
329 SIXEL::Header { aspect: (2, 1), background: false, grid: None });
330
331 test!(header b"1q" =>
332 SIXEL::Header { aspect: (2, 1), background: false, grid: None });
333
334 test!(header b"2q" =>
335 SIXEL::Header { aspect: (5, 1), background: false, grid: None });
336
337 test!(header b"3q" =>
338 SIXEL::Header { aspect: (3, 1), background: false, grid: None });
339
340 test!(header b"4q" =>
341 SIXEL::Header { aspect: (3, 1), background: false, grid: None });
342
343 test!(header b"5q" =>
344 SIXEL::Header { aspect: (2, 1), background: false, grid: None });
345
346 test!(header b"6q" =>
347 SIXEL::Header { aspect: (2, 1), background: false, grid: None });
348
349 test!(header b"7q" =>
350 SIXEL::Header { aspect: (1, 1), background: false, grid: None });
351
352 test!(header b"8q" =>
353 SIXEL::Header { aspect: (1, 1), background: false, grid: None });
354
355 test!(header b"9q" =>
356 SIXEL::Header { aspect: (1, 1), background: false, grid: None });
357
358 test!(header b";2q" =>
359 SIXEL::Header { aspect: (2, 1), background: true, grid: None });
360
361 test!(header b";;100q" =>
362 SIXEL::Header { aspect: (2, 1), background: false, grid: Some(100) });
363 }
364
365 #[test]
366 fn value() {
367 test!(b"?" =>
368 SIXEL::Value(SIXEL::Map(0b000000)));
369
370 test!(b"~" =>
371 SIXEL::Value(SIXEL::Map(0b111111)));
372 }
373
374 #[test]
375 fn map() {
376 let mut map = SIXEL::Map::default();
377
378 map.set(0, true);
379 assert_eq!(SIXEL::Map(1), map);
380
381 map.set(0, false);
382 assert_eq!(SIXEL::Map(0), map);
383
384 map.set(1, true);
385 assert_eq!(SIXEL::Map(2), map);
386 }
387 }
388
389 mod format {
390 use DEC::SIXEL::{self, parse};
391 use format;
392
393 macro_rules! test {
394 ($code:expr) => (
395 let item = $code;
396 assert_eq!(item, parse(&format(&item)).unwrap().1);
397 );
398 }
399
400 #[test]
401 fn repeat() {
402 test!(SIXEL::Repeat(4, SIXEL::Map::default()));
403 }
404 }
405}