likes
comments
collection
share

把终端打造成一个画布

作者站长头像
站长
· 阅读数 13

TL;DR: github.com/shiyangzhao…

前言

经常想在终端输出好看的内容,奈何终端不给力,那如何把 Terminal 打造成一个画布,让自己的终端与众不同起来呢? 总体来说需要关注两个方面:颜色和像素。

把终端打造成一个画布

颜色

我们经常需要在中终端输出五颜六色的重要信息以引起用户的注意,比如用绿色告诉用户操作成功,用红色告诉用户操作失败。一般来说,我们都是使用 chalk 来输出“有颜色”的信息。

把终端打造成一个画布

关于 chalkchalk 是一个 Node.js 包,它允许您在控制台中使用 ANSI 转义序列添加颜色和样式。这对于在终端中输出彩色文本非常有用,因为您可以使用不同的颜色和样式来区分输出。要在 Node.js 中使用 chalk,可以使用 chalk.<style> 方法来应用样式。例如,您可以使用 chalk.red('Hello world!') 将文本设置为红色。要使用多个样式,可以将它们链接在一起,例如 chalk.red.bold('Hello world!') 将文本设置为红色和粗体。有许多不同的样式可用于定制您的输出。有关更多详细信息,请参见 chalk 的文档

上面提到了一个的知识点,“ANSI 转义序列”,搜索资料可知:

