字符画艺术(ASCII ART),是一种用字符来表述图像的视觉艺术。早期打印机擅长文本而非图形,简单的字符(如 ASCII 等)经过精心排列可形成生动有趣的“图形”,由此演化出一种独特的字符画艺术。

字符画有多种类型,包括:

  • 符号表情(颜文字)
:-D  | 开心
:-(  | 不开心
  • 拟物
  |\_/|
 / @ @ \
( > º < )
 `>>x<<´
 /  O  \ 
  • 艺术文字
            _ _
  /\  /\___| | | ___  
 / /_/ / _ \ | |/ _ \ 
/ __  /  __/ | | (_) |
\/ /_/ \___|_|_|\___/ 
  • 图片

本文介绍艺术文字和图片的字符画生成方法。

艺术字

对于艺术字,有许多现成的库供选择,但遗憾尚未发现支持中文的相关库。 pyfiglet 是众多选择之一,它内置丰富多样的字体供选择。

>>> import pyfiglet
>>> def ascii_text(content, font='isometric1'):
...     result = pyfiglet.figlet_format(content, font=font)
...     return result
... 

>>> ascii_text('Python', 'isometric1')
      ___           ___           ___           ___           ___           ___     
     /\  \         |\__\         /\  \         /\__\         /\  \         /\__\    
    /::\  \        |:|  |        \:\  \       /:/  /        /::\  \       /::|  |   
   /:/\:\  \       |:|  |         \:\  \     /:/__/        /:/\:\  \     /:|:|  |   
  /::\~\:\  \      |:|__|__       /::\  \   /::\  \ ___   /:/  \:\  \   /:/|:|  |__ 
 /:/\:\ \:\__\     /::::\__\     /:/\:\__\ /:/\:\  /\__\ /:/__/ \:\__\ /:/ |:| /\__\
 \/__\:\/:/  /    /:/~~/~       /:/  \/__/ \/__\:\/:/  / \:\  \ /:/  / \/__|:|/:/  /
      \::/  /    /:/  /        /:/  /           \::/  /   \:\  /:/  /      |:/:/  / 
       \/__/     \/__/         \/__/            /:/  /     \:\/:/  /       |::/  /  
                                               /:/  /       \::/  /        /:/  /   
                                               \/__/         \/__/         \/__/  
                                            
>>> ascii_text('Python', '5lineoblique')
    //   ) )                                                
   ((         ___     / __      ___      _   __      ___    
     \\     //   ) ) //   ) ) //___) ) // ) )  ) ) //___) ) 
       ) ) //       //   / / //       // / /  / / //        
((___ / / ((____   //   / / ((____   // / /  / / ((____     

pyfiglet 生成字符的原理并不神秘,字体文件中已经包含每个字母的字符画,程序只需使用相应的字体包来生成目标单词的字符画即可。

图片

原理很简单:将图片颜色转化成灰度,然后像素点映射到一组字符上。字符序列 ascii_char 的呈现着色递减的趋势。函数 ascii_img 接收图片链接,返回字符串。与像素格不同,字符的长宽比不是 1:1, fix_rate 用来调节长宽比。可选参数 point_num 用来设置字符数。

ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.   "

def get_char(r, g, b, alpha=256):
    if alpha == 0:
        return ' '
    length = len(ascii_char)
    gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
    unit = (256.0 + 1) / length
    return ascii_char[int(gray/unit)]

def get_image(url):
    response = requests.get(url, timeout=2)
    image = Image.open(BytesIO(response.content))
    return image

def ascii_img(url, fix_rate, point_num = 8000):
    im = get_image(url)
    rate = im.size[0]/im.size[1] * fix_rate
    height = int(math.sqrt(point_num / rate))
    width = point_num // height
    im = im.resize((width, height), Image.NEAREST)
    txt = ""
    for i in range(height):
        for j in range(width):
            txt += get_char(*im.getpixel((j,i)))
        txt += '\n'
    return txt

对于颜色区分大、内容简单的图片,字符生成结果很好。下面是两个示例:

onepunchman

daliu