mod sixel_deserializer;
mod sixel_serializer;
pub use sixel_deserializer::SixelDeserializer;
pub use sixel_serializer::SixelSerializer;
use sixel_tokenizer::{ColorCoordinateSystem, Parser};
use std::collections::BTreeMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct SixelImage {
pub color_registers: BTreeMap<u16, SixelColor>,
pub pixels: Vec<Vec<Pixel>>,
dcs: DCS,
ra: Option<RA>,
}
#[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 {
pub fn new(bytes: &[u8]) -> Result<Self, &'static str> {
let mut parser = Parser::new();
let mut sixel_deserializer = SixelDeserializer::new();
for byte in bytes {
let mut handle_result = Ok(());
parser.advance(&byte, |sixel_event| {
handle_result = sixel_deserializer.handle_event(sixel_event);
});
handle_result?
}
let sixel_image = sixel_deserializer.create_image();
sixel_image
}
pub fn pixel_size(&self) -> (usize, usize) {
let width = self
.pixels
.first()
.map(|first_line| first_line.len())
.unwrap_or(0);
let height = self.pixels.len();
(height, width)
}
pub fn serialize(&self) -> String {
let sixel_serializer =
SixelSerializer::new(&self.dcs, &self.ra, &self.color_registers, &self.pixels);
let serialized_image = sixel_serializer.serialize();
serialized_image
}
pub fn serialize_range(
&self,
start_x_index: usize,
start_y_index: usize,
width: usize,
height: usize,
) -> String {
let adjusted_ra = self.ra.as_ref().map(|ra| RA {
pan: ra.pan,
pad: ra.pad,
ph: Some(width),
pv: Some(height),
});
let sixel_serializer =
SixelSerializer::new(&self.dcs, &adjusted_ra, &self.color_registers, &self.pixels);
let serialized_image =
sixel_serializer.serialize_range(start_x_index, start_y_index, width, height);
serialized_image
}
pub fn cut_out(
&mut self,
start_x_index: usize,
start_y_index: usize,
width: usize,
height: usize,
) {
for row in self.pixels.iter_mut().skip(start_y_index).take(height) {
for pixel in row.iter_mut().skip(start_x_index).take(width) {
pixel.on = false;
}
}
}
}
#[derive(Clone, Copy)]
pub struct Pixel {
pub on: bool,
pub color: u16,
}
impl fmt::Debug for Pixel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.on {
write!(f, "{}", self.color)
} else {
write!(f, "x")
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SixelColor {
Rgb(u8, u8, u8), Hsl(u16, u8, u8), }
impl From<ColorCoordinateSystem> for SixelColor {
fn from(item: ColorCoordinateSystem) -> Self {
match item {
ColorCoordinateSystem::HLS(x, y, z) => SixelColor::Hsl(x as u16, y as u8, z as u8),
ColorCoordinateSystem::RGB(x, y, z) => SixelColor::Rgb(x as u8, y as u8, z as u8),
}
}
}
#[cfg(test)]
mod tests;