8 bit gifview.c

Kevin Kuehl krk at cs.purdue.EDU
Wed Jun 13 10:19:12 AEST 1990


Chris Schoeneman just sent me a copy of gifview.c that works for 8 bit
machines.  I don't have one, so I can't test it, but here it is.

Kevin
krk at cs.purdue.edu
..!{decwrl,ucbvax,gatech}!purdue!krk

/* gifview.c
 * By Chris Schoeneman
 * jindak at surfside.esd.sgi.com  or
 * nujy at vax5.ccs.cornell.edu
 *
 * This program is public domain. Do with it what you will.
 */

#define	CMAP_START	1024

#include <gl.h>
#include <device.h>
#include <stdio.h>

typedef struct {
  int	dx,dy;		/* size */
  int	colors,bits,cr;	/* num colors, bits/pixel, color resolution */
  char	gcm,		/* global color map flag */
	bgnd;		/* background color */
} screen_dscrp;

typedef struct {
  int	x,y,dx,dy,	/* position, size */
	colors,bits;	/* num colors, bits/pixel */
  char	gcm,order;	/* use global cm, seq. or interlaced */
} image_dscrp;

int		bits_left,byte_count,	/* bits in last_char, bytes left */
		mask[14]={0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff,
			0x1ff,0x3ff,0x7ff,0xfff,0x1fff},
		code_size,countsize,countdown,
		dy_table[4]={8,8,4,2},offset_table[4]={0,4,2,1},
		last_char,bit_mask,least_bits;
short		g_colors[256][3],	/* global color map */
		pixel_row[4096],code_table[4096][2],
		cmap;			/* index of first color */
FILE		*stream_source;		/* file for input */
screen_dscrp	si;		/* global screen descriptor */

/*****************************************************
 *                  Input routines                   *
 *****************************************************/
int	mscanf(FILE *infile, char *parse)
{
  char	*scan;
  int	dx,dy;

  for (scan=parse;*scan;scan++)
    if (getc(infile)!=(int)*scan) return(0);
  return(!0);
}

/* read Screen Descriptor */
int	scan_SD(FILE *infile, screen_dscrp *sd)
{
  char	data;

  data=(char)getc(infile);
  sd->dx=data+((char)getc(infile)<<8);
  data=(char)getc(infile);
  sd->dy=data+((char)getc(infile)<<8);
  data=getc(infile);
  if (data&8) return(0);
  sd->gcm=data&0x80;
  sd->cr=(data&0x70)>>4;
  sd->bits=(data&7)+1;
  sd->colors=1<<sd->bits;
  sd->bgnd=getc(infile);
  if (getc(infile)!=0) return(0);
  return(!0);
}

/* skip past an extension block */
void	skip_EB(FILE *infile)
{
  int	count,garbage[256];

  getc(infile);		/* get function */
  while (count=getc(infile)) fread(garbage,1,count,infile);
}

/* read Image Descriptor */
int	scan_ID(FILE *infile, image_dscrp *id)
{
  char	data;

/* wait for ',' or ';' or '!' EOF */
  do {
    data=(char)getc(infile);
    if (data==';') return(1);
    if (feof(infile)) return(0);
    if (data==0x21) skip_EB(infile);
  } while (data!=0x2c);
  data=(char)getc(infile);
  id->x=data+((char)getc(infile)<<8);
  data=(char)getc(infile);
  id->y=data+((char)getc(infile)<<8);
  data=(char)getc(infile);
  id->dx=data+((char)getc(infile)<<8);
  data=(char)getc(infile);
  id->dy=data+((char)getc(infile)<<8);
  data=(char)getc(infile);
  id->gcm=data&0x80;
  id->order=data&0x40;
  id->bits=(data&7)+1;
  id->colors=1<<id->bits;
  return(2);
}

/* read Color Map */
void	scan_CM(FILE *infile, int colors, short *cm)
{
  short	*scan;
  int	i;

  for (scan=cm,i=3*colors;i>0;i--)
    *scan++=(short)getc(infile);
}

