diff options
-rw-r--r-- | ranger/ext/img_display.py | 74 |
1 files changed, 63 insertions, 11 deletions
diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py index a70fe366..7ff611ca 100644 --- a/ranger/ext/img_display.py +++ b/ranger/ext/img_display.py @@ -1,21 +1,19 @@ # This software is distributed under the terms of the GNU GPL version 3. +"""Interface for drawing images into the console -"""Interface for w3mimgdisplay to draw images into the console - -This module provides functions to draw images in the terminal using -w3mimgdisplay, an utilitary program from w3m (a text-based web browser). -w3mimgdisplay can display images either in virtual tty (using linux -framebuffer) or in a Xorg session. - -w3m need to be installed for this to work. +This module provides functions to draw images in the terminal using supported +implementations, which are currently w3m and iTerm2. """ +import base64 +import curses import fcntl import os import select import struct import sys import termios +from ranger.core.shared import FileManagerAware from subprocess import Popen, PIPE W3MIMGDISPLAY_PATH = '/usr/lib/w3m/w3mimgdisplay' @@ -24,8 +22,28 @@ W3MIMGDISPLAY_OPTIONS = [] class ImgDisplayUnsupportedException(Exception): pass - class ImageDisplayer(object): + """Image display provider functions for drawing images in the terminal""" + def draw(self, path, start_x, start_y, width, height): + """Draw an image at the given coordinates.""" + pass + + def clear(self, start_x, start_y, width, height): + """Clear a part of terminal display.""" + pass + + def quit(self): + """Cleanup and close""" + pass + +class W3MImageDisplayer(ImageDisplayer): + """Implementation of ImageDisplayer using w3mimgdisplay, an utilitary + program from w3m (a text-based web browser). w3mimgdisplay can display + images either in virtual tty (using linux framebuffer) or in a Xorg session. + Does not work over ssh. + + w3m need to be installed for this to work. + """ is_initialized = False def initialize(self): @@ -38,7 +56,6 @@ class ImageDisplayer(object): self.is_initialized = True def draw(self, path, start_x, start_y, width, height): - """Draw an image at the given coordinates.""" if not self.is_initialized or self.process.poll() is not None: self.initialize() self.process.stdin.write(self._generate_w3m_input(path, start_x, @@ -47,7 +64,6 @@ class ImageDisplayer(object): self.process.stdout.readline() def clear(self, start_x, start_y, width, height): - """Clear a part of terminal display.""" if not self.is_initialized or self.process.poll() is not None: self.initialize() @@ -108,6 +124,42 @@ class ImageDisplayer(object): if self.is_initialized: self.process.kill() +class ITerm2ImageDisplayer(ImageDisplayer, FileManagerAware): + """Implementation of ImageDisplayer using iTerm2 image display support + (http://iterm2.com/images.html). + + Ranger must be running in iTerm2 for this to work. + """ + def draw(self, path, start_x, start_y, width, height): + curses.putp(curses.tigetstr("sc")) + sys.stdout.write(curses.tparm(curses.tigetstr("cup"), start_y, start_x)) + sys.stdout.write(self._generate_iterm2_input(path, width, height)) + curses.putp(curses.tigetstr("rc")) + sys.stdout.flush() + + def clear(self, start_x, start_y, width, height): + self.fm.ui.win.redrawwin() + self.fm.ui.win.refresh() + + def _generate_iterm2_input(self, path, width, height): + """Prepare the image content of path for image display in iTerm2""" + content = self._encode_image_content(path) + text = "\033]1337;File=inline=1;preserveAspectRatio=0" + text += ";size=" + str(len(content)) + text += ";width=" + str(width) + text += ":" + content + text += "\a\n" + return text + + def _encode_image_content(self, path): + """Read and encode the contents of path""" + file = open(path, "r") + try: + return base64.b64encode(file.read()) + except: + return "" + finally: + file.close() def _get_font_dimensions(): # Get the height and width of a character displayed in the terminal in |