diff --git a/src/lib.rs b/src/lib.rs index 99e14d9..a3ebf99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,10 +35,32 @@ use sixel_tokenizer::{ColorCoordinateSystem, Parser}; #[derive(Debug, Clone)] pub struct SixelImage { + dcs: DCS, + ra: Option, color_registers: BTreeMap, pixels: Vec>, } +#[derive(Debug, Clone)] +pub struct DCS { + macro_parameter: u8, + transparent_bg: bool, +} + +impl Default for DCS { + fn default() -> Self { + DCS{ macro_parameter: 0, transparent_bg: false } + } +} + +#[derive(Debug, Clone)] +pub struct RA { + pan: usize, + pad: usize, + ph: Option, + pv: Option, +} + impl SixelImage { /// Constructs a new `SixelImage` out of an existing slice of serialized sixel bytes pub fn new(bytes: &[u8]) -> Result { @@ -62,14 +84,14 @@ impl SixelImage { } /// Serializes the whole image, returning a stringified sixel representation of it pub fn serialize(&self) -> String { - let sixel_serializer = SixelSerializer::new(&self.color_registers, &self.pixels); + let sixel_serializer = SixelSerializer::new(&self.dcs, &self.ra, &self.color_registers, &self.pixels); let serialized_image = sixel_serializer.serialize(); serialized_image } /// Serializes a specific rectangle of this image without manipulating the image itself, x/y /// coordinates as well as width height are in pixels pub fn serialize_range(&self, start_x_index: usize, start_y_index: usize, width: usize, height: usize) -> String { - let sixel_serializer = SixelSerializer::new(&self.color_registers, &self.pixels); + let sixel_serializer = SixelSerializer::new(&self.dcs, &self.ra, &self.color_registers, &self.pixels); let serialized_image = sixel_serializer.serialize_range(start_x_index, start_y_index, width, height); serialized_image } diff --git a/src/sixel_deserializer.rs b/src/sixel_deserializer.rs index 92ba43f..9bee5ae 100644 --- a/src/sixel_deserializer.rs +++ b/src/sixel_deserializer.rs @@ -2,10 +2,12 @@ use std::iter; use std::collections::BTreeMap; use sixel_tokenizer::SixelEvent; -use crate::{SixelColor, SixelImage, Pixel}; +use crate::{Pixel, SixelColor, SixelImage, DCS, RA}; #[derive(Debug, Clone)] pub struct SixelDeserializer { + dcs: DCS, + ra: Option, color_registers: BTreeMap, current_color: u16, sixel_cursor_y: usize, @@ -14,12 +16,13 @@ pub struct SixelDeserializer { max_height: Option, stop_parsing: bool, got_dcs: bool, - transparent_background: bool, } impl SixelDeserializer { pub fn new() -> Self { SixelDeserializer { + dcs: DCS { macro_parameter: 0, transparent_bg: false }, + ra: None, color_registers: BTreeMap::new(), current_color: 0, // this is totally undefined behaviour and seems like a free for all in general sixel_cursor_y: 0, @@ -28,7 +31,6 @@ impl SixelDeserializer { max_height: None, stop_parsing: false, got_dcs: false, - transparent_background: false, } } /// Provide a `max_height` value in pixels, all pixels beyond this max height will not be @@ -42,9 +44,13 @@ impl SixelDeserializer { if !self.got_dcs { return Err("Corrupted image sequence"); } + let dcs = std::mem::take(&mut self.dcs); + let ra = std::mem::take(&mut self.ra); let pixels = std::mem::take(&mut self.pixels); let color_registers = std::mem::take(&mut self.color_registers); Ok(SixelImage { + dcs, + ra, pixels, color_registers, }) @@ -71,9 +77,8 @@ impl SixelDeserializer { } } } - SixelEvent::RasterAttribute { pan: _, pad: _, ph, pv } => { - // we ignore pan/pad because (reportedly) no-one uses them - if !self.transparent_background { + SixelEvent::RasterAttribute { pan, pad, ph, pv } => { + if !self.dcs.transparent_bg { if let Some(pv) = pv { self.pad_lines_vertically(pv); } @@ -81,6 +86,12 @@ impl SixelDeserializer { self.pad_lines_horizontally(ph); } } + self.ra = Some(RA { + pan, + pad, + ph, + pv, + }); } SixelEvent::Data { byte } => { self.make_sure_six_lines_exist_after_cursor(); @@ -92,10 +103,13 @@ impl SixelDeserializer { self.add_sixel_byte(byte_to_repeat, repeat_count); self.sixel_cursor_x += repeat_count; } - SixelEvent::Dcs { macro_parameter: _, transparent_background, horizontal_pixel_distance: _ } => { + SixelEvent::Dcs { macro_parameter, transparent_background, horizontal_pixel_distance: _ } => { self.got_dcs = true; + if let Some(mp) = macro_parameter { + self.dcs.macro_parameter = mp; + } if transparent_background == Some(1) { - self.transparent_background = true; + self.dcs.transparent_bg = true; } } SixelEvent::GotoBeginningOfLine => { diff --git a/src/sixel_serializer.rs b/src/sixel_serializer.rs index 72e3d7b..f7448af 100644 --- a/src/sixel_serializer.rs +++ b/src/sixel_serializer.rs @@ -1,22 +1,27 @@ use std::collections::{HashMap, BTreeMap}; -use crate::{SixelColor, Pixel}; +use crate::{Pixel, SixelColor, DCS, RA}; pub struct SixelSerializer <'a>{ + dcs: &'a DCS, + ra: &'a Option, color_registers: &'a BTreeMap, pixels: &'a Vec>, } impl <'a>SixelSerializer <'a>{ - pub fn new(color_registers: &'a BTreeMap, pixels: &'a Vec>) -> Self { + pub fn new(dcs: &'a DCS, ra: &'a Option, color_registers: &'a BTreeMap, pixels: &'a Vec>) -> Self { SixelSerializer { + dcs, + ra, color_registers, pixels } } pub fn serialize(&self) -> String { let serialized_image = String::new(); - let serialized_image = self.serialize_empty_dcs(serialized_image); + let serialized_image = self.serialize_dcs(serialized_image); + let serialized_image = self.serialize_ra(serialized_image); let serialized_image = self.serialize_color_registers(serialized_image); let serialized_image = self.serialize_pixels(serialized_image, None, None, None, None); let serialized_image = self.serialize_end_event(serialized_image); @@ -24,14 +29,25 @@ impl <'a>SixelSerializer <'a>{ } pub fn serialize_range(&self, start_x_index: usize, start_y_index: usize, width: usize, height: usize) -> String { let serialized_image = String::new(); - let serialized_image = self.serialize_empty_dcs(serialized_image); + let serialized_image = self.serialize_dcs(serialized_image); + let serialized_image = self.serialize_ra(serialized_image); let serialized_image = self.serialize_color_registers(serialized_image); let serialized_image = self.serialize_pixels(serialized_image, Some(start_x_index), Some(start_y_index), Some(width), Some(height)); let serialized_image = self.serialize_end_event(serialized_image); serialized_image } - fn serialize_empty_dcs(&self, mut append_to: String) -> String { - append_to.push_str("\u{1b}Pq"); + fn serialize_dcs(&self, mut append_to: String) -> String { + append_to.push_str(&format!("\u{1b}P{mp};{bg};0q", mp = self.dcs.macro_parameter, bg = if self.dcs.transparent_bg {1} else {0})); + append_to + } + fn serialize_ra(&self, mut append_to: String) -> String { + if let Some(ra) = self.ra { + if let (Some(ph), Some(pv)) = (ra.ph, ra.pv) { + append_to.push_str(&format!("\"{pan};{pad};{ph};{pv}", pan = ra.pan, pad = ra.pad, ph = ph, pv = pv)); + } else { + append_to.push_str(&format!("\"{pan};{pad};", pan = ra.pan, pad = ra.pad)); + } + } append_to } fn serialize_color_registers(&self, mut append_to: String) -> String {