/* reset code stuff */
void	reset_codes(void)
{
  code_size=least_bits+1;
  if (code_size<=2) code_size=3;
  countsize=1<<code_size;
  countdown=countsize-(1<<least_bits)-2;
  bit_mask=(long)mask[code_size];
}

/* clear bitstream */
void	clear_stream(FILE *infile, int bits)
{
  getc(infile);		/* skip minimum bit size */
  byte_count=0;
  last_char=0;
  bits_left=0;
  least_bits=bits;
  stream_source=infile;
  reset_codes();
}

/* read next code and adjust code width */
short	get_code(void)
{
  static char	flag=0;
  short		code;
  int		new;

  if (byte_count==0) byte_count=getc(stream_source);
  if (bits_left<code_size) {
    new=(int)getc(stream_source);
    byte_count--;
    if (bits_left+8<code_size) {
      if (byte_count==0) byte_count=getc(stream_source);
      byte_count--;
      new|=((int)getc(stream_source)<<8);
      code=16;
    }
    else code=8;
    if (bits_left) new<<=bits_left;
    last_char|=new;
    bits_left+=code;
  }
  code=(short)(last_char&bit_mask);
  last_char>>=code_size;
  bits_left-=code_size;
  if (flag) {
    flag=0;
    reset_codes();
  }
  else if (--countdown==0) {
    countdown=countsize;
    countsize<<=1;
    if (++code_size==13) { flag=1; code_size--; }
    else bit_mask=(int)mask[code_size];
  }
  return(code);
}

/*****************************************************
 *                  Other routines                   *
 *****************************************************/
void	install_cmap(int colors, short *cm)
{
  short	*scan;
  int	i;

  for (scan=cm,i=cmap;colors>0;scan+=3,i++,colors--)
    mapcolor(i,*scan,*(scan+1),*(scan+2));
}

void	setup_codes(int colors)
{
  int	i;

  for (i=0;i<colors;i++) code_table[i][0]=code_table[i][1]=i;
}

void	read_interlaced(image_dscrp *id)
{
  int	table_ptr,row_count,dy,y,pass,end_code,clear_code;
  short	prefix,suffix,save,stack[4096],*stack_ptr,*pixel=pixel_row;

  row_count=id->dx;
  clear_code=id->colors;
  end_code=clear_code+1;
  while ((prefix=get_code())==clear_code);
  reset_codes();
  table_ptr=clear_code+2;
  for (pass=0;pass<4;pass++) {
    y=id->y+id->dy-1-offset_table[pass];
    dy=dy_table[pass];
    while (y>=0 && (save=suffix=get_code())!=end_code) {
      if (suffix==clear_code) {
        reset_codes();
        while ((save=get_code())==clear_code);
        reset_codes();
        table_ptr=clear_code+1;
      }
      else {
        code_table[table_ptr][0]=prefix;
        if (suffix==table_ptr)
          code_table[table_ptr][1]=code_table[prefix][1];
        else {
          while (suffix>=id->colors) suffix=code_table[suffix][0];
          code_table[table_ptr][1]=suffix;
        }
      }
      suffix=1;
      stack_ptr=stack;
      while (prefix>=id->colors) {
        *stack_ptr++=code_table[prefix][1];
        prefix=code_table[prefix][0];
        suffix++;
      }
      *stack_ptr=prefix;
      for (;suffix>0;stack_ptr--,suffix--) {
        *pixel++ = cmap+*stack_ptr;
        if (--row_count==0) {
          row_count=id->dx;
          pixel=pixel_row;
          rectwrite(id->x,y,id->x+id->dx-1,y,pixel_row);
          y-=dy;
        }
      }
      table_ptr++;
      prefix=save;
    }
  }
}

