This story began when I learned about existence bpytop ... I was amazed at the detail of the charts and I began to figure out how it was done. It turned out that Braille characters were used to display the graphs, which are a combination of 8 points: 2 points in width and 4 points in height. After looking for ready-made solutions using this approach, I found on reddit announcement such the project ... In the very first comment of the announcement, I read:
It's cool, but why don't people just rediscover ReGIS (vector graphics in the terminal) and sixel (pixel graphics in the terminal).Until this moment, I did not know anything about sixel. Digging deeper, I found out that in theory sixel should be supported by xterm. I ran xterm on my ubuntu 20.04 in vt340 emulation mode
xterm -xrm "XTerm*decTerminalID: vt340" -xrm "XTerm*numColorRegisters: 256"executed the following command (convert is a command from the imagemagick package)
clear && convert <(curl -s https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png) sixel:-and saw this:
Wow, it works!
First of all, I checked that sixel can be found on Habré. It turned out that not a lot. There is a very short article 2010 without technical details and mention in comments to article about porting Far to Linux. Let's see how sixel works and how you can draw with it in a compatible terminal.
The sixel mode is enabled by the escape sequence DCSp1; p2; p3; q, where DCS is the Device Control Sequence (it can be either an eight-bit character with decimal value 144, or a sequence of two seven-bit characters "Escape", "P". Parameters p1, p2 and p3 optional.
|p1||Pixel Aspect Ratio (Vertical:Horizontal)|
|Not specified||2:1 (default)|
|7, 8, 9||1:1|
p2 can take 3 values and determines how the terminal draws the background color.
|p2||What is he doing|
|0 or 2 (default)||Pixels with a value of 0 are drawn with the current background color.|
|1||The color of pixels with a value of 0 does not change.|
In my experiments in xterm, I always entered sixel mode using the sequence 0x1bPq (0x1b - escape) without using optional parameters.
The sixel mode is turned off by the ST (String Terminator) sequence. ST can be either an 8-bit character with a decimal value of 156 or a sequence of two 7-bit characters "Escape, backslash" (ESC \).
After switching the output device to sixel mode, we need to supply graphic data to it. The name sixel is derived from six pixels. In sixel mode, we draw a column of 6 pixels at a time (the least significant bit is the top). Rendering is carried out in the selected color (more on this later). The value of one pixel can be from 0 (all bits 0) to 63 (all bits 1). This value is added to 63 (ascii '?'). Thus, an empty pixel is represented by '?', And a pixel with all bits set to 1 by '~'.
The sixel format provides primitive compression. The construction '! 42 ~' means that we want to output the pixel '~' 42 times. The official documentation does not mention any restrictions on the counter values. Wherein known that vt240 does not use values greater than 255 when dumping graphic data.
When outputting a sixel line, there are 2 ways to control the cursor. The '$' character moves the cursor to the beginning of the same line. This allows pixels to be displayed in different colors. You can select a color, display a set of pixels, return to the beginning of the same line, select a different color, display a different set of pixels. After the current line is drawn properly, you can use the '-' symbol and move the cursor to the next line.
Color management is carried out in 2 stages. First, we need to define the color registers. This can be done with the command #NN; p1; p2; p3; p4. Here
NN register number (from 0 to 255)
p1 - type of color space (1 - HLS or 2 - RGB)
p2, p3, p4 - hue, lightness, saturation values for HLS or red, green, blue for RGB. Allowed parameter values are from 0 to 100 for all except hue, which can vary from 0 to 360.
Now, to switch to a specific color, we need to use a command like #NN.
Armed with this information, we can write the code which will display the following image for us:
For comparison, this is how the same image will look like. code using braille characters:
And the same image displayed code using plain ascii:
|Vote for this post
Bring it to the Main Page