about summary refs log tree commit diff stats
path: root/linux/202write-int.subx
Commit message (Expand)AuthorAgeFilesLines
* 7842 - new directory organizationKartik K. Agaram2021-03-031-0/+121
='n23' href='#n23'>23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
# This software is distributed under the terms of the GNU GPL version 3.

"""
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.
"""

import termios, fcntl, struct, sys
from subprocess import Popen, PIPE

W3MIMGDISPLAY_PATH = '/usr/lib/w3m/w3mimgdisplay'
W3MIMGDISPLAY_OPTIONS = []

def _get_font_dimensions():
    """
    Get the height and width of a character displayed in the terminal in
    pixels.
    """
    s = struct.pack("HHHH", 0, 0, 0, 0)
    fd_stdout = sys.stdout.fileno()
    x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
    rows, cols, xpixels, ypixels = struct.unpack("HHHH", x)

    return (xpixels // cols), (ypixels // rows)


def _w3mimgdisplay(commands):
    """
    Invoke w3mimgdisplay and send commands on its standard input.
    """
    process = Popen([W3MIMGDISPLAY_PATH] + W3MIMGDISPLAY_OPTIONS, stdin=PIPE,
            stdout=PIPE, universal_newlines=True)

    # wait for the external program to finish
    output, _ = process.communicate(input=commands)

    return output

def draw(path, start_x, start_y, max_width, max_height):
    """
    Draw an image file in the terminal.

    start_x, start_y, max_height and max_width specify the drawing area.
    They are expressed in number of characters.
    """
    fontw, fonth = _get_font_dimensions()

    max_width_pixels = max_width * fontw
    max_height_pixels = max_height * fonth

    # get image size
    cmd = "5;{}".format(path)
    output = _w3mimgdisplay(cmd).split()

    if len(output) != 2:
        raise Exception('Failed to execute w3mimgdisplay')

    width = int(output[0])
    height = int(output[1])

    # get the maximum image size preserving ratio
    if width > max_width_pixels:
        height = (height * max_width_pixels) // width
        width = max_width_pixels
    if height > max_height_pixels:
        width = (width * max_height_pixels) // height
        height = max_height_pixels

    # draw
    cmd = "0;1;{x};{y};{w};{h};;;;;{filename}\n4;\n3;".format(
            x = start_x * fontw,
            y = start_y * fonth,
            w = width,
            h = height,
            filename = path)
    _w3mimgdisplay(cmd)

def clear(start_x, start_y, width, height):
    """
    Clear a part of terminal display.
    """
    fontw, fonth = _get_font_dimensions()

    cmd = "6;{x};{y};{w};{h}\n4;\n3;".format(
            x = start_x * fontw,
            y = start_y * fonth,
            w = width * fontw,
            h = height * fonth)

    _w3mimgdisplay(cmd)