Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,32 @@ use sixel_tokenizer::{ColorCoordinateSystem, Parser};

#[derive(Debug, Clone)]
pub struct SixelImage {
dcs: DCS,
ra: Option<RA>,
color_registers: BTreeMap<u16, SixelColor>,
pixels: Vec<Vec<Pixel>>,
}

#[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<usize>,
pv: Option<usize>,
}

impl SixelImage {
/// Constructs a new `SixelImage` out of an existing slice of serialized sixel bytes
pub fn new(bytes: &[u8]) -> Result<Self, &'static str> {
Expand All @@ -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
}
Expand Down
30 changes: 22 additions & 8 deletions src/sixel_deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RA>,
color_registers: BTreeMap<u16, SixelColor>,
current_color: u16,
sixel_cursor_y: usize,
Expand All @@ -14,12 +16,13 @@ pub struct SixelDeserializer {
max_height: Option<usize>,
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,
Expand All @@ -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
Expand All @@ -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,
})
Expand All @@ -71,16 +77,21 @@ 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);
}
if let Some(ph) = ph {
self.pad_lines_horizontally(ph);
}
}
self.ra = Some(RA {
pan,
pad,
ph,
pv,
});
}
SixelEvent::Data { byte } => {
self.make_sure_six_lines_exist_after_cursor();
Expand All @@ -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 => {
Expand Down
28 changes: 22 additions & 6 deletions src/sixel_serializer.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
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<RA>,
color_registers: &'a BTreeMap<u16, SixelColor>,
pixels: &'a Vec<Vec<Pixel>>,
}

impl <'a>SixelSerializer <'a>{
pub fn new(color_registers: &'a BTreeMap<u16, SixelColor>, pixels: &'a Vec<Vec<Pixel>>) -> Self {
pub fn new(dcs: &'a DCS, ra: &'a Option<RA>, color_registers: &'a BTreeMap<u16, SixelColor>, pixels: &'a Vec<Vec<Pixel>>) -> 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);
serialized_image
}
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 {
Expand Down