GIF file viewer

George Phillips phillips at grads.cs.ubc.ca
Sat Sep 2 14:41:44 AEST 1989


Since I got more requests for this program than I could count on my
fingers, I decided to post it.  Included is a GIF file viewer and
a viewer for 24 bit images as found on venera.isi.edu.  These programs both
require a 24 bit deep display and have only been tried on a personal iris.
I hope they'll end up in the archives at vgr.brl.mil, but if not I'll
try and put them there myself.  I look forward to your improvements.


George Phillips phillips at cs.ubc.ca {alberta,uw-beaver,uunet}!ubc-cs!phillips


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile igif.c decoder.c errs.h std.h vimg.c
# Wrapped by phillips at grads.cs.ubc.ca on Fri Sep  1 21:34:12 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(793 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThere are 2 programs here.  igif will display GIF files on a personal
Xiris workstation.  vimg displays 24 bit RGB files in the venera imglib
Xformat.  Images in the imglib format can be found on venera.isi.edu.
X
XEach program uses very simple interfaces to graphics and windows.  They
Xwork and are more or less directly transliterated from examples in the
Xgraphics documentation that came with our iris.
X
XBoth programs could use improvement, like getting rid of 24 bit mode or
Xadding scroll bars and so on.  If you do make improvements, please send
Xthem to me (phillips at cs.ubc.ca {alberta,uw-beaver,uunet}!ubc-cs!phillips)
Xand maybe I can keep track of future versions.
X
XBut most of all, have fun displaying images.
X
XGeorge Phillips
XDepartment of Computer Science
XUniversity of British Columbia
END_OF_FILE
if test 793 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(273 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCFLAGS=
X
X# If this doesn't work, try LIB=-Zg
XLIB=-lgl_s
X
Xall: igif vimg
X
Xigif: igif.o decoder.o
X	cc -o igif igif.o decoder.o $(LIB)
X
Xdecoder.o: errs.h std.h
X
Xvimg: vimg.o
X	cc -o vimg vimg.o $(LIB)
X
Xshar:
X	shar README Makefile igif.c decoder.c errs.h std.h vimg.c >img.shar
END_OF_FILE
if test 273 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'igif.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'igif.c'\"
else
echo shar: Extracting \"'igif.c'\" \(6871 characters\)
sed "s/^X//" >'igif.c' <<'END_OF_FILE'
X/*
X * igif.c -- display a GIF image on the personal iris.
X *
X * usage:	igif [ file.gif ]
X *
X * Will display the GIF file given as the first argument or a GIF file
X * read from standard input if no arguments are given.
X *
X * This is not a particularly pretty piece of code.  This works on the
X * personal iris we have here, but has not been tested on other irises
X * or other SGI machines.  It uses 24 bit RGB mode because that's all
X * I have looked into (plus it's easy :-).  GIF images are pretty much
X * limited to 256 colours, so using some sort of colourmap mode should
X * be possible.  Those with more experience could also modify the program
X * to display multiple GIF images with a single invocation.
X *
X * Copyright 1989 by George Phillips
X *
X * Permission is granted to freely distribute this program in whole or in
X * part provided you don't make money off it, you don't pretend that you
X * wrote it and that this notice accompanies the code.
X *
X * The GIF LZW decoder was written by someone else who's copyright notice
X * is contained in decode.c.
X *
X * George Phillips <phillips at grads.cs.ubc.ca>
X * Department of Computer Science
X * University of British Columbia
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <gl.h>
X#include <device.h>
X
X#include "errs.h"
X
Xint bad_code_count;
XFILE* glob_fp;
Xstatic char* gif_name;
X
Xmain(argc, argv)
Xint		argc;
Xchar*	argv[];
X{
X	FILE*			fp;
X
X	if (argc > 2) {
X		fprintf(stderr, "Sorry, I can only do one GIF file at a time.\n");
X		exit(1);
X	}
X
X	if (argc == 1) {
X		gif_name = "standard input";
X		gif_display(glob_fp = stdin);
X	}
X	else {
X		char* p;
X		char* lastslash;
X
X		for (p = argv[1], lastslash = argv[1] - 1; *p; p++)
X			if (*p == '/')
X				lastslash = p;
X
X		gif_name = lastslash + 1;
X
X		if ((fp = fopen(argv[1], "r")) == NULL) {
X			fprintf(stderr, "can't open '%s'\n", argv[1]);
X			exit(1);
X		}
X		gif_display(glob_fp = fp);
X	}
X	screen_manage();
X	exit(0);
X}
X
Xstatic int err = 0;
Xstatic long global[256];
Xstatic long local[256];
Xstatic long* cmap;
Xstatic long* screen;
Xstatic long* lineptr;
Xstatic int	i_y;
Xstatic int	pass;
Xstatic long* imagestart;
Xstatic int s_width;
Xstatic int s_height;
Xstatic int i_height;
Xstatic int is_interlaced;
X
X#define error(x)	printf("%s at byte %d\n", x, ftell(fp)); return(0)
X#define reterr(x)	if (err != 0) { error(x); }
X#define reteof()	reterr("Unexpected EOF")
X#define skipbyte(x)	getbyte(x); reteof()
X
Xgif_display(fp)
XFILE*	fp;
X{
X	static unsigned char buf[4096];
X	int s_control, back;
X	int i_top, i_left, i_width, i_control;
X	int ch;
X	int nc;
X	int	i, j;
X
X	/* read signature */
X	if (fread(buf, 3, 1, fp) != 1) {
X		error("File too short");
X	}
X	
X	if (strncmp(buf, "GIF", 3)) {
X		error("Not a GIF file");
X	}
X
X	if (fread(buf, 3, 1, fp) != 1) {
X		error("File too short");
X	}
X
X	if (strncmp(buf, "87a", 3)) {
X		buf[3] = '\0';
X		printf("unknown version '%s'\n", buf);
X		return(0);
X	}
X	
X	/* read screen descriptor */
X	s_width = getword(fp); reteof();
X	s_height = getword(fp); reteof();
X	s_control = getbyte(fp); reteof();
X	back = getbyte(fp); reteof();
X	skipbyte(fp);
X
X	if ((screen = (long*)malloc(sizeof(long) * s_width * s_height)) == NULL) {
X		fprintf(stderr, "not enough memory for screen, bye!\n");
X		exit(1);
X	}
X	/* sure, I should use bzero. Whatever */
X	{ register int i;
X		for (i = 0; i < s_width * s_height; i++)
X			screen[i] = 0;
X	}
X	prefsize(s_width, s_height);
X	winopen(gif_name);
X	RGBmode();
X	gconfig();
X
X	if (s_control & 128) { /* global colour map */
X		if (fread(buf, (2 << (s_control & 7)) * 3, 1, fp) != 1) {
X			error("EOF in global colourmap");
X		}
X		gif2rgb(buf, global, 2 << (s_control & 7));
X	}
X
X	for (;;) {
X		ch = getbyte(fp);
X		reterr("no terminator");
X		switch (ch) {
X		case ',':	/* image follows */
X			i_left = getword(fp);	reteof();
X			i_top = getword(fp);	reteof();
X			i_width = getword(fp); reteof();
X			i_height = getword(fp); reteof();
X			i_control = getbyte(fp); reteof();
X			is_interlaced = i_control & 64; 
X			nc = 2 << (s_control & 7);
X			cmap = global;
X			if (i_control & 128) { /* local colour map */
X				if (fread(buf, (2 << (i_control & 7)) * 3, 1, fp) != 1) {
X					error("EOF in local colourmap");
X				}
X				nc = 2 << (i_control & 7);
X				gif2rgb(buf, local, nc);
X				cmap = local;
X			}
X			bad_code_count = 0;
X			imagestart = lineptr = screen + (s_width * i_top) + i_left +
X					(i_height - 1) * s_width;
X			i_y = 0;
X			pass = 0;
X			decoder(i_width);
X			/* ignore rest of blocks used by decoder */
X			skipblocks(fp); reterr("Bad block in image");
X			break;
X		case ';':	/* terminator ... */
X			return(0);
X		case '!':	/* extension block */
X			skipbyte(fp);	/* function code */
X			skipblocks(fp); reterr("Bad block in extension block");
X			break;
X		default:
X			/* Supposed to ignore any unknown characters up to the image
X			 * separator, but I prefer to be tight about these things because
X			 * there are many corrupt images out there.
X			 */
X			printf("Unknown block type '%c' (%d) at byte %d\n",
X				ch, ch, ftell(fp));
X			return(0);
X		}
X	}
X}
X
X/* Convert the GIF colourmap into long rgb components which can be directly
X * plunked into an lrect.
X *
X * GIF colourmap is a byte stream: rgbrgbrgb
X * lrect format is in 4 byte words: abgr abgr abgr
X * (the a is alpha, which should be zero)
X */
Xgif2rgb(g, r, len)
Xchar*	g;
Xlong*	r;
Xint		len;
X{
X	register int i;
X	register int j;
X
X	for (i = j = 0; i < len; i++, j += 3)
X		r[i] = g[j] | (g[j+1] << 8) | (g[j+2] << 16);
X}
X
Xstatic int pass_width[] = { 8, 8, 4, 2 };
Xstatic int pass_start[] = { 0, 4, 2, 1 };
X
Xout_line(pixel, linelen)
Xunsigned char* pixel;
Xint	linelen;
X{
X	register int i;
X
X	for (i = 0; i < linelen; i++)
X		lineptr[i] = cmap[pixel[i]];
X	
X	if (!is_interlaced) {
X		lineptr -= s_width;
X	}
X	else {
X		lineptr -= pass_width[pass] * s_width;
X		i_y += pass_width[pass];
X		if (i_y >= i_height) {
X			pass++;
X			i_y = pass_start[pass];
X			lineptr = imagestart - pass_start[pass] * s_width;
X		}
X	}
X}
X
Xint get_byte()
X{
X	return(getbyte(glob_fp));
X}
X
Xint getbyte(fp)
XFILE*	fp;
X{
X	int	ch;
X
X	err = 0;
X	if ((ch = fgetc(fp)) == EOF) {
X		err = 1;
X		return(READ_ERROR);
X	}
X	return(ch & 255);
X}
X
Xint getword(fp)
XFILE*	fp;
X{
X	int	c1, c2;
X
X	err = 0;
X	if ((c1 = fgetc(fp)) == EOF) {
X		err = 1;
X		return(0);
X	}
X	if ((c2 = fgetc(fp)) == EOF) {
X		err = 1;
X		return(0);
X	}
X	return(((c2 & 255) << 8) | (c1 & 255));
X}
X
Xskipblocks(fp)
XFILE*	fp;
X{
X	int len;
X	static char buf[256];
X
X	err = 0;
X
X	for (;;) {
X		len = getbyte(fp);
X		reterr("EOF in blocks");
X
X		if (len == 0)
X			return(0);
X
X		if (fread(buf, len, 1, fp) != 1) {
X			puts("EOF in blocks");
X			err = 1;
X			return(0);
X		}
X	}
X}
X
Xscreen_manage()
X{
X	lrectwrite(0, 0, s_width - 1, s_height - 1, screen);
X
X	qdevice(REDRAW);
X	qdevice(PIECECHANGE);
X	qdevice(WINQUIT);
X
X	while (1) {
X		short data;
X
X		switch (qread(&data)) {
X		case REDRAW:
X		case PIECECHANGE:
X			lrectwrite(0, 0, s_width - 1, s_height - 1, screen);
X			break;
X		case WINQUIT:
X			exit(0);
X		default:
X			break;
X		}
X	}
X}
X
END_OF_FILE
if test 6871 -ne `wc -c <'igif.c'`; then
    echo shar: \"'igif.c'\" unpacked with wrong size!
