home *** CD-ROM | disk | FTP | other *** search
- /* pcxlib.c : A .PCX file decoder */
- #define PCX_LIB
- #include <stdio.h>
- #include <io.h>
- #include <conio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <alloc.h>
- #include <mem.h>
- #include <dos.h>
- #include <errno.h>
-
- #include "pcxlib.h"
-
- char PCX16defpalette[16][3] = { { 0, 0, 0 },
- { 0, 0, 0x80 }, { 0, 0x80, 0 }, { 0, 0x80, 0x80 },
- { 0x80, 0, 0 }, { 0x80, 0, 0x80 }, { 0x80, 0x80, 0 },
- { 0x80, 0x80, 0x80 }, { 0xc0, 0xc0, 0xc0 }, { 0, 0, 0xff },
- { 0, 0xff, 0 }, { 0, 0xff, 0xff }, { 0xff, 0, 0 },
- { 0xff, 0, 0xff }, { 0xff, 0xff, 0 }, { 0xff, 0xff, 0xff } };
-
-
- /****************************************************************************
- // (PCXF *)fp=fopenPCXr("example.pcx");
- //
- // returns NULL on error
- // reads the header and palette into fp->h and fp->palette
- // sets first mark [0] to the start of scan lines
- // leaves ftell at the first scan line (line 0)
- //
- ****************************************************************************/
-
- PCXF * fopenPCXr (char *pathname)
- {
- PCXF *pcxfile;
- int i;
-
- if (pcxdebug) {
- fprintf(pcxdebug,"fopenPCXr(%s)\n", pathname);
- }
-
- /* malloc memory for the PCXF, PCXH, and palette structures all at
- once. */
- if ( !(pcxfile=(PCXF *)
- malloc( sizeof(PCXF) + sizeof(PCXH) + 768) ) ) {
- PCXerror=ENOMEM; return(NULL);
- }
- pcxfile->h=NULL;
- if ((pcxfile->fp=fopen(pathname, "rb")) == NULL) {
- PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
- }
- pcxfile->read_or_write=0; /* readonly */
- pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
- pcxfile->name=pathname;
- /* read header from file */
- if (fread(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
- PCXerror=errno; fclosePCX(pcxfile); return (NULL);
- }
- if(pcxfile->h->MagicId != 0x0a) {
- fclosePCX(pcxfile); PCXerror=EINVFMT; return (NULL);
- }
- pcxfile->w = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
- pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
- pcxfile->type=-1;
-
- /* set up marks : mark 0 is scan 16 */
- pcxfile->num_marks=pcxfile->l/16;
- pcxfile->marks=(long *)malloc( sizeof(long)*pcxfile->num_marks);
- for (i=0; i<pcxfile->num_marks; i++) {
- *(pcxfile->marks + i)=0L;
- }
-
- /* Determine PCX file type */
-
- /* 256-color file */
- if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
- pcxfile->type=PCX256colors;
- pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
- pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
- pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
- _read_palette(pcxfile);
- } else
- /* 16-color file */
- if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
- pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
- pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
- pcxfile->type= PCX16colors;
- } else
- /* monochrome file */
- if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
- pcxfile->type=PCXMONO;
- pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
- pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
- } else {
- if (pcxdebug) fprintf(pcxdebug,"invfmt: unknown type.\n");
- PCXerror=EINVFMT;
- }
- if ( (pcxfile->buffer=(unsigned char *)
- malloc( pcxfile->h->bytesline * 16 ) ) == NULL){
- PCXerror=ENOMEM; return(NULL);
- }
- pcxfile->next_scan=pcxfile->buffer_scan=-1;
-
- fseekPCX(pcxfile,0);
- if (pcxdebug) {
- fprintf(pcxdebug,
- "p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
- pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
- fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
- pcxfile, pcxfile->h, pcxfile->palette);
- }
- return ((!PCXerror) ? pcxfile : NULL);
- }
-
- /*///////////////////////////////////////////////////////////////////////////
- // (PCXF *)fp=fopenPCXw("example.pcx", (PCXH *)h, (char *)palette);
- //
- // returns NULL on error
- // opens the file in mode "wb" and writes the header,
- // leaving ftell at the first scan line (end-of-file).
- // _write_pcx_line() should be used sequentially to write the
- // data into the file, followed by _write_pcx_palette(), then
- // fclosePCX().
- ///////////////////////////////////////////////////////////////////////////*/
- PCXF * fopenPCXw(char *name, PCXH *h, char *palette)
- {
- PCXF *pcxfile;
-
- if (pcxdebug) {
- fprintf(pcxdebug,"fopenPCXw(%s,%Fp,%Fp)\n", name,h,palette);
- }
-
- /* malloc memory for the PCXF, PCXH, and palette structures all at
- once. */
- if ( !(pcxfile=(PCXF *)
- malloc( sizeof(PCXF) + sizeof(PCXH) + 768 + h->bytesline) ) ) {
- PCXerror=ENOMEM; return(NULL);
- }
- pcxfile->marks=NULL; pcxfile->num_marks=0; /* writing doesn't use marks */
- pcxfile->palette=NULL;
- if ((pcxfile->fp=fopen(name, "wb")) == NULL) {
- PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
- }
- pcxfile->read_or_write=1; /* write only */
- pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
- memcpy(pcxfile->h,h,sizeof(PCXH)); /* copy prepared header */
- pcxfile->name=name;
- /* write header to file */
- if (fwrite(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
- PCXerror=errno; fclosePCX(pcxfile); return (NULL);
- }
- pcxfile->w = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
- pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
- pcxfile->type=-1;
-
- /* Determine PCX file type */
-
- /* 256-color file */
- if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
- pcxfile->type=PCX256colors;
- pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
- pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
- pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
- memcpy(pcxfile->palette,palette,768);
- /* copy prepared palette */
- if (pcxdebug) {
- fprintf(pcxdebug,"copied palette=%Fp to ->palette=%Fp.\n",
- palette, pcxfile->palette);
- if ( memcmp(pcxfile->palette,palette,768) != 0)
- fprintf(pcxdebug,"palette comparison failed.\n");
- }
- } else
- /* 16-color file */
- if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
- pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
- pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
- pcxfile->type= PCX16colors;
- } else
- /* monochrome file */
- if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
- pcxfile->type=PCXMONO;
- pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
- pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
- } else
- PCXerror=EINVFMT;
- pcxfile->buffer=NULL; pcxfile->next_scan=pcxfile->buffer_scan=-1;
-
- fseekPCX(pcxfile,0);
- if (pcxdebug) {
- fprintf(pcxdebug,
- "p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
- pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
- fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
- pcxfile, pcxfile->h, pcxfile->palette);
- }
- return ((!PCXerror) ? pcxfile : NULL);
- }
-
- /*///////////////////////////////////////////////////////////////////////////
- // _read_pcx_line
- // returns number of characters written to linebuffer
- ///////////////////////////////////////////////////////////////////////////*/
- unsigned _read_pcx_line(PCXF *p, char * linebuffer,
- unsigned x0, unsigned x1)
- {
- unsigned int n, w;
- unsigned short run_len;
- int Data;
- /* n= file ptr, w=image ptr */
- for (w=0,n=0; n < p->h->bytesline ; ) {
- if ((Data=fgetc(p->fp)) == EOF) {
- p->next_scan=-1;
- return(n);
- }
- /* If the two high bits are set... */
- if ((unsigned char)Data >= 0xc0) {
- /* Get duplication count from lower bits */
- run_len = (char)Data & 0x3f;
- /* Set run_len bytes */
- if ((Data=fgetc(p->fp)) == EOF) {
- p->next_scan=-1;
- return(w);
- }
- while(run_len--) {
- if ( ((n >= x0) && (n <= x1)) )
- linebuffer[w++]=(char)Data;
- n++;
- }
- } else {
- if ( ((n >= x0) && (n <= x1)) )
- linebuffer[w++]=(char)Data;
- n++;
- }
- }
- p->next_scan++;
- return (w);
- }
-
- /*///////////////////////////////////////////////////////////////////////////
- // _write_pcx_line
- // returns number of characters written to linebuffer
- ///////////////////////////////////////////////////////////////////////////*/
- unsigned _write_pcx_line(PCXF *p, char * linebuffer,
- unsigned x0, unsigned x1, unsigned char fill)
- {
- unsigned int n=0, w=0;
- unsigned char run_len, last, data;
- /* n= linebuffer, w=image offsets */
-
- while (w < x0 ) {
- if ( (x0 - w) > 63 )
- run_len=63;
- else
- run_len=(x0-w);
- if ( (run_len != 1) || (fill > 191) ) {
- fputc( ( run_len | 0xc0 ),p->fp);
- }
- fputc(fill,p->fp);
- w+=run_len;
- }
- run_len=1;
- last=*(linebuffer+n); /* assign the first character */
- w++;
- for (n=1; (w < p->h->bytesline)&&(w <= x1); n++,w++) {
- if ( (data=*(linebuffer+n)) == last) {
- run_len++;
- if ( run_len < 63 )
- continue;
- }
- while (run_len) {
- if ( (run_len != 1) || (last > 0xbf) ) {
- fputc( (run_len | 0xc0),p->fp);
- }
- fputc(last,p->fp);
- run_len=0;
- }
- last=data;
- run_len=1;
- }
- /* left-overs */
- while (run_len) {
- if ( (run_len != 1) || (last > 0xbf) ) {
- fputc( (run_len | 0xc0),p->fp);
- }
- fputc(last,p->fp);
- run_len=0;
- }
-
- while ( w < p->h->bytesline ) {
- if ( (p->h->bytesline -1 -w) < 63)
- run_len= (p->h->bytesline -1 -w);
- else
- run_len=63;
- if ( (run_len != 1) || (fill > 191) )
- fputc( (run_len | 0xc0),p->fp);
- fputc(fill,p->fp);
- w+=run_len;
- }
- p->next_scan++;
- return (w);
- }
-
- /*/////////////////////////////////////////////////////////////////////////
- // int =fseekPCX(PCXF *pcxfile, unsigned y)
- // -1 on error
- ///////////////////////////////////////////////////////////////////////////*/
- int fseekPCX(PCXF *pcxfile, unsigned y)
- {
- int i=0;
- long lastm=128L;
-
- if (pcxdebug) {
- fprintf(pcxdebug,"fseekPCX(%Fp, %u).\n", pcxfile, y);
- }
- if (y == pcxfile->next_scan) {
- return(y);
- }
- if (y < 16) { /* home */
- if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0) {
- pcxfile->next_scan=-1;
- return(-1);
- }
- pcxfile->next_scan=0;
- if (y==0)
- return(0);
- }
- if ( y>15) {
- if (pcxfile->num_marks > 0) {
- while ( (i<y) && (*(pcxfile->marks + (i/16-1)) != 0L) ) {
- lastm=*(pcxfile->marks + (i/16-1));
- i+=16;
- }
- if (i>15) i-=16;
- if (fseek(pcxfile->fp, lastm, SEEK_SET) != 0) {
- i=0;
- if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0)
- return(-1);
- }
- pcxfile->next_scan=i;
- }
- }
-
- for (; i<y; i++) {
- if ( ((i%16) == 0) && (i > 15)) {
- *(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
- }
- _read_pcx_line(pcxfile, NULL, 1, 0);
- }
- if ( ((i%16) == 0) && (i > 15))
- *(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
- return(y);
- }
-
- /****************************************************************************
- // fclosePCX
- ****************************************************************************/
- int fclosePCX(PCXF *pcx)
- {
- if (pcx->marks) free(pcx->marks);
- if (pcx->buffer) free(pcx->buffer);
- if (pcx->fp) fclose(pcx->fp);
- if (pcx) free(pcx);
- return(0);
- }
-
- /*
- ///////////////////////////////////////////////////////////////////////////
- // Palette entries have values from 0 to ff. Unfortunately, the VGA
- // BIOS only uses the least significant 6 bits (i.e. values 0 - 3f).
- // To adjust, right shift every entry by 2 bits ( divide by 4).
- ///////////////////////////////////////////////////////////////////////////
- */
- void _read_palette(PCXF *p)
- {
- int i;
- char Id256Pal;
- char *pal;
-
- /* Look for the palette at the end of the file */
- if (fseek(p->fp, -769, SEEK_END) == -1) {
- PCXerror=errno; return;
- }
- else {
- /* It should start with a 0Ch byte */
- if (!((fread(&Id256Pal,1,1,p->fp) == 1) && (Id256Pal == '\x0c'))) {
- if (pcxdebug) fprintf(pcxdebug,"palette doesn't start with 0ch.\n");
- PCXerror=EINVFMT; return;
- }
- else
- if (fread(p->palette, 768, 1, p->fp) != 1) {
- PCXerror=errno; return;
- }
- else {
- pal=(char *)p->palette;
- for (i=0; i<256; i++) {
- *(pal+i*3) /=4; *(pal+i*3+1) /=4; *(pal+i*3+2) /=4;
- }
- }
- }
- return;
- }
-
- void _write_pcx_palette(PCXF *p)
- {
- char I256Pal=0x0c;
- unsigned char *tp,*pp;
- int i;
-
- if (fwrite(&I256Pal, 1, 1, p->fp) != 1)
- PCXerror=errno;
- else {
- if ( (tp=(unsigned char *)malloc(768)) == NULL) {
- PCXerror=ENOMEM;
- return;
- }
- pp=p->palette;
- for (i=0; i<256; i++) {
- *(tp+i*3) = *(pp+i*3) * 4;
- *(tp+i*3+1) = *(pp+i*3+1) *4;
- *(tp+i*3+2) = *(pp+i*3+2) *4;
- }
- if (fwrite(tp, 768, 1, p->fp) != 1)
- PCXerror=errno;
- }
- return;
- }
-
- void Start_pcxdebug(char *path)
- {
- if (debugtimeson)
- pcxdebug=fopen(path,"a");
- else
- pcxdebug=fopen(path,"w");
- debugtimeson++;
- }
-
- void Close_pcxdebug(void)
- {
- fclose(pcxdebug);
- }
-
- int Puts_pcxdebug(char *string)
- {
- return(fputs(string,pcxdebug));
- }
-