Created
August 5, 2019 15:25
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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