GDMonline Reading and displaying PCX files
Phil Inch, Game Developers Magazine

DOWNLOAD ... The example files mentioned in this article are contained in the file PCX-SHOW.ZIP (12,091 bytes) which can be downloaded by clicking this disk icon.


Your games probably won't be very exciting without some nice background piccies for your title screens, and perhaps for the gameplay as well.

Of all the formats available for storing pictures, the .PCX format is one of the best known and most accessible from a programmers point of view, and there are a plethora of "paint" programs with which you can create your own PCX files. There are also plenty of PCX files on bulletin boards which you can download and experiment with.

This article will show you how to load and display PCX files which are up to 320x200 in 256 colours - that is, which are designed for the same video mode (mode 13h) as the other graphics articles you've been reading in the magazine.

For simplicity we won't cover the details of PCX files constructed for other video modes - we'll return to these in later issues when we've learnt how to use other video modes.

So please note, ALL of the following text assumes that the file in question is a 256 colour VGA PCX file.

You'll also see references to using the AND function. Basically AND is used to selectively turn off certain bits within a byte, so that we can isolate certain bits we are interested in. The manual which comes with your programming language should have a more detailed description of the AND function.

In Basic and Assembler, the function is AND. In C it's the operator '&'. In Pascal, ... anyone?

The structure of a PCX file

A VGA PCX file consists of a 128-byte header, followed by compressed data which represents the pixels to be drawn, followed by the constant byte 0Ch (12 decimal), followed by the 768 bytes which compose the VGA palette.

(If you're unfamiliar with the VGA palette, please read the article on the VGA palette before proceeding).

The Header of a PCX file

The header of a PCX file is 128 bytes long and starts at the beginning of the file. The "useful" header information is in fact only 70 bytes long, and following that is 58 bytes of unused space. The header contains the following information:

    Manufacturer        1 Byte     Varies, not very useful
    Version             1 Byte     '5' for 256 colour files
    Encoding            1 Byte     Usually set to '1'
    Bits per pixel      1 Byte     '8' for 256 colour files
    XMin                2 Bytes    Top left X co-ordinate
    YMin                2 Bytes    Top left Y co-ordinate
    Width               2 Bytes    Width of image - 1
    Height              2 Bytes    Height of image - 1
    Horizontal Res      2 Bytes    Horizontal resolution
    Vertical Res        2 Bytes    Vertical resolution
    EGA Palette        48 Bytes    EGA palette values
    (not used)          1 Byte     (not currently used)
    Colour planes       1 Byte     Number of colour planes
    Bytes per line      2 Bytes    Number of bytes in 1 line
    Palette Type        2 Bytes    '2' for colour palette
    (not used)         58 Bytes    (not currently used)
As you can see, only some of the information in the header is useful. For example, the EGA palette is not used at all in a VGA image, and some of the other values are constant.

I have noted in the comments column the sorts of values we expect when we're dealing with a mode 13h (320x200) 256-colour PCX file.

You may be surprised to see that the PCX file header contains an "upper left" (x,y) co-ordinate and a width and height specifier. This allows you to display an image smaller than 320x200 and at an offset with regard to the top left hand corner of the screen (320x200). The routine we'll write will account for this.

The Compressed Bitmap

To save space, the pixels which form an image are not stored in the PCX file on a 1:1 basis, that is, one byte does not equal one pixel.

This compression is achieved by storing "runs" of pixels (repeated pixels with the same colour value) as an encoded series of bytes which represents that run.

This is done by storing two bytes. The first byte consists of two "nibbles" (a nibble is half a byte, or four bits). The "high nibble" (first four bits) contain the value 0Ch (12 decimal).

This can be tested for by ANDing the byte with the value C0h (192 decimal) and checking to see if the result is 192, or more simply by seeing if the byte is >= 192.

The "low nibble" (second 4 bits) contain the length of the run.

The following byte in the file contains the value (colour) of the pixel in the run.

You may wonder, then, how it stores a "real" colour code which is greater than 192. The answer is that it's encoded as a run of length 1. This means that colour codes >= 192 take two bytes each to store. For some files, this is wasteful, and for others, it's not.

How to display the PCX file

The steps are (assuming you're already in graphics mode):

1) Read the header. From the header, remove the information which you need, such as the top left (x,y) and the width and height. Remember that the width and height values are actually 1 less than the real width and height ... ie a full-screen image returns width and height values of 319 and 199 instead of 320 and 200.

2) Go to the end of the file, skip back 769 bytes, and check that the byte at that location is 0Ch (12 decimal). This is the double check to ensure that this is a 256-colour PCX file.

3) Read the remaining 768 bytes in the file, which are the colour values for the entire VGA palette.

4) Divide all of these bytes by 4, to bring them into the range 0 - 63. I don't know why they're not already in the range 0 - 63. (I'm sure the spec probably tells you but I haven't looked that deeply into it.)

5) Use these values to reprogram the VGA palette.

6) Skip back to the 129th byte in the file (ie: the byte immediately following the header).

7) Set up a couple of temporary variables to hold the "current" x and y positions. Their initial values should be the "top left" x and y values specified in the header.

8) Read a byte. Check if the two high bits are set, either by ANDing the byte with C0h (192 dec) and seeing if the result is C0h (192 dec), or by checking if the byte is >= 192. If this is NOT the case, go to step 11.

9) You have detected a run. Get the value in the low nibble of the byte by ANDing the byte with 3Fh (63 dec). The resulting value is the run length.

10) Read another byte from the file. This is the colour value of all of the pixels in the run. Note that as we're already in a run this byte will be a "real" colour number.

11) Set the current pixel position, as defined by your working variables, to the specified colour.

12) Increment the temporary position variables according to the width and height specified in the header. If you've exceeded the maximum height, the image is finished so skip to step 14.

13) If you're plotting a run, take one from the run length and return to step 11 until the run length reaches zero. If not, or if the run length has reached zero, go to step 8.

14) The picture is now displayed! Remember to close the PCX file!

A 'C' Implementation of a PCX viewer

As always, a program comes with the article and for this article it's PCX-SHOW.EXE, and it and the source are in the PCX-SHOW zip file. The program contains some basic comments and references to the steps shown above.

It does do some checking to make sure that the file can be correctly displayed in mode 13h, and it detects this by looking at the "Version" byte to check for a 256 colour file, and by looking at the top left (x,y) and width and height values to ensure the image will fit on the screen.

The program will not attempt to display an image which will not display correctly in mode 13h, but instead aborts with an error.

Where to from here?

As I said earlier, adventurous readers may like to read the "complete" PCX specification and modify or re-write the PCX viewer to be able to display other types of files, such as 16-colour files and files for other video modes.

You can also use VGA palette programming examples in the VGA palette programming article to create effects such as "fading in" and "fading out" a PCX image, which is a great looking effect for title screens.

And, if you're really feeling like a challenge, why don't you try to write a routine which takes an existing image on the screen and writes it out as a PCX file? Remember, you'll have to write the header correctly, do the encoding correctly, and get the palette values too!

Next issue, we'll use our PCX file knowledge to learn how to move sprites across a background image without destroying that image!