[HN Gopher] Show HN: a Rust based CLI tool 'imgcatr' for display...
       ___________________________________________________________________
        
       Show HN: a Rust based CLI tool 'imgcatr' for displaying images
        
       cat for images, by RUST
        
       Author : cheeseisinsane
       Score  : 116 points
       Date   : 2024-04-16 08:30 UTC (14 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | TazeTSchnitzel wrote:
       | You could get better resolution in some terminals by using
       | sixels: https://en.wikipedia.org/wiki/Sixel
       | 
       | I think there's some other methods in particular terminals for
       | displaying images, but I don't remember them.
        
         | warbled_tongue wrote:
         | Yeah, but this is in rust.
        
           | ramon156 wrote:
           | Huh?
        
         | martijnarts wrote:
         | You could also probably detect the terminal you're in and use
         | some of their advanced features, like the image protocol in
         | iTerm2[0] or the terminal graphics protocol[1]. 1 also lists
         | alternative programs that do this!
         | 
         | [0]: https://iterm2.com/documentation-images.html [1]:
         | https://sw.kovidgoyal.net/kitty/graphics-protocol/
        
           | hnlmorg wrote:
           | This is how murex works too https://github.com/lmorg/murex/bl
           | ob/master/config/defaults/p...
        
         | dale_glass wrote:
         | And kitty has icat, which just has image support:
         | https://sw.kovidgoyal.net/kitty/kittens/icat/
         | 
         | 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.
        
           | eptcyka wrote:
           | X is literally that.
        
             | mxuribe wrote:
             | Would you kindly clarify? Did you mean Xterm?
        
               | Tmpod wrote:
               | I believe they meant X.org, the graphical stack used by
               | most graphical Linux systems.
        
             | baq wrote:
             | > modern
             | 
             | um.
             | 
             | I guess the rest applies, but...
        
             | IshKebab wrote:
             | It's not though. You have to fiddle around with ports and
             | servers and environment variables.
             | 
             | 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.
        
               | ranger_danger wrote:
               | Xsixel
        
           | hnlmorg wrote:
           | I'm working on exactly that :)
        
             | lambdaba wrote:
             | On behalf of the entire console user community, thank you!
        
           | exitb wrote:
           | I have a feeling that we'd end up regretting it. It would get
           | abused in all the unnecessary ways. Kind of like the magic
           | Docker outputs, with output previews and multiple progress
           | bars that break into a horrible mess the moment they hit a
           | log file, instead of a terminal.
        
           | ranger_danger wrote:
           | Most new-age terminal emulators do have image support and
           | more are getting support every day, even Windows Terminal is
           | working on it.
           | 
           | 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.
        
           | pwdisswordfishc wrote:
           | TermKit?
        
           | godelski wrote:
           | Kitty is fine, but there is a big issue with tmux and the dev
           | seems to think it is about tiling and not about using remote
           | machines.[0] Sure, I tile because it is there and I don't
           | have control of the terminal I'll use on the other end, but
           | the main draw is I gotta work on machines I'm connecting to
           | with ssh. I think there's a lot of us still needing tools
           | like this (and mosh) but little support. Looks like people
           | were trying to help the dev but there was communication
           | breakdown. I'm all for making sure things are done right and
           | not just accepting hacky solutions, but there has to end up
           | being a solution.
           | 
           | 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
           | 
           | [2] https://mitchellh.com/ghostty
           | 
           | [3] https://github.com/warpdotdev/Warp/issues/900
        
       | berkes wrote:
       | I do a lot of work in the terminal. And every few weeks I'm
       | wishing for something like "cat for images".
       | 
       | "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.
        
         | e12e wrote:
         | > Very rarely, am I on a machine that has no display, and I
         | still need to view some images that live there.
         | 
         | X11 forwarding over ssh is an option.
        
       | elliottcarlson wrote:
       | I was making a similar library (paired with a cli app) in Go a
       | while back with some fun results -- it lead me down a rabbit hole
       | trying to render animated gifs, which has interesting results
       | depending on the terminal being used. I also implemented the
       | resizing of the images to properly scale for the terminal as
       | well. I never actually got around to uploading the repo, but will
       | try to get around to that tonight.
       | 
       | Some videos of it in action: https://youtu.be/L2LTPKW6EPw
       | https://youtu.be/b0CYZyuKLr8 https://youtu.be/_VnV96l5Xkc
        
         | overcrowd8537 wrote:
         | I also did something in dotnet that was a half baked visual
         | media player. Had seek, pause, dynamic resizing, and a frame
         | buffer all implemented, but it was a super naive
         | representation. It was neat to be able to save frames of a
         | movie as ascii text to a text file with or without ansi escape
         | sequences to even view later on a machine without the app.
        
       | hsfzxjy wrote:
       | I've made one years ago, supporting gif
       | 
       | https://github.com/hsfzxjy/i2a-rs
        
       | plasticeagle wrote:
       | It doesn't seem to work in macos terminal, but it's likely my
       | term environment vars aren't set correctly.
       | 
       | I just get a whole pile of random colour, some of which are
       | flashing.
        
       | capitainenemo wrote:
       | IMO the best results out there are with chafa right now.
       | https://hpjansson.org/chafa/gallery/
       | 
       | 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.
        
         | kernelsanderz wrote:
         | I just noticed that tmux has some basic sixel support now -
         | https://raw.githubusercontent.com/tmux/tmux/3.4/CHANGES
         | 
         | discovered at https://www.arewesixelyet.com/
        
           | capitainenemo wrote:
           | I guess it'll take a while for that to propagate. I wonder
           | how well it works with nested tmux sessions and multiple
           | servers. Also I do have the issue with terminals support.
           | Regrettably the assigned work computer is still Windows, and
           | I've been using putty there. If you know of a good sixel
           | terminal for windows..
           | 
           | 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.
        
       | williamcotton wrote:
       | If you're on MacOS an imgcat tool pairs well with an imgpbcopy
       | tool like this:
       | 
       | 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!
        
         | throwaway143829 wrote:
         | What's the difference between this recipe and `impbcopy
         | image.png`? Is it just for the pixelated effect?
        
           | williamcotton wrote:
           | I use: https://pypi.org/project/imgcat/
           | 
           | 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/d
           | otfiles/blob/master/bin/pl...
        
             | godelski wrote:
             | Strangely this doesn't work inside tmux...
             | 
             | 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.
             | 
             | [0] https://github.com/kovidgoyal/kitty/issues/391
        
               | tempay wrote:
               | On macOS iterm2 has really nice integration with tmux[1]
               | via tmux's "Control Mode". It allows you to use tmux
               | almost transparently including image printing, mapping
               | windows/split panes into tabs/native splits.
               | 
               | [1] https://iterm2.com/documentation-one-
               | page.html#documentation...
        
       | emilsayahi wrote:
       | I tried this two years ago when I was still actively 'learning'
       | Rust: https://github.com/Dirout/depi
        
       | wokwokwok wrote:
       | > cargo install imgcatr
       | 
       | 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.
        
         | onei wrote:
         | The go CLI does exactly the same. Python's pip (via setup.py)
         | will do the same, and in an arguably less transparent way iirc.
         | I don't disagree that there are better ways, but it's good
         | enough to get you off the ground.
        
           | lelandbatey wrote:
           | To clarify, cargo is like pip _but pip with the --user flag
           | on by default_.
        
             | gpm wrote:
             | `pip --user` still installs things to a per-user-global
             | shared folder, that doesn't exist with cargo. If you're
             | going to compare to pip, it's got to be something like
             | "pip, but everything you build gets its own venv".
        
         | nicce wrote:
         | If you install binary blob from the internet, you trust exactly
         | one person and no way to verify if binary matches the source.
         | 
         | 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.
        
         | tester457 wrote:
         | > Is the installed binary sandboxed? It is namespaced?
         | 
         | I write dumb simple cli tools for myself. How to do either of
         | these things?
        
           | wokwokwok wrote:
           | By only allowing it to be on the PATH when you're in a
           | specific folder (eg. The binary only ever lives in
           | project/bin, not $user/.shared/bin) and by making the binary
           | filename have a prefix (eg. project-git) so you can't
           | possibly invoke it when expecting to call a normal cli
           | command (eg git).
           | 
           | Since cargo manages these installs, both would be trivial for
           | it to do; just inconvenient for cli app authors.
        
             | semi-extrinsic wrote:
             | But this is not "sandboxed" in any conventional
             | understanding of the term. "sandboxed" would mean that the
             | binary has restricted access to resources like the
             | filesystem, the network etc.
        
         | gpm wrote:
         | I think you're fundamentally misunderstanding what is going on
         | here, because your questions about "namespacing", "being shared
         | between objects", and "building installing things" suggest your
         | imagining a system that doesn't exist here. Cargo, unlike a
         | system like pip, doesn't have global files*, it doesn't have
         | libraries installed to the system, there is no* global state to
         | corrupt.
         | 
         | 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.
        
           | wokwokwok wrote:
           | > command is that a binary is placed in `~/.cargo/bin`, which
           | most rust programmers will have on their PATH
           | 
           | 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.
        
             | gpm wrote:
             | > That is a global effect.
             | 
             | 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.
        
         | woodrowbarlow wrote:
         | > I feel very uncomfortable seeing cargo being used as a tool
         | to distribute software. Cargo is a package manager.
         | 
         | 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.
        
           | earthling8118 wrote:
           | I think their thought was incomplete. It's a language-
           | specific package manager. Out of that list I think there are
           | some that have no business installing packages for use on the
           | greater system. They work fine for development dependencies
           | and project building, but they should stay in their lane when
           | it comes to installing tools to use outside of project
           | development.
        
             | woodrowbarlow wrote:
             | oh, that makes sense. it just means the packaging hasn't
             | been taken as far as it can go. once a project is set up
             | for packaging using something like `cargo`, that means it
             | will be that much easier for someone (anyone) to take it
             | one step further and package it in higher-level package
             | managers like `apt` or `dnf` on top. or `snap` or
             | `flatpak`. or a nix/arch recipe.
        
       | S0y wrote:
       | I loved those image2text ever since I learned about libcaca
       | http://caca.zoy.org/wiki/libcaca
        
       | timetraveller26 wrote:
       | If you use the kitty terminal you can use:
       | 
       | kitten icat image.jpeg
        
       | cameroncooper wrote:
       | Terminology (part of Enlightenment) is a fantastic terminal and
       | has image support.
       | 
       | https://www.enlightenment.org/about-terminology.md
        
         | semi-extrinsic wrote:
         | Ah, Enlightenment, that's a blast from the past! I remember
         | using a heavily riced E16 back in the days. I haven't tried it
         | after I fell into the tiling WM rabbit hole 15 years ago. How
         | is it holding up?
        
       | Fileformat wrote:
       | timg is a really nice similar tool that does pixel graphics in
       | the terminal window if supported, falling back to character
       | graphics if not.
       | 
       | The big plus is that it supports SVG images.
       | 
       | https://github.com/hzeller/timg
       | 
       | And it is available via brew/apt/etc.
        
       | zamubafoo wrote:
       | While not CLI, I always look for cross platform image viewers and
       | found https://github.com/woelper/oculante.
       | 
       | Had a few woes compiling it due to my laptops configuration, but
       | once compiled it works with everything I would reasonably throw
       | at it.
        
       | m0shen wrote:
       | I love seeing how many people wrote one of these. I've written 2:
       | 
       | One to learn golang that plays gifs -
       | https://github.com/moshen/gotermimg
       | 
       | And one in perl - https://github.com/moshen/Image-Term256Color
        
       | skyfaller wrote:
       | I've been using viu, which is also written in Rust:
       | https://github.com/atanunq/viu
       | 
       | 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.
        
       ___________________________________________________________________
       (page generated 2024-04-16 23:01 UTC)