use std::fmt::Write as _;
use super::base64;
use super::deflate;
#[cfg(test)]
use super::render::Image;
#[cfg(test)]
pub(crate) fn encode(image: &Image) -> String {
let mut rgba = Vec::with_capacity(image.pixels.len() * 4);
for pixel in &image.pixels {
match pixel {
Some((r, g, b)) => rgba.extend_from_slice(&[*r, *g, *b, 255]),
None => rgba.extend_from_slice(&[0, 0, 0, 0]),
}
}
encode_rgba(image.width, image.height, (0, 0), &rgba, None)
}
pub(crate) fn encode_rgba(
width: usize,
height: usize,
placement: (usize, usize),
rgba: &[u8],
id: Option<u32>,
) -> String {
if width == 0 || height == 0 {
return String::new();
}
let payload = base64::encode(&deflate::zlib_compress(rgba));
let mut out = String::new();
let mut chunks = payload.as_bytes().chunks(4096).peekable();
let mut first = true;
while let Some(chunk) = chunks.next() {
let more = u8::from(chunks.peek().is_some());
out.push_str("\x1b_G");
if first {
match id {
Some(id) => {
let _ = write!(out, "a=t,f=32,o=z,s={width},v={height},i={id},q=2,");
}
None => {
let _ = write!(out, "a=T,f=32,o=z,s={width},v={height},");
if placement.0 > 0 && placement.1 > 0 {
let _ = write!(out, "c={},r={},", placement.0, placement.1);
}
out.push_str("C=1,q=2,");
}
}
first = false;
}
let _ = write!(out, "m={more};");
out.push_str(std::str::from_utf8(chunk).expect("base64 is ASCII"));
out.push_str("\x1b\\");
}
out
}
#[cfg(test)]
#[path = "tests/kitty_tests.rs"]
mod tests;