#!/usr/bin/env python import os, sys, argparse #NOTE: This script uses pygments for RGB->X256 conversion since pygments is #readily available. If you do not like pygments (e.g. because it is large), #you could patch in something like https://github.com/magarcia/python-x256 #(but don't forget to send me a pull request ;) from pygments.formatters import terminal256 from PIL import Image, PngImagePlugin formatter = terminal256.Terminal256Formatter() reset_sequence = terminal256.EscapeSequence(fg=formatter._closest_color(0,0,0), bg=formatter._closest_color(0,0,0)).reset_string() def termify_pixels(img): sx, sy = img.size out = '' fg,bg = None,None fgd,bgd = {},{} def bgescape(color): nonlocal bg if bg == color: return '' bg=color r,g,b,a = color if color in bgd: return bgd[color] bgd[color] = terminal256.EscapeSequence(bg=formatter._closest_color(r,g,b)).color_string() if color == (0,0,0,0): bgd[color] = terminal256.EscapeSequence(bg=formatter._closest_color(0,0,0)).reset_string() return bgd[color] def fgescape(color): nonlocal fg if fg == color: return '' fg=color r,g,b,_ = color fgd[color]= terminal256.EscapeSequence(fg=formatter._closest_color(r,g,b)).color_string() return fgd[color] #NOTE: This ignores the last line if there is an odd number of lines. def balloon(x,y): if img.getpixel((x+1, y)) != (0,255,0,127): w = 1 while img.getpixel((x-w, y)) == (0,255,0,127): w += 1 if x-w<0: break return '$balloon{}$'.format(w) return '' for y in range(0, sy-1, 2): for x in range(sx): coltop = img.getpixel((x, y)) colbot = img.getpixel((x, y+1)) if coltop[3] == 127: #Control colors out += reset_sequence out += {(255, 0, 0, 127): lambda x,y:'$\\$', (0, 0, 255, 127): lambda x,y:'$/$', (0, 255, 0, 127): balloon }.get(coltop, lambda x,y:' ')(x,y) continue if coltop[3] != 255: coltop = (0,0,0,0) if colbot[3] != 255: colbot = (0,0,0,0) #Da magicks: ▀█▄ c,cf = '▀','█' te,be = fgescape,bgescape if coltop == (0,0,0,0) or coltop == bg or colbot == fg: c,cf,te,be = '▄',' ',be,te if colbot == coltop: c,te,be = cf,te,te out += te(coltop) + be(colbot) + c out = out.rstrip() + '\n' out += reset_sequence return out if __name__ == '__main__': parser = argparse.ArgumentParser(description='Render pixel images on 256-color ANSI terminals') parser.add_argument('image', type=str) args = parser.parse_args() img = Image.open(args.image).convert("RGBA") print(termify_pixels(img))