把终端打造成一个画布
TL;DR: github.com/shiyangzhao…
前言
经常想在终端输出好看的内容,奈何终端不给力,那如何把 Terminal 打造成一个画布,让自己的终端与众不同起来呢? 总体来说需要关注两个方面:颜色和像素。
颜色
我们经常需要在中终端输出五颜六色的重要信息以引起用户的注意,比如用绿色告诉用户操作成功,用红色告诉用户操作失败。一般来说,我们都是使用 chalk
来输出“有颜色”的信息。
关于
chalk
,chalk
是一个 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” 。
n | Name | Note | |
---|---|---|---|
0 | Reset or normal | All attributes off | |
1 | Bold or increased intensity | As with faint, the color change is a PC (SCO / en.wikipedia.org/wiki/Color_…) invention.en.wikipedia.org/wiki/ANSI_e… | |
2 | Faint, decreased intensity, or dim | May be implemented as a light en.wikipedia.org/wiki/Font_w… like bold.en.wikipedia.org/wiki/ANSI_e… | |
3 | Italic | Not widely supported. Sometimes treated as inverse or blink.en.wikipedia.org/wiki/ANSI_e… | |
4 | Underline | Style extensions exist for Kitty, VTE, mintty and iTerm2.en.wikipedia.org/wiki/ANSI_e… | |
5 | Slow blink | Sets blinking to less than 150 times per minute | |
6 | Rapid blink | MS-DOS ANSI.SYS, 150+ per minute; not widely supported | |
7 | en.wikipedia.org/wiki/Revers… or invert | Swap foreground and background colors; inconsistent emulationhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-console-termio-realize-43 | |
8 | Conceal or hide | Not widely supported. | |
9 | en.wikipedia.org/wiki/Strike…, or strike | Characters legible but marked as if for deletion. Not supported in Terminal.app | |
10 | Primary (default) font | ||
11–19 | Alternative font | Select alternative font n − 10 | |
20 | en.wikipedia.org/wiki/Fraktu… (Gothic) | Rarely supported | |
21 | Doubly underlined; or: not bold | Double-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… | |
22 | Normal intensity | Neither bold nor faint; color changes where intensity is implemented as such. | |
23 | Neither italic, nor blackletter | ||
24 | Not underlined | Neither singly nor doubly underlined | |
25 | Not blinking | Turn blinking off | |
26 | Proportional spacing | en.wikipedia.org/wiki/ITU_T.… and T.416, not known to be used on terminals | |
27 | Not reversed | ||
28 | Reveal | Not concealed | |
29 | Not crossed out | ||
30–37 | Set foreground en.wikipedia.org/wiki/ANSI_e… | ||
38 | Set foreground en.wikipedia.org/wiki/ANSI_e… | en.wikipedia.org/wiki/ANSI_e… | |
39 | Default foreground color | Implementation defined (according to standard) | |
40–47 | Set background en.wikipedia.org/wiki/ANSI_e… | ||
48 | Set background en.wikipedia.org/wiki/ANSI_e… | en.wikipedia.org/wiki/ANSI_e… | |
49 | Default background color | Implementation defined (according to standard) | |
50 | Disable proportional spacing | T.61 and T.416 | |
51 | Framed | Implemented as "en.wikipedia.org/wiki/Variat…" in mintty.en.wikipedia.org/wiki/ANSI_e… | |
52 | Encircled | ||
53 | Overlined | Not supported in Terminal.app | |
54 | Neither framed nor encircled | ||
55 | Not overlined | ||
58 | Set 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…. | |
59 | Default underline color | Not in standard; implemented in Kitty, VTE, mintty, and iTerm2.en.wikipedia.org/wiki/ANSI_e… | |
60 | Ideogram underline or right side line | Rarely supported | |
61 | Ideogram double underline, or double line on the right side | ||
62 | Ideogram overline or left side line | ||
63 | Ideogram double overline, or double line on the left side | ||
64 | Ideogram stress marking | ||
65 | No ideogram attributes | Reset the effects of all of 60–64 | |
73 | Superscript | Implemented only in minttyhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-mintty-45 | |
74 | Subscript | ||
75 | Neither superscript nor subscript | ||
90–97 | Set bright foreground color | Not in standard; originally implemented by aixtermhttps://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-xtc-30 | |
100–107 | Set 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 [ 30–37 m)
8- 15: high intensity colors (as in ESC [ 90–97 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
成果
素材:
效果:
好看的:
Mac 自带的终端貌似是 16-bit:
其他工具
TODO
- 是否能像 Canvas 一样使用双缓冲技术来提高性能(做动画时)
- 设置宽高时保留图片比例
- 禁用换行,换行样式会乱
注意事项
你应该使用像素级别的图片...
转载自:https://juejin.cn/post/7214037206863839269