PCX graphics files explained

The PCX graphic file was originally used for the PC-based Paint program. It was developed
by Zsoft Corporation. The last known version was in 1991 but is still used by most all
DOS graphical programs and still some Windows programs (MS Paint).

The PCX file format can support 24-bit color, either as a palette of up to 256 colors or
as full, 24-bit RGB, with image sizes of 64k x 64k pixels. PCX files use Run-Length
Encoding (RLE).

The PCX file format must contain two parts: The file header, and the bitmap data. In the
later versions, it also contained a palette of up to 256 colors (located at EOF).

The header has a fixed size of 128 bytes. It contains information about the image contained
in the PCX file. For instance; the size, color or grayscale, and also it might contain
a 48 byte palette.

Next is the bitmap data, or the body of the PCX file.

If the version code (indicated in the header) is 5 and there is a single bit plane, then
there is a 256-color palette of RGB values at the end of the file and is 768 bytes in
length. So to find the palette, find the end of the file, and go back 768 bytes. The
byte just before the palette has the value 10 (0Ah)

Offset  Size    Contents      Meaning
  00     01    0Ah (10)      Zsoft ID byte
  01     01    varies        Version
                               0 = PC Paintbrush 2.5
                               2 = PC Paintbrush 2.8 w/palette
                               3 = PC Paintbrush 2.8 w/out palette
                               4 = PC Paintbrush for Windows
                               5 = PC Paintbrush 3.0, IV, IV Plus,
                                       and Publishers Paintbrush
  02     01    1             Encoding (PCX run-length encoding)
  03     01    varies        Bits/pixel (each plane)
  04     08    varies        Image dimensions Xmin, Ymin, Xmax, Ymax
  12     02    varies        Horizontal Res.
  14     02    varies        Vertical Res.
  16     48    varies        Header palette
  64     01    00            reserved
  65     01    varies        number of planes
  66     02    varies        bytes/line (memory needed for one plane
                                  of each horiz. line)
  68     02    01 or 02      Header interpretation
                               1 = color or B&W
                               2 = grayscale
  70     02    varies        Video screen size (Horizontal)
  72     02    varies        Video screen size (Vertical)
  74     54    ----blanks to end of header----

Because there can be so many variations of the PCX file format, the version
can not be an adequate guide. The most reliable guide to use are the bits/pixel
and the number of color planes. The following table describes how to use these
two fields as the indicator for the type of PCX file.

Interpretation of the PCX data
Bts/pxl   # planes    Interpretation
    1       1           monochrome
    1       2           4 colors
    1       3           8 colors
    1       4           16 colors
    2       1           4 colors using CGA header palette*
    2       4           16 colors
    4       1           16 colors using EGA header palette*
    8       1           256 colors using palette at EOF
    8       3           16.7mil colors

*If version 5, use palette at EOF, not palette in header

If no palette is used:
The data is actual pixel values, RGB.
It is formatted as RRRRRR...GGGGGG...BBBBBB and so on.

If there are two planes, the colors are arbitrary. If there are three planes, the colors
are RGB. When four planes are used, they are usually the 1-bit planes of the IBM CGA/EGA
standard: RGBI (I=intensity). The intensity bit simply gives a pixel a nominally higher

When data are pointers to a palette:
When data are pointers to a palette, each individual data piece points to a position in
the palette. The length of each data piece varies. If it is 16 colors, a 4 bit color,
then each data piece is a nibble (half a byte).

NOTE: In the palette-based images, there is only 1 plane.

The 256 color scheme (EOF palette scheme)
Each piece of data (each pixel) takes one byte to represent the offset of the RGB color
scheme to use. For example: If the pixel value is 0 (zero), then go to the front of the
palette and use the first 3 bytes as the RGB values (respectively). If the pixel value is
1, then use the fourth, fifth, and sixth positions as the RGB values (respectively). etc.

Because the VGA provides only 64 levels of R,G, and B, the palette values must be divided by
four (shr 2 times) when reading the PCX file for VGA display.

The 16 color scheme (EGA/VGA header palette scheme)
The palette in the header is divided in to three 16 byte sections, one for each R,G, and B
value. 16 bytes for R, 16 bytes for G, and 16 bytes for B.

The 24 bit color scheme
Each 24-bit color scheme has eight bits/pixel/plane and three-bit planes.

Run Length Encoding (RLE)
In RLE compression, a series of repeated values is replaced by a count and a single value.
But keep in mind. If I have a lot of single values (not a series of identical values), then
this type of compression would double the size of my file. So rather than use RLE on a series
of non identical values, just store the values with no count value before it.

This makes a problem though. How do you tell if a value is a part of a 2 byte 'count-value'
value, or is that value a direct individual (no count) value to by displayed? The solution
is to make each value that is a count value (a value that you will take the next value and
repeat it) have bits 6 and 7 set. If bits 6 and 7 are set, then clear them, and take the
returned value as the count value. Then take the next value and repeat it count times. Note:
Once you have the count value, the pixel value can have a value of 0-255 (bits 6 and 7 can be set).

This makes another problem. How to display a single value of 192 or higher. First, you must
make a count value of 1 (11000001b) then the display value of 192 (or higher) (makes a 2 byte

Here is an example of RLE compression:
The data to be encoded: (in byte values)
-----> 0,10,63,63,63,63,120,34,34,222,222,222,222,1,222,5,10,0,0,0,0,12,12,255
The encoded data from the above data: (in byte values)
-----> 0,10,196,63,120,194,34,196,222,1,193,222,5,10,196,0,194,12,193,255
Notice the un-encoded data is 24 bytes in length, and the encoded data is 20 bytes in
length. The more identical values that you get in series, the better compression you get.

NOTE: If you have a series of identical values that is a length of 64 or more, you must
make a count-value entry for each 64 length series. i.e.; You can only have the lo 6 bits
(bits 0-5) of the count value for the amount to count. Bits 6 and 7 are marked as a count valued value.

For example: If you have a series of 0's (zero's) valued pixels with a length of 275, you must
encode them like so: 255,0,255,0,255,0,255,0,215,0
Notice that it still cut the length of the data from 275 bytes long to 10 bytes in length.
A compression percentage of 97%.

Something to think about: Some RLE Encoding routines use only bit 7 as the count ID bit.
This way you can have a count of 127 rather than only 63 as shown. You would think that
this is more efficient. It is not. When you use both the two hi most bits, you can have a
single display value of up to 191 with out having to have a count-value pair which is two bytes.

Standard PCX files use both the 6th and 7th bits. If you make your own RLE compressor for your
own format, then you can pick between the two ways of denoting a count byte (either 1 or 2 bits).
Each have their advantages. The single bit denote code allows a lot of identical bytes that are
in a series to be compressed using little space, but uses more space to display non-identical bytes codes
(no count codes). The 2 bit denote code allows a lot of non-identical bytes to be stored on
little space, but takes up more space to display a series of identical bytes.

If you have any other questions or see a mistake that I made, please e-mail me and I will
do my best to help out.

Two simple demo programs written in Basic and C to display a 16 color PCX file is included in
this ZIP file. (5.8k)