#!/usr/bin/env python3 import sys from argparse import ArgumentParser import numpy as n from PIL import Image UNIMAP = { " ": [0, 0, 0, 0], "█": [255, 255, 255, 255], "▄": [0, 0, 255, 255], "▀": [255, 255, 0, 0], "▌": [255, 0, 255, 0], "▐": [0, 255, 0, 255], "▖": [0, 0, 255, 0], "▗": [0, 0, 0, 255], "▘": [255, 0, 0, 0], "▝": [0, 255, 0, 0], "▚": [255, 0, 0, 255], "▞": [0, 255, 255, 0], "▙": [255, 0, 255, 255], "▛": [255, 255, 255, 0], "▜": [255, 255, 0, 255], "▟": [0, 255, 255, 255], } for key in UNIMAP: UNIMAP[key] = n.array(UNIMAP[key]) def get_ascii(c): if c > 127: return "X" if c == 0: return " " return "." def get_unicode(c): minerr = 8192 minchar = " " for key in UNIMAP: err = n.sum(n.abs(UNIMAP[key] - 4*n.clip(c,0,63))) if err < minerr: minerr = err minchar = key return minchar def png2uni(inFile): im = Image.open(inFile).convert("L") # ~ im = im.resize((im.size[0], int(im.size[1]/2)), Image.BICUBIC) # ~ im = im.resize((2 * im.size[0], int(im.size[1])), Image.NEAREST) pixels = im.load() chars = [["." for c in range(0, int(im.size[0] / 2))] for r in range(0, int(im.size[1] / 2))] for r in range(0, im.size[1], 2): for c in range(0, im.size[0], 2): try: char = get_unicode( n.array([pixels[c + 0, r + 0], pixels[c + 1, r + 0], pixels[c + 0, r + 1], pixels[c + 1, r + 1]]) ) c_r = int(r / 2) c_c = int(c / 2) chars[c_r][c_c] = char except IndexError: pass for row in chars: print("".join(row)) def png2asc(inFile): im = Image.open(inFile).convert("L") pixels = im.load() for r in range(im.size[1]): for c in range(im.size[0]): char = get_ascii(pixels[c, r]) sys.stdout.write(char) sys.stdout.write("\n") def asc2png(inFile, outFile): reader = open(inFile, "r") coords = [] max_c = 0 for r, row in enumerate(reader): for c, col in enumerate(row): if col not in (" ", "\n"): if col == ".": coords.append((r, c, 127)) else: coords.append((r, c, 255)) max_c = max(max_c, c) im = n.zeros((r + 1, max_c), dtype=n.uint8) for c in coords: im[c[0], c[1]] = c[2] data = Image.fromarray(im) data.save(outFile) if __name__ == "__main__": parser = ArgumentParser( description="Convert image to ascii, or ascii to image. If only input is defined, it is assumed as image (PNG)." ) parser.add_argument("--unicode", "-u", default=False, action="store_true", help="Unicode characters") parser.add_argument("input", action="store") parser.add_argument("output", action="store", nargs="?") opts = parser.parse_args() if opts.output == None: if opts.unicode: png2uni(opts.input) else: png2asc(opts.input) else: asc2png(opts.input, opts.output)