fi
# end of 'igif.c'
fi
if test -f 'decoder.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'decoder.c'\"
else
echo shar: Extracting \"'decoder.c'\" \(12570 characters\)
sed "s/^X//" >'decoder.c' <<'END_OF_FILE'
X/* DECODE.C - An LZW decoder for GIF
X * Copyright (C) 1987, by Steven A. Bennett
X *
X * Permission is given by the author to freely redistribute and include
X * this code in any program as long as this credit is given where due.
X *
X * In accordance with the above, I want to credit Steve Wilhite who wrote
X * the code which this is heavily inspired by...
X *
X * GIF and 'Graphics Interchange Format' are trademarks (tm) of
X * Compuserve, Incorporated, an H&R Block Company.
X *
X * Release Notes: This file contains a decoder routine for GIF images
X * which is similar, structurally, to the original routine by Steve Wilhite.
X * It is, however, somewhat noticably faster in most cases.
X *
X * GWP -- if GINFO if defined, it will use a global variable and
X * stdio routines in place of most of the get_byte calls to speed
X * things along.
X */
X
X#define GINFO
X
X#ifdef GINFO
X
X#include <stdio.h>
Xextern FILE* glob_fp;
X
X#endif
X
X#include "std.h"
X#include "errs.h"
X
XIMPORT TEXT *malloc();                 /* Standard C library allocation */
X
X/* IMPORT INT get_byte()
X *
X *   - This external (machine specific) function is expected to return
X * either the next byte from the GIF file, or a negative number, as
X * defined in ERRS.H.
X */
XIMPORT INT get_byte();
X
X/* IMPORT INT out_line(pixels, linelen)
X *     UBYTE pixels[];
X *     INT linelen;
X *
X *   - This function takes a full line of pixels (one byte per pixel) and
X * displays them (or does whatever your program wants with them...).  It
X * should return zero, or negative if an error or some other event occurs
X * which would require aborting the decode process...  Note that the length
X * passed will almost always be equal to the line length passed to the
X * decoder function, with the sole exception occurring when an ending code
X * occurs in an odd place in the GIF file...  In any case, linelen will be
X * equal to the number of pixels passed...
X */
XIMPORT INT out_line();
X
X/* IMPORT INT bad_code_count;
X *
X * This value is the only other global required by the using program, and
X * is incremented each time an out of range code is read by the decoder.
X * When this value is non-zero after a decode, your GIF file is probably
X * corrupt in some way...
X */
XIMPORT INT bad_code_count;
X
X#ifndef GINFO
X#define NULL   0L
X#endif
X
X#define MAX_CODES   4095
X
X/* Static variables */
XLOCAL WORD curr_size;                     /* The current code size */
XLOCAL WORD clear;                         /* Value for a clear code */
XLOCAL WORD ending;                        /* Value for a ending code */
XLOCAL WORD newcodes;                      /* First available code */
XLOCAL WORD top_slot;                      /* Highest code for current size */
XLOCAL WORD slot;                          /* Last read code */
X
X/* The following static variables are used
X * for seperating out codes
X */
XLOCAL WORD navail_bytes = 0;              /* # bytes left in block */
XLOCAL WORD nbits_left = 0;                /* # bits left in current byte */
XLOCAL UTINY b1;                           /* Current byte */
XLOCAL UTINY byte_buff[257];               /* Current block */
XLOCAL UTINY *pbytes;                      /* Pointer to next byte in block */
X
XLOCAL LONG code_mask[13] = {
X     0,
X     0x0001, 0x0003,
X     0x0007, 0x000F,
X     0x001F, 0x003F,
X     0x007F, 0x00FF,
X     0x01FF, 0x03FF,
X     0x07FF, 0x0FFF
X     };
X
X
X/* This function initializes the decoder for reading a new image.
X */
XLOCAL WORD init_exp(size)
X   WORD size;
X   {
X   curr_size = size + 1;
X   top_slot = 1 << curr_size;
X   clear = 1 << size;
X   ending = clear + 1;
X   slot = newcodes = ending + 1;
X   navail_bytes = nbits_left = 0;
X   return(0);
X   }
X
X/* get_next_code()
X * - gets the next code from the GIF file.  Returns the code, or else
X * a negative number in case of file errors...
X */
XLOCAL WORD get_next_code()
X   {
X   WORD i, x;
X   ULONG ret;
X
X   if (nbits_left == 0)
X      {
X      if (navail_bytes <= 0)
X         {
X
X         /* Out of bytes in current block, so read next block
X          */
X         pbytes = byte_buff;
X#ifdef GINFO
X		if ((navail_bytes = fgetc(glob_fp)) == EOF)
X			return(READ_ERROR);
X#else
X         if ((navail_bytes = get_byte()) < 0)
X            return(navail_bytes);
X#endif
X         else if (navail_bytes)
X            {
X#ifdef GINFO
X			if (fread(byte_buff, navail_bytes, 1, glob_fp) != 1)
X				return(READ_ERROR);
X#else
X            for (i = 0; i < navail_bytes; ++i)
X               {
X               if ((x = get_byte()) < 0)
X                  return(x);
X               byte_buff[i] = x;
X               }
X#endif
X            }
X         }
X      b1 = *pbytes++;
X      nbits_left = 8;
X      --navail_bytes;
X      }
X
X   ret = b1 >> (8 - nbits_left);
X   while (curr_size > nbits_left)
X      {
X      if (navail_bytes <= 0)
X         {
X
X         /* Out of bytes in current block, so read next block
X          */
X         pbytes = byte_buff;
X#ifdef GINFO
X		 if ((navail_bytes = fgetc(glob_fp)) == EOF)
X			return(READ_ERROR);
X#else
X         if ((navail_bytes = get_byte()) < 0)
X            return(navail_bytes);
X#endif
X         else if (navail_bytes)
X            {
X#ifdef GINFO
X			if (fread(byte_buff, navail_bytes, 1, glob_fp) != 1)
X				return(READ_ERROR);
X#else
X            for (i = 0; i < navail_bytes; ++i)
X               {
X               if ((x = get_byte()) < 0)
X                  return(x);
X               byte_buff[i] = x;
X               }
X#endif
X            }
X         }
X      b1 = *pbytes++;
X      ret |= b1 << nbits_left;
X      nbits_left += 8;
X      --navail_bytes;
X      }
X   nbits_left -= curr_size;
X   ret &= code_mask[curr_size];
X   return((WORD)(ret));
X   }
X
X
X/* The reason we have these seperated like this instead of using
X * a structure like the original Wilhite code did, is because this
X * stuff generally produces significantly faster code when compiled...
X * This code is full of similar speedups...  (For a good book on writing
X * C for speed or for space optomisation, see Efficient C by Tom Plum,
X * published by Plum-Hall Associates...)
X */
XLOCAL UTINY stack[MAX_CODES + 1];            /* Stack for storing pixels */
XLOCAL UTINY suffix[MAX_CODES + 1];           /* Suffix table */
XLOCAL UWORD prefix[MAX_CODES + 1];           /* Prefix linked list */
X
X/* WORD decoder(linewidth)
X *    WORD linewidth;               * Pixels per line of image *
X *
X * - This function decodes an LZW image, according to the method used
X * in the GIF spec.  Every *linewidth* "characters" (ie. pixels) decoded
X * will generate a call to out_line(), which is a user specific function
X * to display a line of pixels.  The function gets it's codes from
X * get_next_code() which is responsible for reading blocks of data and
X * seperating them into the proper size codes.  Finally, get_byte() is
X * the global routine to read the next byte from the GIF file.
X *
X * It is generally a good idea to have linewidth correspond to the actual
X * width of a line (as specified in the Image header) to make your own
X * code a bit simpler, but it isn't absolutely necessary.
X *
X * Returns: 0 if successful, else negative.  (See ERRS.H)
X *
X */
X
XWORD decoder(linewidth)
X   WORD linewidth;
X   {
X   FAST UTINY *sp, *bufptr;
X   UTINY *buf;
X   FAST WORD code, fc, oc, bufcnt;
X   WORD c, size, ret;
X
X   /* Initialize for decoding a new image...
X    */
X   if ((size = get_byte()) < 0)
X      return(size);
X   if (size < 2 || 9 < size)
X      return(BAD_CODE_SIZE);
X   init_exp(size);
X
X   /* Initialize in case they forgot to put in a clear code.
X    * (This shouldn't happen, but we'll try and decode it anyway...)
X    */
X   oc = fc = 0;
X
X   /* Allocate space for the decode buffer
X    */
X   if ((buf = (UTINY *)malloc(linewidth + 1)) == NULL)
X      return(OUT_OF_MEMORY);
X
X   /* Set up the stack pointer and decode buffer pointer
X    */
X   sp = stack;
X   bufptr = buf;
X   bufcnt = linewidth;
X
X   /* This is the main loop.  For each code we get we pass through the
X    * linked list of prefix codes, pushing the corresponding "character" for
X    * each code onto the stack.  When the list reaches a single "character"
X    * we push that on the stack too, and then start unstacking each
X    * character for output in the correct order.  Special handling is
X    * included for the clear code, and the whole thing ends when we get
X    * an ending code.
X    */
X   while ((c = get_next_code()) != ending)
X      {
X
X      /* If we had a file error, return without completing the decode
X       */
X      if (c < 0)
X         {
X         free(buf);
X         return(0);
X         }
X
X      /* If the code is a clear code, reinitialize all necessary items.
X       */
X      if (c == clear)
X         {
X         curr_size = size + 1;
X         slot = newcodes;
X         top_slot = 1 << curr_size;
X
X         /* Continue reading codes until we get a non-clear code
X          * (Another unlikely, but possible case...)
X          */
X         while ((c = get_next_code()) == clear)
X            ;
X
X         /* If we get an ending code immediately after a clear code
X          * (Yet another unlikely case), then break out of the loop.
X          */
X         if (c == ending)
X            break;
X
X         /* Finally, if the code is beyond the range of already set codes,
X          * (This one had better NOT happen...  I have no idea what will
X          * result from this, but I doubt it will look good...) then set it
X          * to color zero.
X          */
X         if (c >= slot)
X            c = 0;
X
X         oc = fc = c;
X
X         /* And let us not forget to put the char into the buffer... And
X          * if, on the off chance, we were exactly one pixel from the end
X          * of the line, we have to send the buffer to the out_line()
X          * routine...
X          */
X         *bufptr++ = c;
X         if (--bufcnt == 0)
X            {
X            if ((ret = out_line(buf, linewidth)) < 0)
X               {
X               free(buf);
X               return(ret);
X               }
X            bufptr = buf;
X            bufcnt = linewidth;
X            }
X         }
X      else
X         {
X
X         /* In this case, it's not a clear code or an ending code, so
X          * it must be a code code...  So we can now decode the code into
X          * a stack of character codes. (Clear as mud, right?)
X          */
X         code = c;
X
X         /* Here we go again with one of those off chances...  If, on the
X          * off chance, the code we got is beyond the range of those already
X          * set up (Another thing which had better NOT happen...) we trick
X          * the decoder into thinking it actually got the last code read.
X          * (Hmmn... I'm not sure why this works...  But it does...)
X          */
X         if (code >= slot)
X            {
X            if (code > slot)
X               ++bad_code_count;
X            code = oc;
X            *sp++ = fc;
X            }
X
X         /* Here we scan back along the linked list of prefixes, pushing
X          * helpless characters (ie. suffixes) onto the stack as we do so.
X          */
X         while (code >= newcodes)
X            {
X            *sp++ = suffix[code];
X            code = prefix[code];
X            }
X
X         /* Push the last character on the stack, and set up the new
X          * prefix and suffix, and if the required slot number is greater
X          * than that allowed by the current bit size, increase the bit
X          * size.  (NOTE - If we are all full, we *don't* save the new
X          * suffix and prefix...  I'm not certain if this is correct...
X          * it might be more proper to overwrite the last code...
X          */
X         *sp++ = code;
X         if (slot < top_slot)
X            {
X            suffix[slot] = fc = code;
X            prefix[slot++] = oc;
X            oc = c;
X            }
X         if (slot >= top_slot)
X            if (curr_size < 12)
X               {
X               top_slot <<= 1;
X               ++curr_size;
X               } 
X
X         /* Now that we've pushed the decoded string (in reverse order)
X          * onto the stack, lets pop it off and put it into our decode
X          * buffer...  And when the decode buffer is full, write another
X          * line...
X          */
X         while (sp > stack)
X            {
X            *bufptr++ = *(--sp);
X            if (--bufcnt == 0)
X               {
X               if ((ret = out_line(buf, linewidth)) < 0)
X                  {
X                  free(buf);
X                  return(ret);
X                  }
X               bufptr = buf;
X               bufcnt = linewidth;
X               }
X            }
X         }
X      }
X   ret = 0;
X   if (bufcnt != linewidth)
X      ret = out_line(buf, (linewidth - bufcnt));
X   free(buf);
X   return(ret);
X   }
X
END_OF_FILE
if test 12570 -ne `wc -c <'decoder.c'`; then
    echo shar: \"'decoder.c'\" unpacked with wrong size!
