Why DOS only has 16 colors

0

If you’ve used conio functions to write FreeDOS programs, you may have noticed that you have a color palette of just 16 text colors, and 8 background colors. You see this “16 colors” limitation repeated in other places, too. For example, while the Linux console actually supports a wide range of text colors using “escape sequences,” your terminal app only supports a basic palette of 16 colors.

The origins of this range of limited colors goes back to how color was defined on early display devices. I’ll use DOS as an example, since that’s the color palette I grew up with.

IBM PC and color text

When the IBM Personal Computer 5150 came out in 1981, the first model supported only monochrome displays: “white on black,” although the green display in use at the time meant you really had “green on black.” Soon after, IBM provided an updated model with a new display interface: the IBM 5153 color display, which used a new IBM Color Graphics Adapter, or “CGA.” And it’s because of the original CGA that DOS inherited its 16 color palette.

Colors on a computer monitor are just a combination of three colors: red, green, and blue. If you mix equal amounts of red, green, and blue, you get white. Mix just red and green, and you get yellow. Just green and blue, you get aquamarine (named “cyan” at the time). Red and blue give you purple (called “magenta”). Without any colors, you get black.

The IBM CGA display represented colors by lighting up tiny red, green, and blue phosphor dots on the inside of the computer screen. Your modern display does the same thing, except with tiny LED red, green, and blue LED lights.

With these three “base” colors, you can turn each red, green, and blue “dot” on at full blast, or leave them off, to create one of eight different colors. I’ll represent the red, green, and blue lights in order as RGB (for “Red, Green, Blue”) and each value is either 1 (“on”) or 0 (“off”). This gives you a 3-bit binary pattern that represents RGB:

000
001
010
011
100
101
110
111

Double the colors

But that’s just a simple mixing of red, green, and blue – with each value either fully “on” or fully “off.” You can actually double the number of colors if you add a fourth bit: an “intensity” bit, giving you iRGB (the i stands for “intensity”). If the intensity bit is 1, you get full brightness for each red, green, and blue dot that is turned on. If the bit is 0, you get some midrange brightness for the RGB dots:

0000 1000
0001 1001
0010 1010
0011 1011
0100 1100
0101 1101
0110 1110
0111 1111

Adjusting the colors

But this isn’t actually 16 colors! With the iRGB color scheme, only the red, green, and blue lights get adjusted. If a bit is 0, nothing gets displayed anyway. That means that 0000 (black) and 1000 (black) are the same black.

To adjust this, the IBM PC actually used a modified iRGB color scheme, where each of the RGB values was set to zero, one-third, two-thirds, and full brightness levels. If the intensity bit is 0, then each 1 value for RGB is set to a two-thirds value, and each 0 value remains off. If the intensity bit is 1, then each 1 value for RGB shifts to full brightness, and each 0 value displays at one-third brightness. This gives a true palette of 16 unique colors:

0000 1000
0001 1001
0010 1010
0011 1011
0100 1100
0101 1101
0110 1110
0111 1111

All the colors of the rainbow

Unfortunately, this isn’t a perfect representation of colors. If you remember your 4th grade colors, you know that the colors of the rainbow are represented by the acronym, ROYGBIV, which means red, orange, yellow, green, blue, indigo, and violet. And while not all of those colors are represented perfectly in the 16 colors, we have similar colors for most of these. The only color that’s really missing in the 16-color palette is orange.

To provide an orange hue, the IBM PC modified the iRGB definition for 0110, giving the R value a two-thirds brightness and the G color a one-third brightness. This generates a color that’s pretty close to orange:

0000 1000
0001 1001
0010 1010
0011 1011
0100 1100
0101 1101
0110 1110
0111 1111

Bits and bytes

Using this modified iRGB color scheme uses only 4 bits, but a full byte can store 8 bits. IBM’s CGA used a full byte to store both text and background colors, using the first 4 bits for the background color and the last 4 bits for the text color. You’d think this gives you 16 colors for the background color, but it doesn’t. That’s because IBM made one final change.

The 8th bit was reserved for a special attribute: blinking text. With the “blink” bit set, text blinked on the screen – a typical way to display critical error messages. With one byte, DOS programs could set all attributes at once: text color, background color, and whether or not the text should blink. Thus, CGA defined 1 bit for the “blink” bit (B), 3 bits for the background color (b), and 4 bits for the text color (t):

B b b b t t t t

Unfortunately, this meant that background colors were limited to just 8 colors, while text could have all 16 colors. Some third-party graphics cards in the early 1990s supported modifying the blink bit to support bright background colors, but most traditional DOS programs were limited to combinations of 16 text colors on 8 background colors. This limited palette continues to this day.