Using Colours in a Console

Using Colours in a Console

It is possible to use different colours for the text a program writes to a console display. This can be achieved using ANSI escape sequences, assuming the console program supports this ANSI standard. QNX's Pterm console does. Escape sequences are series of ordinary ASCII characters that have predefined meanings. The terminal knows the difference between a series of characters that should be displayed in the usual way, and a series of characters that is actually an escape sequence by the identity of the first character of the sequence. This is the escape character, which has the value 26 (0x1b, the classic ASCII ESC character) or the value 156 (0x9b) depending on the terminal.

The length of the escape sequences varies depending on the command and some have additional, optional, parameters. The terminal knows when the escape sequence has ended since each escape sequence is well defined and terminates in a specific byte value that cannot occur in any other part of the same sequence.

The escape sequences defined by ANSI are numerous and complicated, and this is a brief introduction so we'll just stick to changing colours. For more information, search the QNX help system for the word “ansi”.

From ANSI's point of view, there are two types of console, 7 bit, and 8 bit. Pterm is 8 bit, so we'll use the 8 bit command (0x9b). The following simple C program demonstrates how to print using each of the palette entries for foreground, and a couple of entries for the background. The program uses three different commands.

ANSI defines 16 colours for terminals, which actually consist of 8 different colours at two different intensity levels (light and dark). One important thing to note is that the command to change colour does not take into account the intensity level. The intensity level is set or reset using a different command.

The first byte of the escape sequence is the escape character itself. For the 8 bit Pterm, this has the value 0x9b. The next byte is the command type, and the following bytes vary depending on the command. Note that these hex values are the actual values of the characters written by the printf()s, rather than the actual text! For instance, writing the byte 0x3d is the same as writing the character ‘=’. Furthermore, the bytes used to refer to the colour palete entries correspond to the ASCII character, and not the byte value. So, to refer to palette entry one, you use the ASCII character ‘1’, which has byte value 0x31. This can get a bit confusing when reading the escape sequence definitions.

Here is a list of the escape sequences used in the program.

   
#include <stdio.h>
int
main( )
{
   char esc_code = 0x9B; /* 8 bit escape */

   /* Default background is probably black, so change it to 
    * white so that a black foreground will be visible */
   printf("%c1m%c=7G",esc_code, esc_code);

   printf("%c0m%c=0F Pure Black\t\t\t\t", esc_code,esc_code);

   /* Change background to black for rest of foreground colours */
   printf("%c0m%c=0G",esc_code, esc_code);

   printf("%c1m%c=0F Light Black (Dark grey)\n", esc_code,esc_code);

   printf("%c0m%c=1F Red\t\t\t", esc_code, esc_code);
   printf("%c1m%c=1F Light Red\n",esc_code, esc_code);

   printf("%c0m%c=2F Green\t\t\t",esc_code, esc_code);
   printf("%c1m%c=2F Light Green\n",esc_code, esc_code);

   printf("%c0m%c=3F Brown\t\t",esc_code, esc_code);
   printf("%c1m%c=3F Light Brown (Yellow)\n",esc_code, esc_code);

   printf("%c0m%c=4F Blue\t\t\t",esc_code, esc_code);
   printf("%c1m%c=4F Light Blue\n",esc_code, esc_code);

   printf("%c0m%c=5F Magenta\t\t\t",esc_code, esc_code);
   printf("%c1m%c=5F Light Magenta\n",esc_code, esc_code);

   printf("%c0m%c=6F Cyan\t\t\t",esc_code, esc_code);
   printf("%c1m%c=6F Light Cyan\n",esc_code, esc_code);

   printf("%c0m%c=7F Dark White (Light grey)\t", esc_code);
   printf("%c1m%c=7F Pure White\n",esc_code, esc_code);

   return 0;
}

Pterm's Colour Palette

The colours used in a pterm display are selected from a palette of logical colours, which can be adjusted manually. The names of each entry in this palette are predefined, but the physical colours themselves can be anything. For instance, pterm treats palette entry two (counting from zero, which is black) as green. However, the actual colour for this entry can appear as any colour on screen.

There are 16 different palette entries, corresponding to two intensity levels of 7 different colours. The colours 0 to 7 are low intensity, 8 - 15 are high intensity. The low intensity colours are the defaults.

Some colours can be difficult to read under various conditions which vary by machine, location, and user, and adjusting the colours to suit the conditions is a valuable feature. The colour palette is controlled by means of a file called pterm.pal, which pterm checks for the existence of in the directory $HOME/.ph/pterm/. This file does not exist by default, in which case pterm uses the default physical colours.

The file can be stored in binary format, but plain text is also supported, and is easier to read and write. Each entry consists of an 8-digit (four byte) hexadecimal number that has the format 0RGB. Note the first byte is always zero. By adjusting the levels of each primary colour from 00 to ff, any of the 16 million colour values can be obtained. The entries are given in the following order. The numbers refer to the entry's identities for programming (see below).

  1. Black
  2. Blue
  3. Green
  4. Cyan
  5. Red
  6. Magenta
  7. Brown (dark yellow)
  8. White (light drey)
  9. Light black (dark grey)
  10. Light Blue
  11. Light Green
  12. Light Cyan
  13. Light Red
  14. Light Magenta
  15. Yellow (light brown)
  16. Pure White

I found the predefined low intensity (default) colours to be too dark. After some experimentation, I found the following series of palette entries worked best in my circumstances:

00000000
005050ff
00009400
00008b8b
00ab0000
00bb00bb
00cd956f
00c3c3c3
00808080
0000bfff
0000ff00
0000ffff
00ff0000
00ff99ff
00ffff00
00ffffff

Home About Me
Copyright © Neil Carter

Content last updated: 2003-09-23