fi
# end of 'decoder.c'
fi
if test -f 'errs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'errs.h'\"
else
echo shar: Extracting \"'errs.h'\" \(366 characters\)
sed "s/^X//" >'errs.h' <<'END_OF_FILE'
X/* Various error codes used by decoder
X * and my own routines...   It's okay
X * for you to define whatever you want,
X * as long as it's negative...  It will be
X * returned intact up the various subroutine
X * levels...
X */
X#define OUT_OF_MEMORY -10
X#define BAD_CODE_SIZE -20
X#define READ_ERROR -1
X#define WRITE_ERROR -2
X#define OPEN_ERROR -3
X#define CREATE_ERROR -4
X
END_OF_FILE
if test 366 -ne `wc -c <'errs.h'`; then
    echo shar: \"'errs.h'\" unpacked with wrong size!
fi
# end of 'errs.h'
fi
if test -f 'std.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'std.h'\"
else
echo shar: Extracting \"'std.h'\" \(278 characters\)
sed "s/^X//" >'std.h' <<'END_OF_FILE'
X/* STD.H - My own standard header file...
X */
X
X#define LOCAL static
X#define IMPORT extern
X
X#define FAST register
X
Xtypedef short WORD;
Xtypedef unsigned short UWORD;
Xtypedef char TEXT;
Xtypedef unsigned char UTINY;
Xtypedef long LONG;
Xtypedef unsigned long ULONG;
Xtypedef int INT;
X
END_OF_FILE
if test 278 -ne `wc -c <'std.h'`; then
    echo shar: \"'std.h'\" unpacked with wrong size!
