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. |