use super::{b64, Basic}; use crate::Image; use std::borrow::Cow; use std::fmt::{Debug, Display, Formatter, Result, Write}; /// Outputs [Kitty Graphics Protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol) encoded data. pub struct Kitty, const N: usize>(pub Image); impl, const N: usize> std::ops::Deref for Kitty { type Target = Image; fn deref(&self) -> &Self::Target { &self.0 } } impl, const N: usize> Display for Kitty where [(); N]: Basic, { fn fmt(&self, f: &mut Formatter<'_>) -> Result { self.write(f) } } impl, const N: usize> Debug for Kitty where [(); N]: Basic, { fn fmt(&self, f: &mut Formatter<'_>) -> Result { self.write(f) } } impl, const N: usize> Kitty { /// Write out kitty gfx data. pub fn write(&self, to: &mut impl Write) -> Result where [(); N]: Basic, { macro_rules! cast { ($n:literal) => { ( Cow::Owned( , 3>>::from({ // SAFETY: ... unsafe { self.as_ref().trans::<$n>() } }) .take_buffer() .to_vec(), ), "24", ) }; } let (bytes, dtype) = { match N { 1 => cast!(1), 2 => cast!(2), 3 => (Cow::from(self.bytes()), "24"), 4 => (Cow::from(self.bytes()), "32"), _ => unreachable!(), } }; let (w, h) = (self.width(), self.height()); let enc = b64::encode(&bytes); let mut chunks = enc .as_bytes() .chunks(4096) // SAFETY: b64 .map(|x| unsafe { std::str::from_utf8_unchecked(x) }); let last = chunks.len(); const H: &str = "_G"; const MORE: &str = "m"; const DISPLAY: char = 'T'; const ACTION: char = 'a'; const DATATYPE: char = 'f'; const TYPE: char = 't'; const DIRECT: char = 'd'; const E: &str = r"\"; let payload = chunks.next().unwrap(); let more = (last > 1) as u8; write!(to, "{H}{DATATYPE}={dtype},{ACTION}={DISPLAY},{TYPE}={DIRECT},s={w},v={h},{MORE}={more};{payload}{E}")?; for (payload, i) in chunks.zip(2..) { let more = (i != last) as u8; write!(to, "{H}{MORE}={more};{payload}{E}")?; } Ok(()) } } #[test] fn test() { let x = Image::<_, 3>::open("tdata/cat.png"); use std::hash::Hasher; let mut h = std::hash::DefaultHasher::new(); h.write(Kitty(x).to_string().as_bytes()); assert_eq!(h.finish(), 0x1cc13114bcf3cc3); }