From 5d5684903ea0228fc0fcfa021f6a6ab9b4b2a2bb Mon Sep 17 00:00:00 2001 From: Andrew Dirksen Date: Wed, 1 Mar 2023 17:47:17 -0800 Subject: [PATCH 1/2] Add constructors for `Pixel` so users can use the `SixelSerializer`. fixes https://github.com/zellij-org/sixel-image/issues/1 --- Cargo.toml | 5 +++++ src/lib.rs | 11 ++++++++++ src/tests.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d43706f..3f5d755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,8 @@ edition = "2021" [dependencies] sixel-tokenizer = "0.1.0" + +[dev-dependencies] +image = "0.24.5" +itertools = "0.10.5" + diff --git a/src/lib.rs b/src/lib.rs index 99e14d9..2e28045 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,17 @@ pub struct Pixel { color: u16, } +impl Pixel { + pub fn new(color: u16) -> Self { + Pixel { on: true, color } + } + + pub const OFF: Pixel = Pixel { + on: false, + color: 0, + }; +} + impl fmt::Debug for Pixel { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.on { diff --git a/src/tests.rs b/src/tests.rs index 545f2a7..2eeee8d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,4 +1,4 @@ -use crate::SixelImage; +use crate::{Pixel, SixelColor, SixelImage, SixelSerializer}; fn remove_whitespace(s: &str) -> String { let mut s = s.to_string(); @@ -236,3 +236,58 @@ fn corrupted_image() { "; assert!(SixelImage::new(sample.as_bytes()).is_err()); } + +#[test] +fn img_to_sixel() { + let img = image::RgbaImage::from_fn(64, 64, |x, y| { + image::Rgba([ + ((x + 128) % u8::MAX as u32) as u8, + ((y + 128) % u8::MAX as u32) as u8, + (u8::MAX / 2) as u8, + 255, + ]) + }); + println!("{}", render_sixel(&img)); // run with `cargo test -- --nocapture` to see the output +} + +fn render_sixel(img: &image::RgbaImage) -> String { + use std::collections::{BTreeMap, HashMap, HashSet}; + + use itertools::Itertools; + + let colors: HashMap<[u8; 3], u16> = img + .pixels() + .map(|p| [p[0], p[1], p[2]].map(compress)) + .collect::>() // dedup + .into_iter() + .enumerate() + .map(|(i, c)| (c, wrapping_into(i))) + .collect(); + + let color_registers: BTreeMap = colors + .iter() + .map(|(&c, &i)| (i, SixelColor::Rgb(c[0], c[1], c[2]))) + .collect(); + + let pixels: Vec> = img + .pixels() + .map(|p| { + let c = [p[0], p[1], p[2]].map(compress); + Pixel::new(colors[&c]) + }) + .chunks(img.width() as usize) + .into_iter() + .map(|c| c.collect()) + .collect(); + + SixelSerializer::new(&color_registers, &pixels).serialize() +} + +fn wrapping_into(u: usize) -> u16 { + (u % u16::MAX as usize) as u16 +} + +/// compress a color value from the range [0, 255] to the range [0, 100] +fn compress(a: u8) -> u8 { + (a as u16 * 100 / 255) as u8 +} From 52f6c1c71f254f6b245c6a14572d6e2401c5ff57 Mon Sep 17 00:00:00 2001 From: Andrew Dirksen Date: Thu, 2 Mar 2023 09:28:05 -0800 Subject: [PATCH 2/2] remove unnecessary integer cast from test --- src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests.rs b/src/tests.rs index 2eeee8d..875724f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -243,7 +243,7 @@ fn img_to_sixel() { image::Rgba([ ((x + 128) % u8::MAX as u32) as u8, ((y + 128) % u8::MAX as u32) as u8, - (u8::MAX / 2) as u8, + u8::MAX / 2, 255, ]) });