fi
# end of 'std.h'
fi
if test -f 'vimg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vimg.c'\"
else
echo shar: Extracting \"'vimg.c'\" \(4677 characters\)
sed "s/^X//" >'vimg.c' <<'END_OF_FILE'
X/*
X * vimg -- display a venera imglib 24 bit image.
X *
X * usage: vimg picture
X *	or
X *		  vimg picture.a
X *
X * This program will display the 24 bit RGB images which can be ftp'ed from
X * venera.isi.edu.  The format is very simple.  Using some base name (like
X * "picture"), the following files are relevant:
X *
X *	picture.a		-- contains width and height information
X *	picture.r		-- red component of image (1 byte per pixel)
X *	picture.g		-- green component of image (ditto)
X *	picture.b		-- blue component of image (ditto)
X *
X * The program will either take a base name or the .a version.  Also, if any of
X * the files are compressed, it will run uncompress -c on them.  In other words,
X * it will also look for .r.Z, .b.Z and .g.Z files.  I'm not really sure what
X * the standard iris setup is, but if you don't have /usr/bsd in you path,
X * it won't work.  Either add it to your path or change "uncompress" to 
X * /usr/bsd/uncompress in the program.
X *
X * BUGS:
X *
X * If image is bigger than 1024 on any side, then I should clip it.  But I
X * don't since it gives me the urge for scrollbars...
X *
X * It seems if any optimization is turned on, then it will break if any of the
X * red, green or blue components (.r, .g or .b files) is _not_ compressed.
X *
X *
X * Copyright 1989 by George Phillips
X *
X * Permission is granted to freely distribute this program in whole or in
X * part provided you don't make money off it, you don't pretend that you
X * wrote it and that this notice accompanies the code.
X *
X * George Phillips <phillips at grads.cs.ubc.ca>
X * Department of Computer Science
X * University of British Columbia
X */
X
X#include <gl.h>
X#include <stdio.h>
X#include <malloc.h>
X#include <device.h>
X
Xint width;
Xint height;
X
Xlong* img;
Xchar* buf;
X
Xmain(argc, argv)
Xint argc;
Xchar* argv[];
X{
X	int i;
X	FILE* fp;
X	char att[256], red[256], green[256], blue[256];
X	char* myalloc();
X	FILE* myopen();
X	char* p;
X	char* lastdot;
X	char* shortname;
X	char ch;
X	char dimen[256];
X
X	if (argc != 2) {
X		fprintf(stderr, "usage: vimg basename OR vimg basename.a\n");
X		exit(1);
X	}
X
X	shortname = argv[1] - 1;
X	lastdot = NULL;
X	for (p = argv[1]; *p; p++)
X		if (*p == '.')
X			lastdot = p;
X		else if (*p == '/')
X			shortname = p;
X	
X	shortname++;
X	
X	if (lastdot != NULL && !strcmp(lastdot, ".a"))
X		*lastdot = '\0';
X
X	sprintf(att, "%s.a", argv[1]);
X	fp = myopen(att);
X	fgets(dimen, 256, fp);
X	ch = dimen[4];
X	dimen[4] = '\0';
X	width = atoi(dimen);
X	dimen[4] = ch;
X	dimen[8] = '\0';
X	height = atoi(dimen + 4);
X
X	printf("%s: width = %d, height = %d\n", argv[1], width, height);
X	myclose();
X
X	img = (long*)myalloc(sizeof(long) * width * height);
X	buf = myalloc(width);
X
X	for (i = 0; i < width * height; i++)
X		img[i] = 0;
X
X	sprintf(red, "%s.r", argv[1]);
X	printf("reading %s\n", red);
X	getcom(myopen(red), 0);
X	myclose();
X
X	sprintf(green, "%s.g", argv[1]);
X	printf("reading %s\n", green);
X	getcom(myopen(green), 8);
X	myclose();
X
X	sprintf(blue, "%s.b", argv[1]);
X	printf("reading %s\n", blue);
X	getcom(myopen(blue), 16);
X	myclose();
X
X	prefsize(width, height);
X	winopen(shortname);
X	RGBmode();
X	gconfig();
X	lrectwrite(0, 0, width - 1, height - 1, img);
X
X	qdevice(REDRAW);
X	qdevice(PIECECHANGE);
X	qdevice(WINQUIT);
X
X	while (1) {
X		short data;
X
X		switch (qread(&data)) {
X		case REDRAW:
X		case PIECECHANGE:
X			lrectwrite(0, 0, width - 1, height - 1, img);
X			break;
X		case WINQUIT:
X			exit(0);
X		default:
X			break;
X		}
X	}
X}
X
Xgetcom(fp, shift)
XFILE* fp;
Xint shift;
X{
X	FILE* fp;
X	long* line;
X	int i;
X
X	line = img + width * height - width;
X	while (fread(buf, width, 1, fp) == 1) {
X		if (line < img) {
X			printf("extra data, oh well, ignored\n");
X			break;
X		}
X		for (i = 0; i < width; i++)
X			line[i] |= (buf[i] << shift);
X		line -= width;
X	}
X}
X
Xfatal(s)
Xchar* s;
X{
X	fprintf(stderr, "%s\n", s);
X	exit(1);
X}
X
X/* open a file, or a pipe to uncompress -c if it is compressed */
X/* myclose is very hardwired, but will work as long as only 1 file */
X/* is opened by myopen at a time */
X
Xint ftype;
XFILE* glob_fp;
X
XFILE* myopen(fname)
Xchar* fname;
X{
X	FILE* fp;
X	char cmd[256];
X
X	if ((fp = fopen(fname, "r")) == NULL) {
X		sprintf(cmd, "%s.Z", fname);
X		if (access(cmd, 4) < 0) {
X			fprintf(stderr, "Can't open %s or %s.Z\n", fname, fname);
X			exit(1);
X		}
X		sprintf(cmd, "uncompress -c %s.Z", fname);
X		if ((fp = popen(cmd, "r")) == NULL) {
X			fprintf(stderr, "can't open %s or %s.Z\n", fname, fname);
X			exit(1);
X		}
X		ftype = 2;
X	}
X	else
X		ftype = 1;
X	return(glob_fp = fp);
X}
X
Xmyclose()
X{
X	if (ftype == 1)
X		fclose(glob_fp);
X	else
X		pclose(glob_fp);
X}
X
X/* malloc or die! */
Xchar* myalloc(size)
Xint size;
X{
X	char* p;
X
X	if ((p = malloc(size)) == NULL) {
X		fprintf(stderr, "out of memory\n");
X		exit(1);
X	}
X	return(p);
X}
END_OF_FILE
if test 4677 -ne `wc -c <'vimg.c'`; then
    echo shar: \"'vimg.c'\" unpacked with wrong size!
fi
# end of 'vimg.c'
fi
echo shar: End of shell archive.
exit 0



More information about the Comp.sys.sgi mailing list