Skip to content

Instantly share code, notes, and snippets.

@jaysonlarose
Created January 23, 2021 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaysonlarose/fc86aa38360910669e7762c5b49c7923 to your computer and use it in GitHub Desktop.
Save jaysonlarose/fc86aa38360910669e7762c5b49c7923 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# vim: set fileencoding=utf-8 :
from __future__ import print_function
import sys, PIL.Image, numpy, fcntl, termios, struct, os, fabulous, fabulous.color, fabulous.compatibility
def get_terminal_size():
def ioctl_GWINSZ(fd):
try:
cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
except:
return None
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
try:
fd = os.open(os.ctermid(), os.O_RDONLY)
cr = ioctl_GWINSZ(fd)
os.close(fd)
except:
pass
if not cr:
try:
cr = (env['LINES'], env['COLUMNS'])
except:
cr = (25, 80)
return int(cr[1]), int(cr[0])
def resize_aspect(orig_width, orig_height, width=None, height=None, factor=None):
if width is not None:
factor = float(width) / float(orig_width)
height = int(orig_height * factor)
elif height is not None:
factor = float(height) / float(orig_height)
width = int(orig_width * factor)
else:
width = int(orig_width * factor)
height = int(orig_height * factor)
return width, height, factor
def splitlen_array(data, length):
return [ data[x:x+length] for x in [ x * length for x in range(int(len(data) / length)) ] ]
_magic_aspect = 1.0 / 2.0
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("image_file")
parser.add_argument("--fit-height", action="store", dest="fit_height", type=int, default=None, help="Constrain output dimensions to terminal height minus this many rows")
parser.add_argument("--pixel-aspect", action="store", dest="pixel_aspect", type=float, default=_magic_aspect, help="Pixel squareness adjustment")
parser.add_argument("--halfblock", action="store_true", dest="halfblock", default=False, help="Double your vertical resolution with \u2580")
args = parser.parse_args()
img = PIL.Image.open(args.image_file)
cols, rows = get_terminal_size()
# Calculate resize dimensions
# newdims — resized image dimensions, with square pixels
# newdims_magic — resized image dimensions after adjusting pixel aspect ratio
newdims_magic = None
if args.fit_height is not None:
newdims = resize_aspect(img.width, img.height, height=rows - args.fit_height)
newdims_magic = (int(newdims[0] / args.pixel_aspect), newdims[1])
if newdims_magic is None or newdims_magic[0] > cols:
newdims = resize_aspect(img.width, img.height, width=cols)
newdims_magic = (newdims[0], int(newdims[1] * args.pixel_aspect))
if args.halfblock:
newdims_magic = (newdims_magic[0], newdims_magic[1] * 2)
# Perform resize
resized_img = img.resize((newdims_magic[0], newdims_magic[1]), PIL.Image.BICUBIC)
# Convert to RGB if necessary
if resized_img.mode != 'RGB':
resized_img = resized_img.convert("RGB")
# Convert to numpy array
arr = numpy.array(bytearray(resized_img.tobytes()), dtype=numpy.uint8).reshape(newdims_magic[1], newdims_magic[0], -1)
# Print it out
if not args.halfblock:
for row in arr:
rowrep = b''
for char in row:
rowrep += fabulous.color.fgtrue("#{:02x}{:02x}{:02x}".format(*char), u"\u2588").as_utf8
if sys.version_info.major >= 3:
rowrep = rowrep.decode()
print(rowrep)
else:
for rowpair in splitlen_array(arr, 2):
rowrep = b''
for top, bot in zip(*rowpair):
rowrep += fabulous.color.bgtrue("#{:02x}{:02x}{:02x}".format(*bot), fabulous.color.fgtrue("#{:02x}{:02x}{:02x}".format(*top), u"\u2580")).as_utf8
if sys.version_info.major >= 3:
rowrep = rowrep.decode()
print(rowrep)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment