summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/ext/img_display.py74
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