[comp.graphics] Gif Viewer for sun3/sunview

nakada@husc8.HARVARD.EDU (Paul Nakada) (07/30/88)

# this is a Gif picture viewer for the Sun 3 computer ..  It may work on others,
# butit hasn't been tested on anything besides a Sun 3/60.   The code here works
# ok, but it needs some help with the unix interface.  I am but a novice 
# programmer, so please feel free to delve into it.  This program in it's original
# incarnation was written by scott hemphill .. it was then converted to create a 
# sun raster file.  I hope somebody finds this useful...
# paul nakada
# nakada@husc4.harvard.edu
# nakada@husc4.bitnet
# nakada@husc4.uucp
#
#----------------------------<cut here, save, and sh <filename> >----------
# -------- Makefile --------
echo extracting file Makefile
cat << '#*\\\THE_END//////*#' > Makefile
CFILES =	main.c	error.c	headers.c	raster.c

OBJECTS =	main.o	error.o	headers.o	raster.o

PRINT =	main.c	error.c	headers.c	raster.c

CMD	= vg
DESTIN	= .
CFLAGS	= -O $(DEFS)
DEFS	= 
LIBS	= -lsuntool -lsunwindow -lpixrect

$(CMD)	: $(OBJECTS) /lib/libc.a /usr/lib/libsuntool.a /usr/lib/libsunwindow.a /usr/lib/libpixrect.a 
	ld /lib/crt0.o $(OBJECTS) -o $(CMD) $(LIBS) -lc

depend	:
	@makedepend $(CFILES)

clean	:
	-rm $(OBJECTS) $(CMD)

print	:
	print -h $(PRINT)

lint	:
	lint $(CFILES)

#*\\\THE_END//////*#
# -------- error.c --------
echo extracting file error.c
cat << '#*\\\THE_END//////*#' > error.c
#include <stdio.h>
#include "viewgif.h"

void usage()
{
	fprintf(stderr, "usage: %s [file ... ]\n", progname);
	exit(1);
}

void fatal(s)
char *s;
{
	fprintf(stderr,"%s: %s\n",progname, s);
	exit(-1);
}
#*\\\THE_END//////*#
# -------- headers.c --------
echo extracting file headers.c
cat << '#*\\\THE_END//////*#' > headers.c
#include <stdio.h>
#include <ctype.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include "viewgif.h"
#include "sunvgif.h"

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");
}

void readscreen()
{
	unsigned char buf[7];

	xx=yy=0;
	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;
		fread(globalmap,3,1 << globalbits,infile);
	}
}

void initcolors(colortable, colormap,ncolors)

char
	colortable[256][3];
unsigned char
	colormap[256][3];
int	ncolors;
{
	register unsigned 
		color;
	register
		i;
	for (i=0; i < ncolors; i++) {
		red[i] = colormap[i][0];
		green[i] = colormap[i][1];
		blue[i] = colormap[i][2];
	}
	pw_setcmsname(pw, filename);
	pw_putcolormap(pw, 0, ncolors, red, green, blue);
}





#*\\\THE_END//////*#
# -------- main.c --------
echo extracting file main.c
cat << '#*\\\THE_END//////*#' > main.c
#include <stdio.h>
#include <ctype.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include "viewgif.h"
#include "sunvgif.h"

void main(argc, argv)

int
	argc;
char
	*argv[];

{
	extern int
		optinf,
		opterr;
	int i;
	bool
		used_stdin = FALSE;
	opterr = 1;
	scale = 2;
	progname=argv[0];

	argc--;
	argv++;
	if (argv[0][0]=='-')
		if (argv[0][1] >='1' && argv[0][1]<='4') {
			scale=argv[0][1]-'0';
			argc--;
			argv++;
		}
	for (i=0; i<argc; i++) {
		if (strcmp(argv[i],"-") == 0) {
			if (used_stdin) {
				fprintf(stderr,"standard input used twice\n");
				exit(1);
			}
			else {
				used_stdin=TRUE;
			}
		}
#ifdef unix
		else if (access(argv[i],4) == -1) {
			fprintf(stderr, "%s: cannot access %s: ",progname, argv[i]);
			perror("");
			exit(1);
		}
#endif unix
	}

	infile=stdin;
	filename="stdin";
	i=0;
	do {
		if (argc > 0) {
			infile = fopen(argv[i],"r");
			filename=argv[i];
		}
		do_prog();
		(void) fclose(infile);
	} while (++i < argc);
	exit(0);
}


void draw_loop()
{
	int quit = FALSE;
	char ch;
	do {
		ch = getc(infile);
		switch (ch) {
			case '\0':  break;  /* this kludge for non-standard files */
			case ',':   readimage();
						break;
			case ';':   quit = TRUE;
						(void) notify_set_itimer_func(frame,draw_loop,
						   ITIMER_REAL,((struct itimerval *) 0),
						   ((struct itimerval *) 0));
						break;
			case '!':   readextension();
						break;
			default:	fatal("illegal GIF block type");
						fprintf(stderr,ch);
						break;
		}
	} while (!quit);
}


