21 comments

  • williamcotton 13 days ago
    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 13 days ago
      What's the difference between this recipe and `impbcopy image.png`? Is it just for the pixelated effect?
      • williamcotton 13 days ago
        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/dotfiles/blob/master/bin/pl...

        • godelski 12 days ago
          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

          • xk3 12 days ago
            It's not really that strange that tmux doesn't support sixels. It's quite a bit more complicated and resource-intensive than ANSI Escape Codes or ncurses.

            It might be fine for local[1] multiplexing but over the network it is not as fast as even something like VNC or RDP.

            [1] https://github.com/csdvrx/sixel-tmux/

          • tempay 12 days ago
            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...

  • TazeTSchnitzel 13 days ago
    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.

    • dale_glass 13 days ago
      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.

      • exitb 13 days ago
        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 13 days ago
        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.

      • eptcyka 13 days ago
        X is literally that.
        • IshKebab 13 days ago
          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 13 days ago
            Xsixel
            • IshKebab 12 days ago
              > You have to fiddle around with ports and servers and environment variables.
        • mxuribe 13 days ago
          Would you kindly clarify? Did you mean Xterm?
          • Tmpod 12 days ago
            I believe they meant X.org, the graphical stack used by most graphical Linux systems.
        • baq 13 days ago
          > modern

          um.

          I guess the rest applies, but...

      • godelski 12 days ago
        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

      • hnlmorg 13 days ago
        I’m working on exactly that :)
        • lambdaba 13 days ago
          On behalf of the entire console user community, thank you!
      • pwdisswordfishc 13 days ago
        TermKit?
    • martijnarts 13 days ago
      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/

    • warbled_tongue 13 days ago
      Yeah, but this is in rust.
  • elliottcarlson 13 days ago
    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 13 days ago
      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.
  • skyfaller 12 days ago
    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.

  • Fileformat 13 days ago
    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 13 days ago
    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.

  • hsfzxjy 13 days ago
    I've made one years ago, supporting gif

    https://github.com/hsfzxjy/i2a-rs

  • S0y 13 days ago
    I loved those image2text ever since I learned about libcaca http://caca.zoy.org/wiki/libcaca
  • emilsayahi 13 days ago
    I tried this two years ago when I was still actively 'learning' Rust: https://github.com/Dirout/depi
  • m0shen 13 days ago
    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

  • cameroncooper 13 days ago
    Terminology (part of Enlightenment) is a fantastic terminal and has image support.

    https://www.enlightenment.org/about-terminology.md

    • semi-extrinsic 12 days ago
      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?
  • plasticeagle 13 days ago
    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.

  • timetraveller26 13 days ago
    If you use the kitty terminal you can use:

    kitten icat image.jpeg

  • capitainenemo 13 days ago
    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 13 days ago
      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 13 days ago
        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.

  • berkes 13 days ago
    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 13 days ago
      > 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.

  • BitNomad 12 days ago
    It would be better if the images were more clear.
  • wokwokwok 13 days ago
    > 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.

    • gpm 13 days ago
      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 13 days ago
        > 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 13 days ago
          > 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.

    • nicce 13 days ago
      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.

    • onei 13 days ago
      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 13 days ago
        To clarify, cargo is like pip but pip with the --user flag on by default.
        • gpm 13 days ago
          `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".
    • woodrowbarlow 13 days ago
      > 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 13 days ago
        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 13 days ago
          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.
    • tester457 13 days ago
      > Is the installed binary sandboxed? It is namespaced?

      I write dumb simple cli tools for myself. How to do either of these things?

      • wokwokwok 13 days ago
        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 12 days ago
          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.
          • wokwokwok 12 days ago
            Ok, you’re right, sandboxed isn’t the right word; my bad.

            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.

  • Samuel_w 13 days ago
    [dead]
  • HomoJS 13 days ago
    [flagged]
    • aumerle 13 days ago
      Yes hence our butts are so much more hygenic than yours.
  • sylware 13 days ago
    [flagged]
    • thesuperbigfrog 13 days ago
      >> Guys, this frenzy of computer languages with ultra-complex syntax requiring absurdely massive and complex compiler infrastructure has to go away.

      >> Don't you see we need the other way around, namely computer languages with simpler syntax.

      You can't "wish away" essential complexity. Programming languages can be "simple" or "easy to use", but it's hard to make a programming language that does both because software development has some elements that are complex by nature. There are trade-offs to be made when designing programming languages.

      Overly simple programming languages are toys. No one uses them for real work because they are too limited or too constrained.

      Some programming languages like Python and Go (to some degree) hide a lot of complexity and are easy to use for many use cases, but the complexity is still present and becomes visible when you try to do something outside their common uses.

      Other programming languages (like C, C++, and Rust) hide very little and give the software developer more control in exchange for more complexity. This requires more skill and care but allows for leaner, faster software.

      Rich Hickey has a great talk that highlights the differences between software that is "simple" versus software that is "easy": https://www.infoq.com/presentations/Simple-Made-Easy/

      • sylware 13 days ago
        I am refering to complexity of a computer language syntax, NOT the complexity of a computer program.

        Those two are completely different, don't be fooled.

        Some extremely complex programs can be written in assembly, the code and data structure complexity is unrelated to the computer language.

        Damn, and all those pesky downvoters on HN the second you talk about an unpleasant reality.

        Maybe the downvoting system should go away, as it may be AI bots anyway. Like youtube dislike.

    • ape4 13 days ago
      Herb Stutter's Cpp2 is like that https://github.com/hsutter/cppfront
      • sylware 13 days ago
        The complexity of c++ syntax makes it a lost cause (like rust syntax unfortunately), but the root of this tool is "syntax simplication/sanitazer" too. Acknowleding there is an issue here, a core issue, is growing up, and this tool is part of this trend.
    • chompychop 13 days ago
      And then there's this little issue of backward compatibility. :)
      • sylware 13 days ago
        But they are kind of hypocrit, since feature creeps, complex or not, will break compilers via planned obsolescence on 5-10 years cycles.

        From a reality point of view this 'backward compatibility' is actually a trojan horse for those feature creeps. This is this very toxic cycle which has to broken.

        Compilers have already standard version switches, namely the migration path towards saner C syntax is to leverage such options: -std=c11 will allow syntax from "legacy C below c11", and for instance -std=c25 will start to enforce a simplified and saner C syntax. Adding feature creeps or fixing C syntax will have the same effect on real life code, but in the case of fixing C syntax, it is going to make compiler easier to write and real-life alternatives will spawns, which is is very good and sane thing.