Display Images, PDFs, and GIFs Directly in Your Terminal

Viewing JPEGs, PDFs and even GIFs directly in the terminal.

Introduction

Did you know that modern terminal emulators are capable of displaying many file formats, including images, PDFs and GIFs directly in the terminal? This can be particularly useful when connected to a remote SSH server. Although similar functionality may be achieved using X11 forwarding, this feature is not always enabled on remote servers. In addition, the X11 protocol tends to be quite slow, since it needs to forward the entire graphical user interface (GUI) application, rendering it unpractical for quickly viewing images.

Setup

Many modern terminal emulators support various protocols for visualizing images in the terminal. In this post, we will focus on the iTerm2 and the Kitty terminal emulators, since these are the ones that I use on my Mac and Linux computers, respectively.

iTerm2

In order for iTerm2 to display images, its Utilities Package needs to be installed. This can be done by navigating in the menu bar to iTerm2 > Install Shell Integration. A popup will open in which the “Also install iTerm2 Utilities” option needs to be selected.

The utilities may then either be installed using local copy or the latest version of the tools may be fetched from a remote repository. I recommend the latter method, which should provide better compatibility with the latest version of iTerm2. The command automatically pulls a number of useful shell scripts from a remote Git repository, which extend the functionality of iTerm2. Note that, if preferred, each individual script may be manually installed by simply placing them somewhere in your PATH. The one that we are interested in is the imgcat script. Once it has been installed, various image formats (JPG, PNG, etc…), PDF and even animated GIF may be displayed directly in the terminal using

imgcat image.ext

The script comes with a number of command line options that are listed in its help page, accessible with imgcat --help. Noteworthy flags include -H and -W, which configure the height and width of the images, and the -u/--url with which arbitrary images can be fetched from the internet using a URL.

Tip

Since, by default, imgcat preserves the original size of the image–leading to vastly varying sizes of the displayed images–I prefer setting a fixed height of the image (in my case 33% of the terminal window) such that images are displayed using a consistent size. This can be done by passing the -H 33% flag to imgcat. I use an alias to overwrite the default behavior: alias imgcat="imgcat -H 33%".

Kitty

For the kitty terminal, this feature is part of a set of extensions–called kittens–many of which provide similar functionality to the iTerm2 utility scripts. The icat kitten, which can be display images in the terminal, requires the ImageMagick program as a dependency for performing some of the image manipulations. Once, these have been installed, images may be viewing using:

kitten icat image.ext

The icat kitten also comes with a number of options which are listed in its help page.

Enabling use through SSH

Viewing images in the terminal becomes an essential feature in the context where GUI applications are not available, as in the case of an SSH connection to a remote server. Thankfully, both the iTerm2 and kitty protocols work seamlessly even through SSH. All that needs to be done is to also install the iTerm2 imgcat script (following the procedure described above) or the kitty terminal on the remote server.

Automatically Dispatching to iTerm2 or Kitty

Note that the iTerm2 and kitty protocols are not compatible. Therefore, if the iTerm2 terminal emulator was used to SSH into the remote server then the kitten icat command will not work. Therefore, it would be convenient to configure the shell on the remote server to detect the terminal that was used to SSH and, based on that, automatically dispatch to the appropriate command. This can be achieved by storing the terminal emulator in use in an environment variable on the host and then sending it to the remote server. In the iTerm2 settings enable the Advanced > Experimental Features > Set LC_TERMINAL=iTerm2 option. This will set the LC_TERMINAL environment variable to iTerm2 whenever a shell is started in iTerm2.

Now, this environment variable needs to be propagated to the remote server. The iTerm2 documentation states that OpenSSH passes this environment variable by default to the remote servers. However, this doesn’t seem to be the case for me. In any case, environment variables may be sent explicitly to the remote server by setting the option SendEnv LC_TERMINAL in the ~/.ssh/config file. This option can be enabled for all servers using the following wildcard at the top of the configuration:

Host *
  SendEnv LC_TERMINAL

Note that in order for this to work, the remote server needs to be configured such that it accepts sent environment variables from the host. Further information on enabling this feature can be found by consulting the sshd_config man pages (see for instance the AcceptEnv entry).

On the remote server, inside the .bashrc or .zshrc, this environment variable may be queried and, accordingly, the icat command can be dispatched to the appropriate routine:

if [ "$LC_TERMINAL" = "iTerm2" ]; then
  alias icat="imgcat -H 33%"
else
  alias icat="kitten icat"
fi

Waring: Compatibility with tmux

Unfortunately, in my case, both of these methods failed inside of tmux sessions. For some users, this is resolved by enabling the set -gq allow-passthrough in the tmux configuration.

Conclusion

Terminal emulators have come a long way from their initial exclusively text-based input/output modality. Today, they offer a surprising array of features, including the ability to display images, PDFs and GIFs directly within the terminal. This functionality is a game-changer, particularly for remote work, where traditional graphical interfaces may not be available or feasible.