phillips@grads.cs.ubc.ca (George Phillips) (09/02/89)
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@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@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@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@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@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
bobf@BLUMIRIS.CHEM.UMR.EDU ("Robert B. Funchess") (05/05/90)
As stated before, one is available for anonymous FTP from here. The address,however, has been changed: clciris.chem.umr.edu (131.151.14.48). -- Bob Funchess bobf@blumiris.chem.umr.edu Chemistry Dept. University of Missouri - Rolla