Listing 3: PXC file functions


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <conio.h>
#include <dos.h>

#include "vbe.h"    /* vesa vbe interface */

/* --------------- Local Data -------------*/

/* (Abridged) header record of a PCX file */
typedef struct    
{
    char Manufacturer; /* pcx file sig: 10 */
    char Version;      /* pc paintbrsh ver */
    char Encoding;     /* 1: rle */
    char BitsPerPixel; /* color resolution */
    int  Xmin,Ymin;    /* image origin */
    int  Xmax,Ymax;    /* image extent */
    char NotUsed1[53]; /* not used by this
                          program */
    char Planes;       /* number of color
                          planes */
    int  BytesPerLine; /* (per plane) */
    char NotUsed2[58]; /* by this program */
    
} pcx_t;

/* Error codes; these also index ErrorText
   array below */
enum    
{
    PCX_OK,PCX_EOPEN,PCX_EVIDEO,
    PCX_EREAD,PCX_EFORMAT
};

static const char *ErrorText[]=
{
/* PCX_OK */     "Ok",
/* PCX_EOPEN */  "File not found",
/* PCX_EVIDEO */ "Unsupported video mode",
/* PCX_EREAD */  "File read error",
/* PCX_EFORMAT */
    "Invalid or unsupported format"
};

/* PCX image line buffer */
static char Line[640]; 
/* DAC palette data */
static char Palette256[768];
/* PCX file header record */
static pcx_t Header; 
           
/*------ local pcx file functions ---------*/

static int ReadHeader(FILE *f)

/* reads the header of the open file into the
   global Header structure; returns 0 on a
   file read error, or if the file is not a
   valid pcx file, or if the pcx file does
   not contain a 640x480x256-compatible
   image. */
{
    pcx_t *h=&Header;
    
    fread(h,sizeof(pcx_t),1,f);
    return !(ferror(f) ||   
        h->Manufacturer!=10 ||
        h->Encoding!=1 ||
        h->Planes!=1 ||
        h->BitsPerPixel!=8 ||
        h->Ymax-h->Ymin>479 ||
        h->Xmax-h->Xmin>639);
}
static int ReadPalette(FILE *f)
    
/* reads the 256-color palette of the open
   file into the global buffer Palette256,
   and converts it to 6-bit DAC palette
   register data; returns 0 on a file read
   error or an invalid palette block. */
{
    int i;
    fseek(f,-769L,SEEK_END); /* to palette */
    if(fgetc(f)!=12) /* check sig byte */
        return 0; 

    /* read the 256 triplets */

    fread(Palette256,768,1,f); 
    if(ferror(f)) return 0;
    fseek(f,128L,SEEK_SET); /* bk to image */
    for(i=0;i<768;i++)
        Palette256[i]>>=2; /* to 6-bit rgb */
    return 1;
}
static void ReadLine(FILE *f)


/* reads and decompresses the next scanline
   from the current pcx file into the global
   Line buffer. */
{
    int    c,i=0;
    
    while(i<Header.BytesPerLine)
    {
        c=fgetc(f);
        if((c&0xc0)==0xc0) /* is rle hdr */
        {
            c&=~0xc0;   /* =repeat count */
            /* copy repeated pixel data */
            memset(Line+i,fgetc(f),c);
            i+=c;
        }
        else Line[i++]=c; /* is pixel data */
    }
     return;
}

/*----------- general functions -----------*/

int PcxShowFile(const char *file)

/* reads and displays a pcx file; returns 0
   on success, PCX_ error code on failure. */
{
    int    e=PCX_OK;
    FILE *f=fopen(file,"rb");
    if(!f) e=PCX_EOPEN;
    else if(!ReadHeader(f)) e=PCX_EFORMAT;
    else if(Header.Version==5 &&
            !ReadPalette(f)) e=PCX_EFORMAT;
    else if(!VbeSetMode(0x101)) e=PCX_EVIDEO;
    else
    {
        int y,ymax=min(Header.Ymax,479);
        int    n=min(Header.Xmax,640)-
               Header.Xmin+1;
        if(Header.Version==5)
            VbeSetPalette(Palette256,0,256);
        for(y=Header.Ymin;y<ymax;y++)
        {
            ReadLine(f);
            VbeWrite(Header.Xmin,y,n,Line);
        }
    }
    if(f) fclose(f);
    return e;
} 
void PcxDeinit()

/* clears the image and resets the video to
   standard 80-column text mode */
{
    VbeSetMode(3);
}
void main(int argc,char **argv)

/* displays the pcx file specified by the
   first argument to the program
   (usage: PCX <filename>) */
{
    int e=PcxShowFile(argv[1]);
    
    if(!e)
    {
        getch();
        PcxDeinit();
    }
    else puts(ErrorText[e]);
} 
/* End of File */