Show HN: a Rust based CLI tool 'imgcatr' for displaying images
github.com
github.com
https://github.com/williamcotton/dotfiles/blob/master/bin/im...
Then create a shell function like:
imgc() {
tee >(imgcat "$@") >(impbcopy -) > /dev/null
}
So you can: cat image.png | imgc
Which will then show the image in the console, and if you switch over to another app you can simply paste in the image. And if you create a new file in Preview it will be the image in the paste buffer!The VS Code terminal supports both the sixel and iterm image format so you get the actual image.
Most of the time I'm using it with my personal CLI graph template language:
cat some.csv | plt '[x, y], z { bar 10px [solid red, solid green] }' | imgc
So then I see the graph in the console and then I'm ready to save it if I'm happy with the output.If you're curious, here's plt, powered by python and matplotlib under the hood: https://github.com/williamcotton/dotfiles/blob/master/bin/pl...
It really seems like there are a lot of issues with rendering images in the cli. I know kitty has a python version too but kitty doesn't play nice with tmux and the dev isn't a fan of tmux[0]. To be fair, I'd love to move away from tmux but I use remote machines all day and I haven't found a good alternative. I don't care about tiling (I can do that in vim, even the terminal), though it is useful (mostly switching sessions for managing workflow context). I'd also love to see someone pick back up mosh (ssh).
A critical problem is that if you work on remote machines a lot you probably gotta be able to build some things from source and build into your local bin because you don't have sudo access on the machine. Preferably installs without network access.
[1] https://iterm2.com/documentation-one-page.html#documentation...
It might be fine for local[1] multiplexing but over the network it is not as fast as even something like VNC or RDP.
I think there's some other methods in particular terminals for displaying images, but I don't remember them.
[0]: https://iterm2.com/documentation-images.html [1]: https://sw.kovidgoyal.net/kitty/graphics-protocol/
I'm really confused about how is it that we're in 2024, Linux is open source from top to bottom, and we're still messing around with rendering images in ASCII.
I really wish there was some interest in doing a modern, graphical console. UTF8, antialiasing, graphics, the works.
um.
I guess the rest applies, but...
But a drawing API is clearly not the way modern graphics works best. What would be really cool is a terminal that supported low latency streaming video. Then you can do proper GUI apps using any rendering system they want and it will properly integrate with ssh.
However this brings up the philosophical debate of just how close you're becoming to a real window manager or display server in the first place.
I'd honestly just love to have a minimal terminal like foot[1], but that's wayland only and wayland support is still very mixed. And who knows when ghostty will come out[2]. But I also need linux + mac support and I think a lot of people do (and no wayland to mac port?). Too many terminals are far too bloated. And boy... do I not need this bullshit[3]
[0] https://github.com/kovidgoyal/kitty/issues/391
[1] https://codeberg.org/dnkl/foot
Some videos of it in action: https://youtu.be/L2LTPKW6EPw https://youtu.be/b0CYZyuKLr8 https://youtu.be/_VnV96l5Xkc
How does imgcatr compare?
Viu was last updated 5 months ago, imgcatr 3 months ago, not a significant difference. imgcatr is a longer name than viu, requiring more keystrokes to type.
The big plus is that it supports SVG images.
https://github.com/hzeller/timg
And it is available via brew/apt/etc.
Had a few woes compiling it due to my laptops configuration, but once compiled it works with everything I would reasonably throw at it.
One to learn golang that plays gifs - https://github.com/moshen/gotermimg
And one in perl - https://github.com/moshen/Image-Term256Color
I just get a whole pile of random colour, some of which are flashing.
kitten icat image.jpeg
It also has some basic ffmpeg support.
And yeah, there are sixels and native rendering of graphics in terminals, but I still find this handy if I'm a couple of tmux sessions deep on a remote server and I need to figure out which graphic is which.
discovered at https://www.arewesixelyet.com/
Anyway, Chafa's results are darn good IMO. The images in the gallery don't I feel showcase how well it matches against organic forms. And it handles a wide variety of images. SVG etc.
Even when I have access to pixels, I find on slow connections Chafa can be a decent form of compression :) For example, I was using the ffmpeg patch to play a video remotely to figure out what it was and while I could have relayed it with ssh -YC , Chafa was simply a lot more performant due to it being a lossy transformation. Kinda like playing the video in a VNC session with jpeg loss cranked up to max, but without the need to fire that up.
"I should write it!". And then realize it already exists and is on my machine. I presume most OSes and distro's have some simple image viewer. Mine, Ubuntu, comes with `eog`.
Very rarely, am I on a machine that has no display, and I still need to view some images that live there. Then the workflow becomes convoluted: transfer images to a local machine, or put them in some http-accessible place. For those cases, I think imgcatr would be great. But then it's not available on these machines, so that kindof defeats the purpose again.
X11 forwarding over ssh is an option.
I feel very uncomfortable seeing cargo being used as a tool to distribute software.
Cargo is a package manager.
It should build software.
I suppose it’s arguable that it should be able to install developer tooling to help you build things.
However, I feel uncomfortable seeing this type of thing.
Is the installed binary sandboxed? It is namespaced? Is it shared between projects? What causes it to be updated?
Can building a crate update the globally installed version of “foo” by “cargo install” installing a different crate that happens to have a binary with the same name? (Yes, via build.rs, but just as a dependency?)
How would I even know?
There are so many things wrong with this imo.
Building a crate should generally be sandboxed, but this (cargo install as a concept, not this particular app) feels like the goal is the opposite of a sandbox, instead it’s a shared arbitrary named tool that goes into your path by default and gets updated an unknown times.
I feel like this is going to bite the rust community in the foot at some point.
If you build with cargo, you can at least verify that the current source matches the binary and the trust of the dependencies is decentralized, with many eyes on them.
There are better ways, but these better ways just use different package managers. The above is no different than any ”build from source” method.
I write dumb simple cli tools for myself. How to do either of these things?
Since cargo manages these installs, both would be trivial for it to do; just inconvenient for cli app authors.
However, it’s more isolated than what currently exists, even if it’s not totally isolated, and it’s an effort to prevent abuse, rather than doing nothing.
My point is that you can contain the impact of cli apps in various ways.
The only "side effect" of running a `cargo install` command is that a binary is placed in `~/.cargo/bin`, which most rust programmers will have on their PATH. There are no side effects of running a normal cargo build, it won't update anything outside of the crate you are building (and in the crate you are building, it will only change Cargo.lock and the target directory). There isn't any scary action at a distance.
> What causes it to be updated?
Nothing, except a user manually running `cargo install --force imgcatr`. This is the main criticism of using `cargo install`, it's not a package manager, it's a shortcut to doing the C equivalent of `git clone project && cd project && ./configure --prefix=~/.cargo/bin && make && make install` (but for binaries only, no libraries).
* There is a local cache of checked out code, and the index of crates, which is generally updated every time you run a `cargo build` command that might need anything that isn't local. You can use this cache without touching the internet by specifying `--offline`, at which point the contents of the cache matters. The only reason to do this is if you don't have internet. I'm also ignoring nonsense that people can put in `build.rs` files, but pretty much no one does. Rust will also look for certain global dependencies on your system (namely C style libraries), but it doesn't have any support for putting new ones there.
That is a global effect.
> Nothing, except a user manually running `cargo install --force imgcatr`.
I’m absolutely certain build.rs can also do this; you can choose to ignore that if you want.
I hope ignoring it makes it not a thing we have to ever worry about. I guess.
I get it, it’s convenient; but I think people are fooling themselves if they think having a binary on their path is no big deal, or that manually calling “cargo install” is the only way this can happen.
FWIW, there is a precedent with serde shipping a binary (https://github.com/serde-rs/serde/releases/tag/v1.0.184 related discussion etc. which kind of shows this is not an idle concern)… mmm… oh well, whatever I guess.
Yes, I agree, that's why I said it is the only one. Moreover the sole purpose of cargo install is to cause that side effect (otherwise you use cargo build, which builds the binaries but doesn't copy them to a shared directory).
> I’m absolutely certain build.rs can also do this
build.rs is running arbitrary code, it can do anything, that's part of what I disclaimed in my asterix. In practice it doesn't do anything. Every packaging system has an escape hatch like this.
Serde shipping a binary was someone embedding a chunk of opaque bytes in their "source code", it's completely unrelated to this discussion and has no effect on what `cargo install` does.
but... that's exactly what a package manager is. a tool to package and distribute software. apt, dnf, nix, snap, flatpak, npm, cargo, pip... they're all package managers.