[comp.sys.apollo] Apollo Gif Viewer

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