Making art in the terminal window

The 24-Bit True Color Mode

For those who believe no number of colors is too many, there's True Color mode: 24-bit RGB.

This mode supports over 16.7 million colors, the same as your monitor (assuming it isn't from the same era as ANSI itself).

To bring the colors to life, you can use the following syntax:

\033[38;2;<r>;<g>;<b>m<C> : Foreground
\033[48;2;<r>;<g>;<b>m<C> : Background

For example:

std::cout << "\033[38;2;255;128;0mOrange text\033[0m\n";
std::cout << "\033[48;2;0;64;128mBlue background\033[0m\n";

With all this in mind, now you can create a beautiful color picker, as shown in Figure 2. Not as sophisticated as the one you would get from a native GUI application, and still missing a mouse, but the color picker in Figure 2 still does the job if you are willing to move around with the cursor keys to browse the colors and use s and w for adjusting the luminosity.

Figure 2: The color picker.

The source of this colorful beauty is to be found in colorsel.cpp, but sadly, it is too long to waste the paper of a printed journal on it. The best way to understand the application of this color picker is to take a small detour into color spaces.

Color Spaces

Color representation in digital systems is most commonly modeled using the RGB and HSV color spaces, each optimized for different purposes. The RGB model (Red, Green, Blue) is an additive system in which colors are generated by combining varying intensities of these three primary components. Each component typically ranges from zero to its maximum, conventionally 255 in 8-bit systems.

RGB can be visualized as a three-dimensional cube: The origin corresponds to black, the vertex at maximal intensity in all three channels corresponds to white, and the edges represent the pure primary colors. Intermediate points within the cube generate all possible colors achievable by additive mixing of the three components. While this model is directly aligned with the physical mechanisms of light emission in displays, it is not particularly intuitive for human color perception, as the perceptual differences between colors do not correspond linearly to distances within the RGB cube.

To address perceptual intuitiveness, the HSV model (Hue, Saturation, Value) is often employed. Hue is the qualitative aspect of color, representing angles along a 360-degree color wheel, where 0 is red, 120 is green, and 240 is blue. Saturation quantifies the purity or intensity of the color, ranging from zero (a neutral gray) to one (fully saturated). Value measures the brightness of the color, from complete black at zero to maximum brightness at one. This model can be visualized as a cylindrical or conical volume: Hue determines the angular coordinate, saturation the radial distance from the central axis, and value the vertical axis.

Conversion between HSV and RGB is mathematically straightforward and involves a complex mathematical formula I will skip for now.

Figure 3, which we bravely borrowed from the researchgate.net website [2] depicts the relationship between the two color spaces.

Figure 3: How color is visualized: the RGB cube versus the HSV cylinder.

A Word on Compatibility

Not every terminal speaks fluent RGB. Most modern terminals fully support 24-bit, and some older ones only understand 256-color mode. The ancient ones spoke only green. If you're unsure, you can test with a short script, such as:

[[ "$COLORTERM" == *truecolor* || "$COLORTERM" == *24bit* ]] && echo "True Color supported" || echo "No True Color"

or just print a rainbow and see what happens (Listing 2).

Listing 2

Printing a Rainbow

awk -v w=80 'BEGIN{for(i=0;i<w;i++){r=int(128+127*cos(i*6.283/w));g=int(128+127*cos(i*6.283/w+2.094));\
  b=int(128+127*cos(i*6.283/w+4.188));printf "\033[48;2;%d;%d;%dm ",r,g,b}print "\033[0m"}'

Buy this article as PDF

Download Article PDF now with Express Checkout
Price $2.95
(incl. VAT)

Buy Linux Magazine

Related content

  • Animation with OpenToonz

    OpenToonz is a professional animation tool for comic and manga artists.

  • FOSSPicks

    Graham has just recorded a one-off podcast featuring the wonderful open source VCV Eurorack emulator, often written about here. He's now strongly considering doing a more regular synth-related podcast.

  • Next Steps in Vector Graphics

    What are vector graphics and how could we make them better?

  • Graphics in Python with Cairo

    Build graphic elements into your Python programs with the Cairo graphics library. We'll show you how to draw an analog clock face that displays the current time.

  • FOSSPicks

    This month Graham looks at Plasma System Monitor, projectM audio visualizer, yt-dlg downloader GUI, and more.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News