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 */