The PCX format is a relatively simple format that provides a minimum of compression using Run Length Encoding (RLE). RLE means that the file can be read from start to finish in one pass and encoded or decoded without any holistic information (i.e., in order to figure out what the next encoded byte is, you only have to know what preceded it, not anything after it.) The PCX format is especially useful for 320x200x256 VGA mode 13h (where each pixel is stored as a byte). The PCX format was originally used by PC Paintbrush.
The following discussion assumes 320x200x256 VGA mode 13h, as described in Section 11.2
Two types of bytes are stored in the data image portion of a PCX file. One type is a length, and the other is color. A length byte is specified by the two upper bits being set. This limits the length specified by a length byte to 64. The other type is a color byte, and specifies a value for the byte from the palette table (the palette holds the actual RGB values of the color, and the color byte is an index into this table). This is the same method used in mode 13h. The first byte from the data is read. If the two upper bits are set, then it is a length byte, and the next byte is the color which will be replicated as many times as stated by the length byte, from left to right on the screen, ending at the end of a line (see BYTES_PER_LINE below). If the two bits are not set, then it is a color byte, and it goes onto the screen in the next location (left to right) as is.
Note: Any color greater than or equal to 192 cannot be stored as a single color byte, and must be a given a length first. For instance, if you have a single byte of color 192, then it must be represented by two bytes of 193 (length byte of 1) and 192 (color byte 192).
The PCX file itself contains two parts--the first part is called the header, which contains information about the image; the second part is the image data, which contains actual image data and color information. Rather than explain each field of the header in detail, a structure is shown below which gives a brief glance at the purpose of each field.
STRUC PCX_Header .Manufacturer resb 1 ; should always be 0Ah .Version resb 1 ;.Encoding resb 1 ; should always be 01h .BitsPerPixel resb 1 ;
.XMin resw 1 ; image width = XMax-XMin .YMin resw 1 ; image height = YMax-YMin .XMax resw 1 .YMax resw 1 .VertDPI resw 1 ;
.Palette resb 48 ;
.Reserved resb 1 .ColorPlanes resb 1 ;
.BytesPerLine resw 1 ;
.PaletteType resw 1 .HScrSize resw 1 ; only supported by .VScrSize resw 1 ; PC Paintbrush IV or higher .Filler resb 56 ENDSTRUC

| 0 -- Version 2.5 |
| 2 -- Version 2.8, palette included |
| 3 -- Version 2.8, use default palette |
| 5 -- Version 3.0 or better |

| 1 -- Monochrome |
| 4 -- 16 colors |
| 8 -- 256 colors |
| 24 -- 16.7 million colors |



| 4 -- 16 colors |
| 3 -- 24 bit color (16.7 million colors) |

In a PCX file containing 16 colors of less, the palette is contained in the .Palette section of the header. In a PCX file containing 256 colors, the palette is at the end of the file, and takes up the last 768 bytes (256 * 3 bytes per color RGB). If the last 768 bytes is a palette, there is a padding byte preceding it in the file (whose value is 12).
Example 11-1. Displaying a PCX File
EXTERN kbdin, dosxit ; LIB291 functions
SEGMENT ScratchSeg
ScratchPad resb 65535
SEGMENT stkseg STACK
resb 64*8
stacktop:
resb 0
SEGMENT code
PCX1 db 'my_pcx1.pcx', 0 ; Filenames
PCX2 db 'my_pcx2.pcx', 0 ; (Must end with 0 byte)
..start:
mov ax, cs ; Set up data and stack segments
mov ds, ax
mov ax, stkseg
mov ss, ax
mov sp, stacktop
MAIN:
; Sets up mode 13h and clears screen
mov ax, 0013h
int 10h
mov dx, pcx1 ; Filename to display
call ShowPCX ; Display PCX file to screen
; Wait for keypress
call kbdin
; Go back to text mode
mov ax, 0003h
int 10h
; Return to DOS
call dosxit
;-----------------------------------------------------------------------------
; ShowPCX procedure by Brandon Long,
; modified by Eric Meidel and Nathan Jachimiec,
; converted to NASM, cleaned up, and better commented by Peter Johnson
; Inputs: DX has the offset of PCX filename to show.
; Output: PCX file displayed (all registers unchanged)
; Notes: Assumes PCX file is 320x200x256.
; Uses ScratchSeg for temporary storage.
; The PCX file must be in the same directory as this executable.
;-----------------------------------------------------------------------------
ShowPCX
push ax ; Save registers
push bx
push cx
push si
push di
push es
mov ax, 3D00h
int 21h ; Open file
jc .error ; Exit if open failed
mov bx, ax ; File handle
mov cx, 65535 ; Number of bytes to read
mov ax, ScratchSeg ; DS:DX -> buffer for data
mov ds, ax
mov dx, ScratchPad
mov si, dx
mov ah, 3Fh
int 21h ; Read from file
mov ax, 0A000h ; Start writing to upper-left corner
mov es, ax ; of graphics display
xor di, di
add si, 128 ; Skip header information
xor ch, ch ; Clear high part of CX for string copies
.nextbyte:
mov cl, [si] ; Get next byte
cmp cl, 0C0h ; Is it a length byte?
jb .normal ; No, just copy it
and cl, 3Fh ; Strip upper two bits from length byte
inc si ; Advance to next byte - color byte
lodsb ; Get color byte into AL from [SI]
rep stosb ; Store to [ES:DI] and inc DI, CX times
jmp short .tst
.normal:
movsb ; Copy color value from [SI] to [ES:DI]
.tst:
cmp di, 320*200 ; End of file? (written 320x200 bytes)
jb .nextbyte
mov cl, [si]
cmp cl, 0Ch ; Palette available?
jne .close
; Set palette using port I/O
mov dx, 3C8h
mov al, 0
out dx, al
inc dx ; Port 3C9h
mov cx, 256*3 ; Copy 256 entries, 3 bytes (RGB) apiece
inc si ; Skip past padding byte
.palette:
lodsb
shr al, 1 ; PCX stores color values as 0-255
shr al, 1 ; but VGA DAC is only 0-63
out dx, al
dec cx
jnz .palette
.close:
mov ah, 3Eh
int 21h ; Close file
.error:
pop es ; Restore registers
pop di
pop si
pop cx
pop bx
pop ax
ret