ANSI 转义序列是用于在控制台或终端中添加格式和颜色的一种方法。它们以 \\u001B[ 开头,后面是一个或多个数字和字符,用于指定要应用的格式或颜色。例如,\\u001B[31m 表示红色文本,\u001B[1m 表示粗体文本。例如,要在控制台中打印红色粗体文本,可以使用 console.log('\u001B[1m\u001B[31mHello, world!\u001B[0m')

把终端打造成一个画布

通俗表达: 如果你需要输出有特定效果的字符,只需要 \u001B[code;codem + 你的文本 即可,多种效果只需要:

把终端打造成一个画布

上述几个命令在结尾添加了 \u001B[0m ,这个是为什么呢,尝试删除

把终端打造成一个画布

发现后续输出的文本保留了颜色和加粗的效果,颜色的话,尝试了几种,如果不去清除,都是变成黄色,这大概就是 “it was all yellow” 。

nNameNote
0Reset or normalAll attributes off
1Bold or increased intensityAs with faint, the color change is a PC (SCO / en.wikipedia.org/wiki/Color_…) invention.en.wikipedia.org/wiki/ANSI_e…
2Faint, decreased intensity, or dimMay be implemented as a light en.wikipedia.org/wiki/Font_w… like bold.en.wikipedia.org/wiki/ANSI_e…
3ItalicNot widely supported. Sometimes treated as inverse or blink.en.wikipedia.org/wiki/ANSI_e…
4UnderlineStyle extensions exist for Kitty, VTE, mintty and iTerm2.en.wikipedia.org/wiki/ANSI_e…
5Slow blinkSets blinking to less than 150 times per minute
6Rapid blinkMS-DOS ANSI.SYS, 150+ per minute; not widely supported
7en.wikipedia.org/wiki/Revers… or invertSwap foreground and background colors; inconsistent emulationhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-console-termio-realize-43
8Conceal or hideNot widely supported.
9en.wikipedia.org/wiki/Strike…, or strikeCharacters legible but marked as if for deletion. Not supported in Terminal.app
10Primary (default) font
11–19Alternative fontSelect alternative font n − 10
20en.wikipedia.org/wiki/Fraktu… (Gothic)Rarely supported
21Doubly underlined; or: not boldDouble-underline per ECMA-48,en.wikipedia.org/wiki/ANSI_e… 8.3.117  but instead disables bold intensity on several terminals, including in the en.wikipedia.org/wiki/Linux_… en.wikipedia.org/wiki/Linux_… before version 4.17.en.wikipedia.org/wiki/ANSI_e…
22Normal intensityNeither bold nor faint; color changes where intensity is implemented as such.
23Neither italic, nor blackletter
24Not underlinedNeither singly nor doubly underlined
25Not blinkingTurn blinking off
26Proportional spacingen.wikipedia.org/wiki/ITU_T.… and T.416, not known to be used on terminals
27Not reversed
28RevealNot concealed
29Not crossed out
30–37Set foreground en.wikipedia.org/wiki/ANSI_e…
38Set foreground en.wikipedia.org/wiki/ANSI_e…en.wikipedia.org/wiki/ANSI_e…
39Default foreground colorImplementation defined (according to standard)
40–47Set background en.wikipedia.org/wiki/ANSI_e…
48Set background en.wikipedia.org/wiki/ANSI_e…en.wikipedia.org/wiki/ANSI_e…
49Default background colorImplementation defined (according to standard)
50Disable proportional spacingT.61 and T.416
51FramedImplemented as "en.wikipedia.org/wiki/Variat…" in mintty.en.wikipedia.org/wiki/ANSI_e…
52Encircled
53OverlinedNot supported in Terminal.app
54Neither framed nor encircled
55Not overlined
58Set underline en.wikipedia.org/wiki/ANSI_e…Not in standard; implemented in Kitty, VTE, mintty, and iTerm2.en.wikipedia.org/wiki/ANSI_e… en.wikipedia.org/wiki/ANSI_e….
59Default underline colorNot in standard; implemented in Kitty, VTE, mintty, and iTerm2.en.wikipedia.org/wiki/ANSI_e…
60Ideogram underline or right side lineRarely supported
61Ideogram double underline, or double line on the right side
62Ideogram overline or left side line
63Ideogram double overline, or double line on the left side
64Ideogram stress marking
65No ideogram attributesReset the effects of all of 60–64
73SuperscriptImplemented only in minttyhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-mintty-45
74Subscript
75Neither superscript nor subscript
90–97Set bright foreground colorNot in standard; originally implemented by aixtermhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-xtc-30
100–107Set bright background color

ANSI 的颜色

3-bit and 4-bit

初始的规格只有8种颜色,参数30-37选择前景色,40-47选择背景色,相当多的终端将“粗体”(SGR代码1)实现为更明亮的颜色而不是不同的字体,从而提供了8种额外的前景色。

把终端打造成一个画布

8-bit

随着显卡中的 256 色查找越来越常见,相应的 ANSI 转义序列也增加了,可以从 256 个颜色中挑选

ESC[38;5;⟨n⟩m Select foreground color      where n is a number from the table below
ESC[48;5;⟨n⟩m Select background color
  0-  7:  standard colors (as in ESC [ 3037 m)
  8- 15:  high intensity colors (as in ESC [ 9097 m)
 16-231:  6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
232-255:  grayscale from dark to light in 24 steps

实际结构变成: \u001B[${38 + offset};5;${code}m

把终端打造成一个画布

24-bit

受显卡的发展,Xterm、KDE的Konsole,以及所有基于libvte的终端(包括GNOME终端)支持了24位前景色和背景色设置(我们使用的 iTerm 肯定也是支持的

ESC[38;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB foreground color
ESC[48;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB background color

实际使用的格式:\u001B[${38 + offset};2;${red};${green};${blue}m

像素点

颜色的问题基本上解决了,现在需要处理的就是 Canvas 中的像素点的问题,如何实现一个像素。查找了很多资料,找到一个比较好的方案,“半块字符”,“▀”和“▄”,实际使用 “▀” 非常好用:

把终端打造成一个画布

多么 标准的一个像素啊,是不是可以直接用它来实现呢?答案是不行,原因是:

console.log("▀▀\n▀▀");

把终端打造成一个画布

我想做一个 2 * 2 的画布,因为它只是半块字符,没法填充满,完了,这下路不是堵死了?

把终端打造成一个画布

聪明的你一定想到如何去处理了,答案就是背景色:

console.log("\u001B[40;m▀\u001B[0m")

把终端打造成一个画布

把终端打造成一个画布

我如果想做一个 2 * 2 的画布:

console.log("\u001B[40;m▀\u001B[40;m▀\u001B[0m")

把终端打造成一个画布

渲染图片:

总之是以上下两个像素作为一个单位去遍历 把终端打造成一个画布

Coding

github.com/shiyangzhao…

成果

素材:

把终端打造成一个画布

效果:

把终端打造成一个画布

好看的:

把终端打造成一个画布

Mac 自带的终端貌似是 16-bit:

把终端打造成一个画布

其他工具

  1. hpjansson.org/chafa/
  2. en.wikipedia.org/wiki/Sixel
  3. github.com/sindresorhu…

TODO

  1. 是否能像 Canvas 一样使用双缓冲技术来提高性能(做动画时)
  2. 设置宽高时保留图片比例
  3. 禁用换行,换行样式会乱

注意事项

你应该使用像素级别的图片...

素材来源:www.figma.com/community/f…