emsquid / pic

Preview Image in CLI.
MIT License
57 stars 4 forks source link

Support kitty remote pixel transfer #10

Open bogzbonny opened 1 year ago

bogzbonny commented 1 year ago

As far as I can tell pic currently has the best system for interfacing with kitty image protocol as it allows for handling of kitty image ids... hence it's my fav rust cui image viewing library!

One things that's missing is remote pixel transfer. This is cool for a few reasons, but I'm most interested in remote viewing such that temp-file artifacts aren't left around (also good for SSHing)

https://sw.kovidgoyal.net/kitty/graphics-protocol/#transferring-pixel-data

viuer implemented it reasonably well here https://github.com/atanunq/viuer/blob/master/src/printer/kitty.rs#L154

Here is snippet of some of my adapted code (which you're welcome to use in implementing this feature if you desire).

    pub fn render_new_img(
        &mut self, buf: &[u8], buf_width: u32, buf_height: u32, id: u32, cols: u16, rows: u16,
    ) -> bool {
        let encoded = general_purpose::STANDARD.encode(buf);

        let mut iter = encoded.chars().peekable();
        let first_chunk: String = iter.by_ref().take(4096).collect();

        // write the first chunk, which describes the image
        let first = format!(
            "{KITTY_START}f=24,a=T,t=d,i={},p=1,s={buf_width},v={buf_height},c={},r={},m=1,q=2;{first_chunk}{KITTY_END}",
            id, cols, rows,
        );
        self.images_queue.push((None, first));

        // write all the chunks, each containing 4096 bytes of data
        while iter.peek().is_some() {
            let chunk: String = iter.by_ref().take(4096).collect();
            let m = if iter.peek().is_some() { 1 } else { 0 };
            let next = format!("{KITTY_START}m={m};{chunk}{KITTY_END}");
            self.images_queue.push((None, next));
        }
    }
emsquid commented 1 year ago

Thanks for loving it! I will try to see if I can implement that soon, I never thought about it but it shouldn't be that hard, I have been using it in some kitty tests. Great suggestion from you :) I wonder how you think it should work, should it be an option? a default? how should I choose between sending files names and pixels ?

bogzbonny commented 1 year ago

Oh yeah interesting question ... judging by your design so far, I'd recommend adding this feature as an option within your current Options struct. Also I'm looking at the options struct right now, and I'm thinking it may a bit more sense to group all your kitty options together under a common enum. For instance, is it not bad state if the user sets both the clear and load to Some(...)?

I'd personally probably do something like this:

pub struct Options {
  ..
  kitty_op: Option<KittyOp>,
}

pub enum KittyOp {
  Load(u32), 
  LoadRemote(u32),
  Display(u32),
  Clear(u32),
}