Skip to content

Instantly share code, notes, and snippets.

@bschlenk
Created August 5, 2019 15:25
Show Gist options
  • Save bschlenk/9d24c90f21bfa75ed7881024ed56bd32 to your computer and use it in GitHub Desktop.
Save bschlenk/9d24c90f21bfa75ed7881024ed56bd32 to your computer and use it in GitHub Desktop.
Generate a node.js script that prints an image to the console using chalk. Requires pillow.
#!/usr/bin/env python3
import sys
from itertools import islice
from PIL import Image
PIXEL = '▄'
# The amount an image needs to be scaled to look good in terminal
TERM_RATIO = 0.8276
def main():
im = Image.open(sys.argv[1])
im = im.convert('RGB')
im = scale_image(im)
width, height = im.size
fgcolors = set()
bgcolors = set()
rows = []
for [row1, row2] in every_two_rows(im.getdata(), width):
log_row = []
for pair, i in dedupe(zip(row1, row2)):
bg, fg = pair
bgcolors.add(bg)
fgcolors.add(fg)
log_row.append((pair, i))
rows.append(log_row)
fgcolors = sorted(list(fgcolors))
bgcolors = sorted(list(bgcolors))
fgmap = {}
bgmap = {}
def do_map(l, m, n):
for i, c in enumerate(l):
name = f'{n}{i}'
args = ', '.join(map(str, c))
if n == 'bg':
print(f'const {name} = chalk.bgRgb({args});')
else:
print(f'const {name} = chalk.rgb({args});')
m[c] = name
print("const chalk = require('chalk');")
print()
do_map(fgcolors, fgmap, 'fg')
do_map(bgcolors, bgmap, 'bg')
print()
for row in rows:
parts = []
for (bg, fg), count in row:
bgfn = bgmap[bg]
fgfn = fgmap[fg]
if bgfn == fgfn:
parts.append(f"{bgfn}(' ')")
else:
parts.append(f"{bgfn}({fgfn}('{PIXEL*count}'))")
joined = ''.join(map(lambda x: f'${{{x}}}', parts))
print(f"console.log(`{joined}`);")
def dedupe(data):
same = []
for d in data:
if not same or len(set(same + [d])) == 1:
same.append(d)
else:
yield same[0], len(same)
same = [d]
if same:
yield same[0], len(same)
def every_two_rows(data, width):
curr_row = []
rows = []
for d in data:
curr_row.append(d)
if len(curr_row) == width:
rows.append(curr_row)
curr_row = []
if len(rows) == 2:
yield rows
rows = []
if len(rows) == 1:
rows.append([(0,0,0)] * width)
yield rows
def scale_image(img):
# first, resize due to terminal scaling
width, height = img.size
if width > 64:
scale = 64/width
width = int(width*scale)
height = int(height*scale)
img = img.resize((width, height))
return img.resize((width, int(height * TERM_RATIO)), Image.BICUBIC)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment