Skip to content

Instantly share code, notes, and snippets.

@sooop
Created May 17, 2021
Embed
What would you like to do?
import argparse
from PIL import Image, ImageDraw, ImageFont
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("filename")
parser.add_argument("-w", "--width", dest="width", type=int, default=80)
parser.add_argument("-l", "--level", dest="level", type=int, default=16)
parser.add_argument("-i", "--invert", dest="invert", action="store_true")
return parser.parse_args()
def create_char_map(levels: int = 16, inv: bool = false):
cmap = []
ft = ImageFont.truetype("g:/temp/pys/pil/CascadiaMono.ttf", size=12)
canvas = Image.new("L", (20, 20), color=0)
ctx = ImageDraw.Draw(canvas)
for i in range(128):
c = chr(i)
if c.isprintable():
ctx.rectangle((0, 0, 20, 20), 0)
ctx.text((0, 0), c, font=ft, fill=255)
val = sum(canvas.getdata())
cmap.append((val, c))
m, n = max(cmap)[0], min(cmap)[0]
cmap = [((v - n) / (m - n) * 255, c) for v, c in cmap]
result = []
for i in range(levels):
v = i / levels * 255
result.append(min(cmap, key=lambda x: abs(x[0] - v))[1])
return "".join(result if inv else result[::-1])
def convert(
img: Image.Image, width: int = 80, levels: int = 16, invert: bool = False
) -> str:
cmaps = create_char_map(levels, invert)
W = width
H = int(W / img.width * img.height)
im_res: Image.Image = img.convert("L").resize((W, H), resample=Image.BOX)
res: list[str] = []
for y in range(im_res.height):
line: list[str] = []
for x in range(im_res.width):
p = im_res.getpixel((x, y))
line.append(cmaps[int(p / 256) * levels])
res.append("".join(line))
return "\n".join(res)
if __name__ == "__main__":
args = get_args()
im = Image.open(args.filename)
print(convert(im, width=args.width, levels=args.level, invert=args.invert))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment