Sunday, January 23, 2022

Convert image to printable ASCII with Python

我上大学那时还没有喷墨和激光打印机,只有9针/16针的针式打印机,只能打印ASCII字符,不能打印图像。有很酷的程序把图像转换成ASCII符。Google可以找到很多这类程序,如:

https://github.com/qeesung/image2ascii

https://github.com/uvipen/ASCII-generator

https://github.com/LazoCoder/Image-To-ASCII

这里share一个我写的比较简单的程序 (font file can be downloaded from fonts.google.com: hhttps://fonts.google.com/specimen/Courier+Prime?query=courier):

import tkinter
from tkinter import filedialog
from PIL import Image, ImageFont

def create_char_map():
characters = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
weights = []

font_name = "Courier_Prime/CourierPrime-Regular.ttf"
font_size = 16 # px
font_color = "#000000" # HEX Black
font = ImageFont.truetype(font_name, font_size)
max_weight = 0

# Loop through the characters needed and save to desired location
for character in characters:
# Get text size of character
width, height = font.getsize(character)
pix = font.getmask(character)
weight = 0
for y in range(len(pix)//width): # the actual row might be smaller than hegith
for x in range(width):
weight += pix[x+width*y]
weights.append(weight)
if weight>max_weight: max_weight = weight
# uniform the weight to 0~256*3-1
char_map = {767-int(w*767/max_weight):ch for (w, ch) in zip(weights, characters)}
# for revert image: char_map = {int(w*767/max_weight):ch for (w, ch) in zip(weights, characters)}
return char_map

def get_pixmap(path):
im = Image.open(path)
print('Original: ' + str(im.size))
size = 320
if im.size[0] > size:
resized_image = im.resize((size, int(size * im.size[1] / im.size[0])))
pixmap = resized_image.load()
pixmap_size = resized_image.size
print('Resized: ' + str(pixmap_size))
else:
pixmap = im.load()
pixmap_size = im.size
return pixmap, pixmap_size
 
def getchar(rgb_sum):
for i in range(1, len(char_keys)):
if rgb_sum<char_keys[i]:
if char_keys[i]+char_keys[i-1]>rgb_sum*2: i=i-1
break
return char_map[char_keys[i]]

def main():
#return
root = tkinter.Tk()
root.withdraw()
fin=filedialog.askopenfilename()
if(fin):
pixmap, pixmap_size = get_pixmap(fin)
file = open('output.txt', 'w')
for y in range(0, pixmap_size[1]-1, 2):
line=''
for x in range(pixmap_size[0]):
# merge two line into one printed line to keep a better ratio
rgb_sum = (pixmap[x, y][0] + pixmap[x, y][1] + pixmap[x, y][2] +
 pixmap[x, y+1][0] + pixmap[x, y+1][1] + pixmap[x, y+1][2])>>1
line+=getchar(rgb_sum)
file.write(line+'\n')
file.close()

if __name__=="__main__":
char_map = create_char_map()
char_keys = sorted(char_map)
main()

0 Comments:

Post a Comment