TOC

终端图像渲染技术

终端显示二维码或图片,本质上是在用字符(包括空格、字母、符号)或像素块来“画”出图形。由于传统命令行是纯文本设备,无法直接渲染图片文件,所以需要将图片的像素信息映射为终端能理解的表现形式。

一、两种主流的实现原理

1. 字符画(ASCII Art)

这是最古老且兼容性最好的方式。原理是将图片降采样(降低分辨率),把每个小区域的像素灰度值映射为一个字符(比如 @ 表示深色,. 表示浅色)。

  • 特点:在任何终端(包括最老的黑白终端)都能显示,但细节丢失严重,看起来像由字符组成的马赛克。
  • 常见应用cowsay 命令、早期 BBS 的欢迎界面。

2. 块元素与半角字符

比纯字符画更精细。利用 Unicode 字符集中的块元素(如 )或半角字符(如 )来构建图像。

  • 原理:利用 (下半块)和 (上半块)这样的字符,配合终端颜色,可以在一个字符位置内表现两种颜色,从而提升“分辨率”。
  • 特点:比纯字母画清晰,但依然受限于字符网格。

3. 六分之一块字符(Sixel)

维基百科:Sixel

一种较新的终端图形协议。它将像素分组(通常 6x1 或 6x2),用特殊的控制序列告诉终端如何渲染这些小色块。

  • 原理:通过转义序列(Escape Sequence)传输图形数据,终端解析后直接绘制。
  • 特点:支持颜色和更高分辨率,但需要终端支持(如 iTerm2、WezTerm)。

4. 现代终端图形协议(Kitty / iTerm2)

现代终端(如 Kitty、iTerm2、WezTerm)支持更高级的图形协议。

  • 原理:通过特定的转义序列,直接将图片数据(PNG/JPEG)传输给终端,由终端原生渲染。
  • 特点最清晰,能显示真彩图片,甚至支持动画。这是目前显示二维码最理想的方式。

二、二维码在终端的具体实现

终端显示二维码通常采用字符画块元素方式,因为二维码本身就是二值化(黑白)图像,非常适合用字符模拟。

技术细节

  1. 二值化:将二维码图片转换为纯黑白。
  2. 降采样:将二维码的模块(Module)映射到终端的字符网格。通常一个二维码模块对应终端的一个字符位置(或半个字符位置)。
  3. 映射规则
    • 黑色模块 → ██##
    • 白色模块 → (两个空格)
    • 或者使用 等块字符来提升密度。

为什么能扫出来?

  • 二维码的容错能力很强。只要模块的相对位置Finder Pattern(三个角上的回字框)大致正确,扫码软件就能识别。
  • 终端显示的“粗糙”二维码,在扫码摄像头看来,依然是清晰的黑白块结构。

Python 实现

  1. 生成二维码矩阵:使用 qrcode 库生成一个二值矩阵。
  2. 遍历矩阵:逐行读取矩阵中的 0 和 1。
  3. 输出映射
    • 遇到 1(黑色):打印 ██
    • 遇到 0(白色):打印 (两个空格)
  4. 换行:每行结束打印 \n

代码示例(Python)

import qrcode

# 生成二维码矩阵
qr = qrcode.QRCode()
qr.add_data("https://yuanbao.ai")
matrix = qr.get_matrix()

# 终端渲染
for row in matrix:
    line = ""
    for cell in row:
        line += "██" if cell else "  "
    print(line)

三、关键支撑技术:转义序列

无论哪种方式,核心都是ANSI/VT 转义序列(Escape Sequences)。这是终端与应用程序之间的“暗号”。

  • 控制颜色\033[31m 表示设置前景色为红色。
  • 控制光标\033[2J 表示清屏。
  • 显示图片:现代协议通过 \033]1337;File=... 这样的序列传输图片数据。

简单来说:程序向终端输出一串包含控制码的文本,终端解析这些控制码,决定在屏幕的哪个位置显示什么字符或颜色,从而“拼”出图像。

如果你有魔法,你可以看到一个评论框~