Skip to content
Ascii Moth edited this page Sep 28, 2023 · 44 revisions

Since 1.6.0, ranger can preview images in full color. This works by calling a program named w3mimgdisplay that's included in the w3m web browser, which draws images directly into the terminal.

If you use iTerm2, a Mac OS X terminal replacement, you can enable a method that takes advantage of the built-in drawing functionality so you won't need w3m.

Steps to enable it:

With w3mimgdisplay

  • Get a compatible terminal. Terminals that are known to work are rxvt-unicode, xterm and st (at least since st 0.6, besides if it doesn't work under st, you maybe use ueberzug).
  • install w3m with the image drawing feature. On Arch Linux, the package is called "w3m", on Debian and Fedora it's "w3m-img".
  • Add the line set preview_images true to your ~/.config/ranger/rc.conf.
  • In the most recent versions, you no longer need to get the scope.sh configuration file by running ranger --copy-config=scope, however if you do you can edit it to get graphical previews of pdfs and svgs for example.
  • Restart ranger and navigate to an image file. \o/

With ueberzug

The original python version of ueberzug has been discontinued but an active fork rewrriten in c++ is available and works as a drop-in replacement.

  • This will work with most terminals and even with tmux but requires X11. Doesn't work well with tabs.

  • Install ueberzugpp or on Arch Linux it is also available in the AUR.

  • Add the following lines to your ~/.config/ranger/rc.conf.

    set preview_images true
    set preview_images_method ueberzug
    
  • Restart ranger and navigate to an image file. \o/

With urxvt

The image preview methods urxvt and urxvt_full can be used with the urxvt terminal and are typically more reliable. They use a special escape sequence to change the background of the terminal in order to render the image.

  • Run urxvt with pixbuf support (some operating systems ship it without pixbuf support, but for example ArchLinux has an AUR package called rxvt-unicode-pixbuf which should work)
  • Add the following lines to your ~/.config/ranger/rc.conf:
    set preview_images true
    set preview_images_method urxvt
    
    You can also choose urxvt-full if you would like the image to fill the whole terminal rather than just the preview pane.
  • Restart ranger and navigate to an image file. \o/

With iTerm2

NOTE: You need at least iTerm2 version 2.9 for the image preview feature to work.

  • Add the following lines to your ~/.config/ranger/rc.conf:
    set preview_images true
    set preview_images_method iterm2
    
  • Restart ranger and navigate to an image file. \o/

With kitty

The image preview method kitty can be used with the kitty terminal.

NOTE: Tested with kitty 0.14.6

  • Add the following lines to your ~/.config/ranger/rc.conf:
    set preview_images true
    set preview_images_method kitty
    
  • Restart ranger and navigate to an image file. \o/

With mpv

NOTE: You need at least mpv version 0.25 for the below method to work.

The mpv image preview method allows ranger to control an external client for viewing media. The benefit of this approach is that both images and videos share a single, separate window.

  • Add the following lines to your ~/.config/ranger/commands.py:
import subprocess
import json
import atexit
import socket
from pathlib import Path

import logging
logger = logging.getLogger(__name__)
import traceback

from ranger.ext.img_display import ImageDisplayer, register_image_displayer

@register_image_displayer("mpv")
class MPVImageDisplayer(ImageDisplayer):
    """Implementation of ImageDisplayer using mpv, a general media viewer.
    Opens media in a separate X window.

    mpv 0.25+ needs to be installed for this to work.
    """

    def _send_command(self, path, sock):

        message = '{"command": ["raw","loadfile",%s]}\n' % json.dumps(path)
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        s.connect(str(sock))
        logger.info('-> ' + message)
        s.send(message.encode())
        message = s.recv(1024).decode()
        logger.info('<- ' + message)

    def _launch_mpv(self, path, sock):

        proc = subprocess.Popen([
            * os.environ.get("MPV", "mpv").split(),
            "--no-terminal",
            "--force-window",
            "--input-ipc-server=" + str(sock),
            "--image-display-duration=inf",
            "--loop-file=inf",
            "--no-osc",
            "--no-input-default-bindings",
            "--keep-open",
            "--idle",
            "--",
            path,
        ])

        @atexit.register
        def cleanup():
            proc.terminate()
            sock.unlink()

    def draw(self, path, start_x, start_y, width, height):

        path = os.path.abspath(path)
        cache = Path(os.environ.get("XDG_CACHE_HOME", "~/.cache")).expanduser()
        cache = cache / "ranger"
        cache.mkdir(exist_ok=True)
        sock = cache / "mpv.sock"

        try:
            self._send_command(path, sock)
        except (ConnectionRefusedError, FileNotFoundError):
            logger.info('LAUNCHING ' + path)
            self._launch_mpv(path, sock)
        except Exception as e:
            logger.exception(traceback.format_exc())
            sys.exit(1)
        logger.info('SUCCESS')
  • Ensure the following lines appear in your ~/.config/ranger/rc.conf:
set preview_images true
set preview_images_method mpv
set use_preview_script true
set preview_script ~/path/to/your/scope.sh     # or whatever your preview script is
  • Restart ranger and navigate to an image file. \o/

If you want mpv to support common image viewing features, see this gist for a sample mpv configuration.

With imv

Source: guyuming76@83a7264 from #2628

  • Add the following to your ~/.config/ranger/commands.py:
from ranger.ext.img_display import ImageDisplayer, register_image_displayer
from subprocess import Popen, PIPE, run
import time

@register_image_displayer("imv")
class IMVImageDisplayer(ImageDisplayer):
    """
    Implementation of ImageDisplayer using imv
    """
    is_initialized = False

    def __init__(self):
        self.process = None

    def initialize(self):
        """ start imv """
        if (self.is_initialized and self.process.poll() is None and
                not self.process.stdin.closed):
            return

        self.process = Popen(['imv'], cwd=self.working_dir,
                             stdin=PIPE, universal_newlines=True)
        self.is_initialized = True
        time.sleep(1)

    def draw(self, path, start_x, start_y, width, height):
        self.initialize()
        run(['imv-msg', str(self.process.pid), 'close'])
        run(['imv-msg', str(self.process.pid), 'open', path])

    def clear(self, start_x, start_y, width, height):
        self.initialize()
        run(['imv-msg', str(self.process.pid), 'close'])

    def quit(self):
        if self.is_initialized and self.process.poll() is None:
            self.process.terminate()
  • Ensure the following lines appear in your ~/.config/ranger/rc.conf:
set preview_images true
set preview_images_method imv
set use_preview_script true
set preview_script ~/path/to/your/scope.sh     # or whatever your preview script is
  • Restart ranger and navigate to an image file. \o/

With your own image previewing method

Image display methods can be added via ~/.config/ranger/commands.py by implementing ImageDisplayer.draw() and registering your class with a nickname to be used with set preview_images_method. So basically:

  • Add the following lines to your ~/.config/ranger/commands.py:
from ranger.ext.img_display import ImageDisplayer, register_image_displayer

@register_image_displayer("my-image-display-method")
class MyImageDisplayer(ImageDisplayer):
    # Draws image placed in path
    def draw(self, path, start_x, start_y, width, height):
        # implement me
    # Clears the area of the screen where the image was before drawing a preview of another file
    def clear(self, start_x, start_y, width, height):
        # implement me
  • Ensure the following lines appear in your ~/.config/ranger/rc.conf:
set preview_images true
set preview_images_method my-image-display-method
set use_preview_script true
set preview_script ~/path/to/your/scope.sh     # or whatever your preview script is

See ranger/ext/img_preview.py or the above mpv-based image preview for examples.

With wezterm imgcat

  • Add the following lines to your ~/.config/ranger/commands.py:
from ranger.ext.img_display import ImageDisplayer, register_image_displayer
import subprocess
from shlex import quote

@register_image_displayer("wezterm-image-display-method")
class WeztermImageDisplayer(ImageDisplayer):
    def draw(self, path, start_x, start_y, width, height):
        print("\033[%d;%dH" % (start_y, start_x+1))
        path = quote(path)
        draw_cmd = "wezterm imgcat {} --width {} --height {}".format(path, width, height)
        subprocess.run(draw_cmd.split(" "))
    def clear(self, start_x, start_y, width, height):
        cleaner = " "*width
        for i in range(height):
            print("\033[%d;%dH" % (start_y+i, start_x+1))
            print(cleaner)
  • Ensure the following lines appear in your ~/.config/ranger/rc.conf:
set preview_images true
set preview_images_method wezterm-image-display-method
set use_preview_script true
set preview_script ~/path/to/your/scope.sh     # or whatever your preview script is

Troubleshooting

If the w3m program doesn't show images itself, then ranger won't show them either in the w3mimgdisplay mode. Try w3m xkcd.com for example.

Sometimes black stripes are drawn over the images when using w3mimgdisplay. This is due to the unreliable drawing mechanism, and for some people it helps to set the option draw_borders to true.

Sometimes it helps trying a different terminal emulator or a different displaying method.

w3mimgdisplay appears not to work with compositing managers like xcompmgr.

If your image previews broke after upgrading ranger's git after september 2015, you need to update scope.sh for image previews to work. See https://github.com/hut/ranger/wiki/Upgrading#image-previews-stopped-working-after-updating-ranger-git

ASCII previews

Oldschool ASCII art previews can be enabled like this:

  • install libcaca (or whatever package provides the "img2txt" executable)
  • get a current scope.sh config, e.g. with ranger --copy-config=scope
  • The following ~/.config/ranger/rc.conf settings are also essential, though the default rc.conf already includes them, so usually you don't need to change anything.
set preview_images false
set use_preview_script true
set preview_script ~/path/to/your/scope.sh

set preview_images false is necessary because otherwise ranger might use full color previews instead.

Previewing RAW photos

Add the following to scope.sh just before image/*). It handles Canon (.CR2), Olympus (.ORF), and Sony (.ARW, which at least xdg-mime query filetype <file> recognizes as image/tiff). Expects the exiftool command to be available.

handle_image() {
    local mimetype="${1}"
    case "${mimetype}" in
        # SVG
        # image/svg+xml)
        #     convert "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6
        #     exit 1;;

        # BEGIN SNIPPET
        image/x-canon-cr2|image/x-olympus-orf|image/tiff)
            local orientation
            # extract orientation from RAW file using exiftool (identify won't work)
            orientation=$( exiftool -b -Orientation "${FILE_PATH}")
            exiftool -b -PreviewImage "${FILE_PATH}" > "${IMAGE_CACHE_PATH}"
            if [[ -n "$orientation" && "$orientation" != 1 ]]; then
                # ...auto-rotate the image according to the EXIF data.
                exiftool -overwrite_original_in_place -Orientation="$orientation" -n "${IMAGE_CACHE_PATH}"
                mogrify -auto-orient "${IMAGE_CACHE_PATH}"
            fi
            exit 6;;
        # END SNIPPET

        # Image
        image/*)
            local orientation
            local orientation
            orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FILE_PATH}" )"