void do_prog()
{

	checksignature();
	readscreen();
	frame = window_create(NULL,FRAME,0);
	
	window_set(frame,WIN_HEIGHT,scale*screenheight+28,WIN_WIDTH,scale*screenwidth+14,0);
	canvas = window_create(frame,CANVAS,CANVAS_AUTO_SHRINK,FALSE,
		CANVAS_WIDTH,screenwidth, CANVAS_HEIGHT,screenheight,
		WIN_VERTICAL_SCROLLBAR,scrollbar_create(0),
		WIN_HORIZONTAL_SCROLLBAR,scrollbar_create(0),0);
	pw = canvas_pixwin(canvas);
	(void) notify_set_itimer_func(frame,draw_loop,ITIMER_REAL,&NOTIFY_POLLING_ITIMER,
		((struct itimerval *) 0));
	window_main_loop(frame);
}


#*\\\THE_END//////*#
# -------- raster.c --------
echo extracting file raster.c
cat << '#*\\\THE_END//////*#' > raster.c
#include <stdio.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include "viewgif.h"
#include "sunvgif.h"

void outcode(p)
register codetype
	*p;

{
	int	x, y;
	if (p->prefix) 
		outcode(p->prefix);
	for (y=0; y < scale; y++) {
		for (x=0; x < scale; x++) {
			if (interleaved)
				pw_put(pw, (left + xx) * scale + x,(interleavetable[yy] + top)
					* scale + y, p->suffix);
			else 
				pw_put(pw, (left + xx) * scale + x,(yy + top) * scale + y, p->suffix);
		}
	}
	if (++xx > width-1) {
		xx=0;
		yy++;
		pw_show(pw);
	}
}

void process(code)
register
	code;

{
	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]);
		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);
		if ((avail & codemask) == 0 && avail < 4096) { 
			codesize++; 
			codemask += avail; 
		}
		oldcode = code;
	} else {
		fatal("illegal code in raster data");
	}
}

		


void readraster(width, height)
unsigned int 
	width,
	height;
{
	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);
			}
		}
	}
exitloop:
	free(codetable);
}


/* Read image information (position, size, local color map, etc.) and convert
   to postscript. */

void readimage()
{
	unsigned char 
		buf[9];
	
	bool 
		local;
	
	char 
		localmap[256][3];
	
	int localbits;
	
	register 
		row;
	
	register i;

	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);
	local = buf[8] & 0x80;
	interleaved = buf[8] & 0x40;
	if (local) {
		localbits = (buf[8] & 0x7) + 1;
		fread(localmap, 3, 1<<localbits, infile);
		initcolors(colortable, localmap, 1<<localbits);
	} else if (global) {
		initcolors(colortable, globalmap, 1<<globalbits);
	} else {
		fatal("no colormap present for image");
	}
	if (interleaved) {
		interleavetable = (int*) malloc(height * sizeof(int));
		if (!interleavetable) 
			fatal("not enough memory for interleave table");
		row = 0;
		for (i = 0; i < height; i += 8) 
			interleavetable[row++] = i;
		for (i = 4; i < height; i += 8) 
			interleavetable[row++] = i;
		for (i = 2; i < height; i += 4) 
			interleavetable[row++] = i;
		for (i = 1; i < height; i += 2) 
			interleavetable[row++] = i;
	} 
	pw_batch_on(pw);
	readraster(width, height);
	pw_batch_off(pw);
}

/* 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);
}
#*\\\THE_END//////*#
# -------- sunvgif.h --------
echo extracting file sunvgif.h
cat << '#*\\\THE_END//////*#' > sunvgif.h
Frame frame;
Canvas canvas;
Pixwin *pw;
#*\\\THE_END//////*#
# -------- viewgif.h --------
echo extracting file viewgif.h
cat << '#*\\\THE_END//////*#' > viewgif.h
#define TIMER_NULL ((struct itimerval *) 0)
#define TRUE 1
#define FALSE 0

typedef int bool;
typedef struct codestruct {
			struct codestruct *prefix;
			unsigned char first,suffix;
		} codetype;

char *malloc();
int strncmp();
FILE *infile, *fopen();
void main(),
	usage(),
	fatal(),
	checksignature(),
	readscreen(),
	initcolors(),
	outcode(),
	process(),
	readraster(),
	readimage(),
	readextension(),
	draw_loop(),
	do_prog();

int scale,
	datasize, codesize, codemask,
	clear, eoi,
	*interleavetable,
	globalbits;

unsigned int 
	screenwidth,
	screenheight,
	xx,yy,
	left,width,
	top,height;

bool
	global,
	interleaved;

char
	colortable[256][3],
	*progname,
	*filename;

unsigned char
	red[256], green[256], blue[256],
	globalmap[256][3];

codetype
	*codetable;


#*\\\THE_END//////*#
echo Done with extraction
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
 Paul Nakada '89  #8-)                          nakada@husc4.harvard.edu
 Harvard College                                     nakada@husc4.bitnet
 Cambridge, MA       {ihnp4!think, seismo, rutgers}!harvard!husc4!nakada
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_