void	read_sequential(image_dscrp *id)
{
  int	table_ptr,row_count,y,end_code,clear_code;
  short	*pixel=pixel_row,prefix,suffix,save,stack[4096],*stack_ptr;

  y=id->y+id->dy-1;
  row_count=id->dx;
  clear_code=id->colors;
  end_code=clear_code+1;
  while ((prefix=get_code())==clear_code);
  reset_codes();
  table_ptr=clear_code+2;
  while ((save=suffix=get_code())!=end_code) {
    if (suffix==clear_code) {
      reset_codes();
      while ((save=get_code())==clear_code);
      reset_codes();
      table_ptr=clear_code+1;
    }
    else {
      code_table[table_ptr][0]=prefix;
      if (suffix==table_ptr)
        code_table[table_ptr][1]=code_table[prefix][1];
      else {
        while (suffix>=id->colors) suffix=code_table[suffix][0];
        code_table[table_ptr][1]=suffix;
      }
    }
    suffix=1;
    stack_ptr=stack;
    while (prefix>=id->colors) {
      *stack_ptr++=code_table[prefix][1];
      prefix=code_table[prefix][0];
      suffix++;
    }
    *stack_ptr=prefix;
    for (;suffix>0;stack_ptr--,suffix--) {
      *pixel++ = cmap+*stack_ptr;
      if (--row_count==0) {
        row_count=id->dx;
        pixel=pixel_row;
        rectwrite(id->x,y,id->x+id->dx-1,y,pixel_row);
         y--;
      }
    }
    table_ptr++;
    prefix=save;
  }
}

int	draw_image(FILE *infile)
{
  short		lcm[256][3];
  int		flag;
  image_dscrp	id;

/* get image descriptor and setup colors */
  flag=scan_ID(infile,&id);
  if (flag==0) {
    printf("unexpected eof.\n");
    exit(3);
  }
  if (flag==1) return(0);
  if (id.gcm) {
    scan_CM(infile,id.colors,lcm);
    install_cmap(id.colors,lcm);
  }
  else {
    install_cmap(si.colors,g_colors);
    id.colors=si.colors;
    id.bits=si.bits;
  }
/* draw image */
  if (id.bits==1) {
    id.bits=2;
    id.colors=4;
  }
  clear_stream(infile,id.bits);
  setup_codes(id.colors);
  color(si.bgnd+CMAP_START);
  clear();
  if (id.order) read_interlaced(&id);
  else read_sequential(&id);
  return(!0);
}

void	read_cmap(int colors, short *cm)
{
  short	*scan;
  int	i;

  for (scan=cm,i=cmap;colors>0;scan+=3,i++,colors--) {
    getmcolor(i,scan,scan+1,scan+2);
    
  }
}

void	main(int argc, char **argv)
{
  FILE	*gif_data;
  int	name_arg=1,map=0,planes;
  short	key_status,save_map[256][3];

/* open file */
  if (argc<2 || argc>3) {
    printf("usage: %s [-map#] <filename>\n",argv[0]);
    exit(1);
  }
  if (argv[1][0]=='-') {
    name_arg=2;
    if (isdigit(argv[1][1])) map=argv[1][1]-'0';
    if (map<0 || map>7) printf("%d out of range (0-7).\n");
  }
  gif_data=fopen(argv[name_arg],"r");
  if (gif_data==NULL) {
    printf("can't open %s.\n",argv[name_arg]);
    exit(1);
  }
  if (!mscanf(gif_data,"GIF87a")) {
    printf("%s not a gif file.\n",argv[name_arg]);
    exit(2);
  }
/* get global info */
  if (!scan_SD(gif_data,&si)) {
    printf("data format error.\n");
    exit(3);
  }
  printf("File %s:\n resolution: %dx%d\n     colors: %d\n",
	argv[name_arg],si.dx,si.dy,si.colors);
  printf("Press escape to quit.\n");
/* get global colors */
  if (si.gcm) scan_CM(gif_data,si.colors,g_colors);
/* open window */
  prefsize(si.dx,si.dy);
  maxsize(si.dx,si.dy);
  minsize(si.dx,si.dy);
  winopen(argv[name_arg]);
/* setup colormap mode */
  cmode();
  onemap();
  gconfig();
  planes=getplanes();
  if (planes>8) cmap=CMAP_START+(map<<8);
  else cmap=0;
  read_cmap(si.colors,save_map);
  while (draw_image(gif_data));
  fclose(gif_data);
  qdevice(ESCKEY);	/* escape key */
  qreset();
  while (qread(&key_status)!=ESCKEY);
  unqdevice(ESCKEY);
  install_cmap(si.colors,save_map);
}



More information about the Comp.sys.sgi mailing list