/* ViewPC - IFF File Viewer - (c) 1988 Dallas John Hodgson This program must be compiled under memory model "compact" or larger in order to fetch the correct allocation libraries. This is to avoid problems when loading in pictures of 64K in size. View requires the library "EGAVGA.obj" to be linked in at compile time. Compiled under Turbo C 1.5 SHAREWARE IS FOR THE PUBLIC GOOD. SUPPORT IT! */ #include #include #include #include #include "view.h" #define SafeRead(file,buf,len) if (!fread(buf,len,1,file)) { puts("disk error!"); fclose(file); return(NULL); } /* The following routines are required because Intel machines are little-endian; i.e., constants are stored in reverse order. Since the IFF spec was originally designed for Motorola CPU's, ANY time we read a numerical value larger than a char we had better reverse the result! */ #define REVERSE(a) Reverse_Constant(&a,sizeof(a)) struct Screen screen; char planes[MAXPLANES][LINELEN]; int ega_remap[256], debug, scaling=1, /* scaling ON by default */ remap=1, /* remapping ON by default */ pal=1; /* palette zapping allowed by default */ struct palettetype palette; /* used to hold our default palette */ /* RGB 2-bit analog to EGA palette remap tables */ static char r_map[4] = { 0,32,4,36 }, g_map[4] = { 0,16,2,18 }, b_map[4] = { 0,8,1,9 }; /************************************************************************ * * * Routine name(s) : ReadILBM() * * Author : D. John Hodgson * * Environment : Turbo "C" 1.5, small model * * * * ReadILBM attempts to read an IFF ILBM file into memory. Returns * * a screen pointer if successful, otherwise NULL. * * * * LIMITATIONS : no CATS/LISTS/PROPS. CAMG chunks,masking supported. * ************************************************************************/ struct Screen *ReadILBM(fspec) char *fspec; /* MS-DOS filename */ { FILE *fp; BitMapHeader bmhd; Chunk header; long id; int i; if (!(fp=fopen(fspec,"rb"))) { puts("Error opening file."); return(NULL); } SafeRead(fp,&header,sizeof(header)); if (header.ckID!=ID_FORM) { fclose(fp); return(NULL); } SafeRead(fp,&id,sizeof(id)); if (id!=ID_ILBM) { fclose(fp); return(NULL); } for (;;) { SafeRead(fp,&header,sizeof(header)); REVERSE(header.ckSize); if (header.ckID==ID_BODY) break; switch(header.ckID) { case ID_BMHD: SafeRead(fp,&bmhd,sizeof(bmhd)); REVERSE(bmhd.w); REVERSE(bmhd.h); REVERSE(bmhd.x); REVERSE(bmhd.y); break; case ID_CMAP: SafeRead(fp,&screen.colormap[0][0],header.ckSize); screen.colors=header.ckSize/3; break; case ID_CAMG: SafeRead(fp,&screen.ViewModes,header.ckSize); REVERSE(screen.ViewModes); break; /* skip unknown ID's */ default: fseek(fp,ROUNDODDUP(header.ckSize),SEEK_CUR); } } /* ID_BODY reached : read planes into RAM for ease of decompression */ if (!(screen.buffer=farmalloc(header.ckSize))) { puts("Insufficient memory for picture allocation."); fclose(fp); return(NULL); } /* this special is necesary to overcome fread()'s 64K size limitation. */ BigRead(fp,screen.buffer,header.ckSize); fclose(fp); /* reduce 8-bit color register values to most significant 4 bits */ for (i=0;i>=4 SHOULD WORK! */ screen.colormap[i][RGB_GREEN]/=16; screen.colormap[i][RGB_BLUE]/=16; } screen.width=bmhd.w; screen.height=bmhd.h; screen.compression=bmhd.compression; screen.mask=bmhd.masking; /* add the masked plane to the interleaved plane cnt, if present */ screen.planes=bmhd.nPlanes+(screen.mask==mskHasMask); return(&screen); } /* this buffer is TOO BIG to be declared locally! */ #define BUFSIZE 40000 char buf[BUFSIZE]; BigRead(FILE *file,unsigned char huge *buffer,unsigned long len) { /* Use this routine to perform fast reads into a HUGE buffer */ unsigned int size; char *ptr; while (len) { if (len>=BUFSIZE) { /* 64K max buffer for fread() */ size=BUFSIZE; SafeRead(file,buf,size); } else { size=len; SafeRead(file,buf,size); } len-=size; ptr=buf; while (size--) *buffer++=*ptr++; /* local to HUGE buffer copy */ } } Reverse_Constant(value,size) char value[]; int size; { int i; char buf[sizeof(long)]; /* big enough to hold a char, short, or long */ movmem(value,&buf,size); /* Copy the Motorola value to our buffer */ size--; /* size must be from [0..n-1] for array processing */ for (i=0;i<=size;i++) value[i]=buf[size-i]; /* & copy it back, Intel-style */ } Expand() /* pixel line decompress/deinterleave */ { short plane,linelen,rowbytes,i,width=screen.width; char n,*destbuf,huge *sourcebuf=screen.buffer; /* roundup width to a multiple of 16 pixels, if necessary; important for deinterleaving brushes correctly! */ if (width%16) width=(((width/16)+1)*16); linelen=width/8; for (i=0;i=0) { movmem(sourcebuf,destbuf,(unsigned int)++n); rowbytes-=n; destbuf+=n; sourcebuf+=n; } else { /* compressed block? expand n duplicate bytes */ n=-n+1; rowbytes-=n; setmem(destbuf,n,(unsigned int)*sourcebuf++); destbuf+=n; } } /* finish unpacking line */ } else { /* uncompressed? just copy */ movmem(sourcebuf,destbuf,(unsigned int)linelen); sourcebuf+=linelen; destbuf+=linelen; } } /* finish interleaved planes */ /* line assembled, so flush pixels out */ flush_pixels(i,linelen); } /* finish lines */ } flush_pixels(line,bytelen) int line,bytelen; { int index,bit,p,color,px; for (index=0;indexLOWIDTH) putpixel(px,line,color); else { /* stretch 320-wide pics to meet 640 resolution */ px<<=1; putpixel(px,line,color); putpixel(px+1,line,color); } } } /* bit loop */ } /* byte loop */ } remap_colors() { int color,i,delta,bestpick,bestdelta; char sr,sg,sb,dr,dg,db,br,bg,bb; static char ega_colors[16][3] = { { 0,0,0 }, /* black */ { 0,0,10 }, /* blue */ { 0,10,0 }, /* green */ { 0,10,10 }, /* cyan */ { 10,0,0 }, /* red */ { 10,0,10 }, /* magenta */ { 10,5,0 }, /* brown */ { 10,10,10 }, /* lt. grey */ { 5,5,5 }, /* dk. grey */ { 5,5,15 }, /* lt. blue */ { 5,15,5 }, /* lt. green */ { 5,15,15 }, /* lt. cyan */ { 15,5,5 }, /* lt. red */ { 15,5,15 }, /* lt. magenta */ { 15,15,5 }, /* yellow */ { 15,15,15 } /* white */ }; /* step through the colors in our picture, remapping to the closest possible equivalent in the EGA color scheme. This will also perform color reduction if the picture has more bitplanes (colors) than EGA will allow! */ for (color=0;colorLOHEIGHT) mode=EGAHI; /* acknowledge the existence of our pre-linked EGA driver */ if (registerbgidriver(EGAVGA_driver) < 0) return(NULL); initgraph(&driver,&mode,""); result=graphresult(); if (result!=grOk) { printf("Error : %s\n",grapherrormsg(result)); return(NULL); } /* save the TurboC default palette so we can restore it later */ getpalette(&palette); /* We have one chance to display a picture in EGA mode without remapping. Pictures in EGAHI with 16 colors or less can be displayed simply by zapping the palette, which supports a whopping 6 bits per color register. No need to do this for EGALO, which only supports a 16-color palette to begin with. NOTE #1 : We could display EGALO pictures in EGAHI resolution, except that we would lose 50 lines of image expanding a 200-line picture to 400 lines. Drawing would be twice as slow, and screen captures would be twice the size. NOTE #2 : Zapping color registers only preserves the most significant two bits of RGB color present in the source image. This is fine for IBM pics, but colors may be less pleasant than the AI remapping scheme used when other pictures are displayed. Then again, they may be better. */ if (screen.planes <= 4 && mode==EGAHI && pal) { for (i=0;i [-s] [-p] [-d]\n\n" "Options : -s disables auto horizontal scaling\n" " -p disables auto direct palette mapping\n" " -d displays information about your IFF picture\n\n" "PC-View : Dallas Hodgson\n" " 351 Kiely Bl, #B304\n" " San Jose, Ca. 95129\n\n" " Comments & Contributions gladly accepted.\n"); exit(100); } main(argc,argv) int argc; char *argv[]; { char *fspec=0; /* parse up command line */ while (--argc) { ++argv; if (argv[0][0]=='-') switch(toupper(argv[0][1])) { case 'S': scaling=0; break; case 'P': pal=0; break; case 'D': debug=1; break; default : welcome(); /* unrecognized switch */ } else fspec=argv[0]; } if (!fspec) welcome(); /* no filename specified */ puts(TITLE); if (!ReadILBM(fspec)) exit(100); if (debug) { printf("Width=%d, Height=%d, Planes=%d, Colors=%d\n", screen.width,screen.height,screen.planes,screen.colors); printf("Compression=0x%x, Masking=0x%x, ViewModes=0x%lx\n", screen.compression,screen.mask,screen.ViewModes); putchar('\n'); } if (OpenScreen()) { Expand(); getchar(); setallpalette(&palette); closegraph(); } }