samit@demon.siemens.com (Ben Samit) (03/18/89)
Here is an apollo GIF (compuserve's graphics file format) viewer. It is not very elegant, having no capabilities to resize images and does not deal with local colormaps (which I have never seen used). I may add these features later (time permitting) or you may add them yourself. The program also does not do any color interpretation, so if you have an 8 bit picture and try to display it on a 4 bit system it won't look good (at all). If you make any major enhancements to this program, I would appreciate a copy of the new code. Comments on programming style are always welcome (hell, I'm an engineer, what do I know about programming) but please make your suggestions via email (no point in being publicly humiliated if I can avoid it). And, lastly, I should give my thanks to Scott Hemphill for his gif to postscript converter from which I shamelessly pilfered the majority of this program. --CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT-- /* viewgif.c * * The majority of this code was lifted right out * of Scott Hemphill's gif to postscript converter. * The display portion of the code was written by * myself and Ken Hampel. Since Scott Hemphill was * kind enough to put his code in the public domain, * I feel obliged to do the same. * * This program is hereby placed in the public domain. * There are no restrictions on the use of all or any * part of this program. * * Ben Samit March 1989 * samit@demon.siemens.com */ #include <stdio.h> #include "/sys/ins/base.ins.c" #include "/sys/ins/gpr.ins.c" char *malloc(); int strncmp(); #define min(x,y) ((x) < (y) ? (x) : (y)) #define max(x,y) ((x) > (y) ? (x) : (y)) #define FALSE 0 #define TRUE 1 status_$t status; gpr_$color_vector_t color_map; typedef int bool; typedef struct codestruct { struct codestruct *prefix; unsigned char first,suffix; } codetype; FILE *infile; unsigned int screenwidth; /* The dimensions of the screen */ unsigned int screenheight; /* (not those of the image) */ bool global; /* Is there a global color map? */ int globalbits; /* Number of bits of global colors */ unsigned char globalmap[256][3]; /* RGB values for global color map */ unsigned char *raster; /* Decoded image data */ codetype *codetable; /* LZW compression code data */ int datasize,codesize,codemask; /* Decoder working variables */ int clear,eoi; /* Special code values */ unsigned WIDTH,HEIGHT; void usage() { fprintf(stderr,"usage: viewgif gif-file\n"); exit(-1); } void fatal(s) char *s; { fprintf(stderr,"viewgif: %s\n",s); exit(-1); } void checksignature() { char buf[6]; fread(buf,1,6,infile); if (strncmp(buf,"GIF",3)) fatal("file is not a GIF file"); if (strncmp(&buf[3],"87a",3)) fatal("unknown GIF version number"); } /* Get information which is global to all the images stored in the file */ void readscreen() { unsigned char buf[7]; fread(buf,1,7,infile); screenwidth = buf[0] + (buf[1] << 8); screenheight = buf[2] + (buf[3] << 8); global = buf[4] & 0x80; if (global) { globalbits = (buf[4] & 0x07) + 1; printf("global bitmap : %d colors\n",(1<<globalbits)); fread(globalmap,3,1<<globalbits,infile); } } /* Output the bytes associated with a code to the raster array */ void outcode(p,fill) register codetype *p; register unsigned char **fill; { if (p->prefix) outcode(p->prefix,fill); *(*fill)++ = p->suffix; } /* Process a compression code. "clear" resets the code table. Otherwise make a new code table entry, and output the bytes associated with the code. */ void process(code,fill) register code; unsigned char **fill; { static avail,oldcode; register codetype *p; if (code == clear) { codesize = datasize + 1; codemask = (1 << codesize) - 1; avail = clear + 2; oldcode = -1; } else if (code < avail) { outcode(&codetable[code],fill); if (oldcode != -1) { p = &codetable[avail++]; p->prefix = &codetable[oldcode]; p->first = p->prefix->first; p->suffix = codetable[code].first; if ((avail & codemask) == 0 && avail < 4096) { codesize++; codemask += avail; } } oldcode = code; } else if (code == avail && oldcode != -1) { p = &codetable[avail++]; p->prefix = &codetable[oldcode]; p->first = p->prefix->first; p->suffix = p->first; outcode(p,fill); if ((avail & codemask) == 0 && avail < 4096) { codesize++; codemask += avail; } oldcode = code; } else { fatal("illegal code in raster data"); } } /* Decode a raster image */ void readraster(width,height) unsigned width,height; { unsigned char *fill = raster; unsigned char buf[255]; register bits=0; register unsigned count,datum=0; register unsigned char *ch; register int code; datasize = getc(infile); clear = 1 << datasize; eoi = clear+1; codesize = datasize + 1; codemask = (1 << codesize) - 1; codetable = (codetype*)malloc(4096*sizeof(codetype)); if (!codetable) fatal("not enough memory for code table"); for (code = 0; code < clear; code++) { codetable[code].prefix = (codetype*)0; codetable[code].first = code; codetable[code].suffix = code; } for (count = getc(infile); count > 0; count = getc(infile)) { fread(buf,1,count,infile); for (ch=buf; count-- > 0; ch++) { datum += *ch << bits; bits += 8; while (bits >= codesize) { code = datum & codemask; datum >>= codesize; bits -= codesize; if (code == eoi) goto exitloop; /* This kludge put in because some GIF files aren't standard */ process(code,&fill); } } } exitloop: if (fill != raster + width*height) fatal("raster has the wrong size"); free(codetable); } void readimage() { unsigned char buf[9]; unsigned left,top,width,height; bool local,interleaved; char localmap[256][3]; int localbits; int *interleavetable; register row; register i; unsigned char *newraster; fread(buf,1,9,infile); left = buf[0] + (buf[1] << 8); top = buf[2] + (buf[3] << 8); width = buf[4] + (buf[5] << 8); height = buf[6] + (buf[7] << 8); WIDTH= width; HEIGHT=height; printf("gif dimensions : %d x %d pixels\n",WIDTH,HEIGHT); local = buf[8] & 0x80; interleaved = buf[8] & 0x40; if (local) { localbits = (buf[8] & 0x7) + 1; fread(localmap,3,1<<localbits,infile); } else if (!global) { fatal("no colormap present for image"); } raster = (unsigned char*)malloc(width*height); if (!raster) fatal("not enough memory for image"); readraster(width,height); if (interleaved) { newraster = (unsigned char*)malloc(width*height); if (!newraster) fatal("not enough memory for newimage"); interleavetable = (int*)malloc(height*sizeof(int)); if (!interleavetable) fatal("not enough memory for interleave table"); row = 0; for (i = top; i < top+height; i += 8) interleavetable[i] = row++; for (i = top+4; i < top+height; i += 8) interleavetable[i] = row++; for (i = top+2; i < top+height; i += 4) interleavetable[i] = row++; for (i = top+1; i < top+height; i += 2) interleavetable[i] = row++; for (row = top; row < top+height; row++) { for(i=left;i<left+WIDTH;i++) { newraster[(row-top)*WIDTH+i-left]= raster[interleavetable[row-top]*WIDTH+i-left]; } } free(raster); free(interleavetable); raster=newraster; } } /* Read a GIF extension block (and do nothing with it). */ void readextension() { unsigned char code,count; char buf[255]; code = getc(infile); while (count = getc(infile)) fread(buf,1,count,infile); } main(argc,argv) int argc; char *argv[]; { int quit = FALSE; char ch; if (argc != 2) usage(); infile = fopen(argv[1],"r"); if (!infile) { perror("viewgif"); exit(-1); } checksignature(); readscreen(); do { ch = getc(infile); switch (ch) { case '\0': break; case ',': readimage(); break; case ';': quit = TRUE; break; case '!': readextension(); break; default: fatal("illegal GIF block type"); break; } } while (!quit); putimage(); } putimage() { long int x,y; long *foo; gpr_$window_t destination_window; foo = (long *) malloc(WIDTH*sizeof(long)); if (!foo) { printf("not enough memory for long image\n"); exit(0); } destination_window.window_base.x_coord = 0; destination_window.window_size.x_size = WIDTH; destination_window.window_size.y_size = 1; Initialize(); save_color_map(); set_color_map(); gpr_$acquire_display(status); for(y=0;y<HEIGHT; y++) { for(x=0;x<WIDTH; x++) { foo[x]= (long) raster[(x+y*WIDTH)]; } destination_window.window_base.y_coord = y; gpr_$write_pixels(*foo, destination_window, status); /* *foo looks wrong, but the interface between c and pascal is brain damaged */ } gpr_$release_display(status); KbEnable(); reset_color_map(); Close(); } Initialize() { gpr_$offset_t init_size; gpr_$bitmap_desc_t init_bitmap; gpr_$display_mode_t mode=gpr_$direct; gpr_$plane_t hi_plane_id = 7; init_size.x_size = WIDTH; init_size.y_size = HEIGHT; gpr_$init(mode, (short)1, init_size, hi_plane_id, init_bitmap, status); } Close() { int i=0; gpr_$terminate (false, status); while(status.fail && i<10) { i++; gpr_$terminate (false, status); printf("i= %d\n",i); } } set_color_map() { int i; gpr_$color_vector_t color; gpr_$acquire_display(status); for(i=0;i<(1<<globalbits);i++) { color[i]=(globalmap[i][0]<<16)|(globalmap[i][1]<<8)|(globalmap[i][2]); } gpr_$set_color_map(0L,(short) (1<<globalbits), color, status); gpr_$release_display(status); } save_color_map() { gpr_$acquire_display(status); gpr_$inq_color_map(0L,(short) (1<<globalbits), color_map, status); gpr_$release_display(status); } reset_color_map() { gpr_$acquire_display(status); gpr_$set_color_map(0L,(short) (1<<globalbits), color_map, status); gpr_$release_display(status); } KbEnable() { gpr_$keyset_t keys; gpr_$event_t ev_type; gpr_$position_t ev_pos; char ev_char; boolean wait; lib_$init_set(keys, (short)256); lib_$add_to_set(keys, (short)256, ' '); gpr_$enable_input (gpr_$keystroke, keys, status); wait = gpr_$event_wait (ev_type, ev_char, ev_pos, status); } plane4p() { gpr_$display_config_t config; gpr_$inq_config(config, status); return (config == gpr_$color2_1024x800x4); } --CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT--CUT-- | "It's a jelly" - Bob McKenzie | | ARPA: samit@siemens.siemens.com uucp: ..!princeton!siemens!samit | | snail: Siemens SCR 755 College Rd East Princeton, NJ 08540-6668 | | These opinions are solely mine and in no way reflect those of my employer. |