phillips@cs.ubc.ca (George Phillips) (09/07/90)
And here's part 2 ... #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # decoder.c # newsmap.c # floydstein.c # errs.h # std.h # mem_image.h # newsmap.h # imgfile.h # This archive created: Thu Sep 6 22:51:24 1990 export PATH; PATH=/bin:$PATH echo shar: extracting "'decoder.c'" '(11341 characters)' if test -f 'decoder.c' then echo shar: will not over-write existing file "'decoder.c'" else sed 's/^X//' << \SHAR_EOF > 'decoder.c' 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: I've hacked this around to make a somewhat cleaner interface... X */ X X#include <stdio.h> X X#include "std.h" X#include "errs.h" X X#include "mem_image.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 */ Xextern char* 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#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(fp) XFILE* fp; 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 if ((navail_bytes = fgetc(fp)) == EOF) X return(READ_ERROR); X else if (navail_bytes) X { X if (fread(byte_buff, navail_bytes, 1, fp) != 1) X return(READ_ERROR); 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 if ((navail_bytes = fgetc(fp)) == EOF) X return(READ_ERROR); X else if (navail_bytes) X { X if (fread(byte_buff, navail_bytes, 1, fp) != 1) X return(READ_ERROR); 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(fp, img) XFILE* fp; Xstruct mem_image* img; X { X FAST UTINY *sp, *bufptr; X FAST WORD code, fc, oc, bufcnt; X WORD c, size, ret; X X /* Initialize for decoding a new image... X */ X if ((size = fgetc(fp)) == EOF) X return(READ_ERROR); 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 /* Set up the stack pointer and decode buffer pointer X */ X sp = stack; X bufptr = img->data; X bufcnt = img->width; 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(fp)) != ending) X { X X /* If we had a file error, return without completing the decode X */ X if (c < 0) { 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(fp)) == 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 bufptr = out_line(img); X bufcnt = img->width; 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 bufptr = out_line(img); X bufcnt = img->width; X } X } X } X } X ret = 0; X if (bufcnt != img->width) X out_line(img); /* buf, (linewidth - bufcnt));*/ X return(ret); X } X SHAR_EOF fi # end of overwriting check echo shar: extracting "'newsmap.c'" '(2217 characters)' if test -f 'newsmap.c' then echo shar: will not over-write existing file "'newsmap.c'" else sed 's/^X//' << \SHAR_EOF > 'newsmap.c' X/* X * newsmap.c -- convert an RGB triplet into a nearby value from the X * NeWS 8 plane colourmap. X * X * Note: I could hard code the inverse tables, but this is not so X * inscrutable in case it should be changed. Besides, the true X * colour mode could use this information in fitting the colour X * collisions to a next-best choice. X */ X X#include "newsmap.h" X X#define gray_base (32) Xshort gray_level[] = { X 0, 10, 20, 30, 40, 51, 61, 71, 81, 91, 102, 112, 122, 132, X 142, 153, 163, 173, 183, 193, 204, 214, 224, 234, 244, 255 X}; X#define gray_run (sizeof(gray_level) / sizeof(short)) X#define gray_black (56) X#define gray_white (255) X X#define colourbase (56) Xshort red_level[] = { 0, 63, 127, 191, 255 }; Xshort green_level[] = { 0, 36, 72, 109, 145, 182, 218, 255 }; Xshort blue_level[] = { 0, 63, 127, 191, 255 }; X X#define nreds (sizeof(red_level) / sizeof(short)) X#define ngreens (sizeof(green_level) / sizeof(short)) X#define nblues (sizeof(blue_level) / sizeof(short)) X Xshort gray_inverse[256]; Xshort red_inverse[256]; Xshort green_inverse[256]; Xshort blue_inverse[256]; X Xstatic void run_ramp(); X Xvoid init_newsmap() X{ X int i; X X run_ramp(gray_run, gray_level, gray_inverse); X for (i = 0; i < 256; i++) { X if (gray_inverse[i] == 0) X gray_inverse[i] = gray_black; X else if (gray_inverse[i] == gray_run - 1) X gray_inverse[i] = gray_white; X else X gray_inverse[i] += gray_base - 1; X } X X run_ramp(ngreens, green_level, green_inverse); X run_ramp(nreds, red_level, red_inverse); X for (i = 0; i < 256; i++) X red_inverse[i] *= ngreens; X X run_ramp(nblues, blue_level, blue_inverse); X for (i = 0; i < 256; i++) X blue_inverse[i] *= ngreens * nreds; X} X Xstatic void run_ramp(n, level, inverse) Xint n; Xshort level[]; Xshort inverse[]; X{ X int i; X int closest = 0; X X for (i = 0; i < 256; i++) { X if (abs(i - level[closest]) > abs(i - level[closest + 1])) X closest++; X inverse[i] = closest; X if (closest == n - 1) X break; X } X for (; i < 256; i++) X inverse[i] = closest; X} X Xstatic int abs(n) Xint n; X{ X if (n < 0) X return(-n); X return(n); X} X Xint rgb2newsmap(r, g, b) Xint r; Xint g; Xint b; X{ X if (r == g && g == b) X return(gray_inverse[r]); X X return(red_inverse[r] + green_inverse[g] + blue_inverse[b] + colourbase); X} SHAR_EOF fi # end of overwriting check echo shar: extracting "'floydstein.c'" '(5035 characters)' if test -f 'floydstein.c' then echo shar: will not over-write existing file "'floydstein.c'" else sed 's/^X//' << \SHAR_EOF > 'floydstein.c' X/* X * floydstein.c -- perform Floyd-Steinberg dithering on an in-memory image. X * X * This is designed around the NeWS colour map and is for colour mapped X * images. Beware. X * X * This code is based on ppmquant from Jef Poskanzer's PBM+ package which is X * X * Copyright (C) 1989 by Jef Poskanzer. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation. This software is provided "as is" without express or X * implied warranty. X*/ X X#include <stdio.h> X#include <malloc.h> X X#include "mem_image.h" X#include "newsmap.h" X Xlong* long_alloc(); X Xunsigned char red[256], green[256], blue[256]; Xunsigned short news_red[256]; Xunsigned short news_green[256]; Xunsigned short news_blue[256]; Xlong *thisrerr, *nextrerr, *thisgerr, *nextgerr, *thisberr, *nextberr; Xint fs_direction; X Xvoid init_floydstein(img) Xstruct mem_image* img; X{ X register int col; X#define FS_SCALE 1024 X int i; X X /* Build a local colour map for convenience */ X for (i = 0; i < img->maplen; i++) { X red[i] = img->colourmap[i] & 255; X green[i] = (img->colourmap[i] >> 8) & 255; X blue[i] = (img->colourmap[i] >> 16) & 255; X } X X for (i = 0; i < 256; i++) X getmcolor(i, news_red + i, news_green + i, news_blue + i); X X /* Initialize Floyd-Steinberg error vectors. */ X thisrerr = long_alloc(img->width + 2); X nextrerr = long_alloc(img->width + 2); X thisgerr = long_alloc(img->width + 2); X nextgerr = long_alloc(img->width + 2); X thisberr = long_alloc(img->width + 2); X nextberr = long_alloc(img->width + 2); X X srand((int)time(0)); X X for (col = 0; col < img->width + 2; col++) { X thisrerr[col] = rand() % (FS_SCALE * 2) - FS_SCALE; X thisgerr[col] = rand() % (FS_SCALE * 2) - FS_SCALE; X thisberr[col] = rand() % (FS_SCALE * 2) - FS_SCALE; X /* (random errors in [-1 .. 1]) */ X } X fs_direction = 1; X} X Xvoid floydstein(img, row) Xstruct mem_image* img; Xint row; X{ X register unsigned char* pP; X int rows, cols; X register int col, limitcol; X long* temperr; X register long sr, sg, sb; X int r, g, b; X#define FS_SCALE 1024 X int err; X int i; X X for (col = 0; col < img->width + 2; col++) X nextrerr[col] = nextgerr[col] = nextberr[col] = 0; X X if (fs_direction ) { X col = 0; X limitcol = img->width; X pP = img->data + row * img->width; X } X else { X col = img->width - 1; X limitcol = -1; X pP = img->data + row * img->width + img->width - 1; X } X X do { X /* Use Floyd-Steinberg errors to adjust actual color. */ X sr = red[*pP] * FS_SCALE + thisrerr[col + 1]; X sg = green[*pP] * FS_SCALE + thisgerr[col + 1]; X sb = blue[*pP] * FS_SCALE + thisberr[col + 1]; X r = sr / FS_SCALE; if (r < 0) r = 0; else if (r > 255) r = 255; X g = sg / FS_SCALE; if (g < 0) g = 0; else if (g > 255) g = 255; X b = sb / FS_SCALE; if (b < 0) b = 0; else if (b > 255) b = 255; X /* just for fun, replace the previous 3 lines with these */ X /*r = (sr / FS_SCALE) & 255; X g = (sg / FS_SCALE) & 255; X b = (sb / FS_SCALE) & 255;*/ X *pP = rgb2newsmap(r, g, b); X X if (fs_direction) { X err = sr - news_red[*pP] * FS_SCALE; X thisrerr[col + 2] += ( err * 7 ) / 16; X nextrerr[col ] += ( err * 3 ) / 16; X nextrerr[col + 1] += ( err * 5 ) / 16; X nextrerr[col + 2] += ( err ) / 16; X err = sg - news_green[*pP] * FS_SCALE; X thisgerr[col + 2] += ( err * 7 ) / 16; X nextgerr[col ] += ( err * 3 ) / 16; X nextgerr[col + 1] += ( err * 5 ) / 16; X nextgerr[col + 2] += ( err ) / 16; X err = sb - news_blue[*pP] * FS_SCALE; X thisberr[col + 2] += ( err * 7 ) / 16; X nextberr[col ] += ( err * 3 ) / 16; X nextberr[col + 1] += ( err * 5 ) / 16; X nextberr[col + 2] += ( err ) / 16; X } X else { X err = sr - news_red[*pP] * FS_SCALE; X thisrerr[col ] += ( err * 7 ) / 16; X nextrerr[col + 2] += ( err * 3 ) / 16; X nextrerr[col + 1] += ( err * 5 ) / 16; X nextrerr[col ] += ( err ) / 16; X err = sg - news_green[*pP] * FS_SCALE; X thisgerr[col ] += ( err * 7 ) / 16; X nextgerr[col + 2] += ( err * 3 ) / 16; X nextgerr[col + 1] += ( err * 5 ) / 16; X nextgerr[col ] += ( err ) / 16; X err = sb - news_blue[*pP] * FS_SCALE; X thisberr[col ] += ( err * 7 ) / 16; X nextberr[col + 2] += ( err * 3 ) / 16; X nextberr[col + 1] += ( err * 5 ) / 16; X nextberr[col ] += ( err ) / 16; X } X if (fs_direction) { X col++; X pP++; X } X else { X col--; X pP--; X } X } while (col != limitcol); X X temperr = thisrerr; X thisrerr = nextrerr; X nextrerr = temperr; X temperr = thisgerr; X thisgerr = nextgerr; X nextgerr = temperr; X temperr = thisberr; X thisberr = nextberr; X nextberr = temperr; X fs_direction = !fs_direction; X} X Xclean_floyd() X{ X free(thisrerr); X free(nextrerr); X free(thisgerr); X free(nextgerr); X free(thisberr); X free(nextberr); X} X Xlong* long_alloc(n) Xint n; X{ X long* l; X X l = (long*)malloc(n * sizeof(long)); X X if (l == NULL) X no_mem(); X X return(l); X} SHAR_EOF fi # end of overwriting check echo shar: extracting "'errs.h'" '(366 characters)' if test -f 'errs.h' then echo shar: will not over-write existing file "'errs.h'" else sed 's/^X//' << \SHAR_EOF > 'errs.h' 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 SHAR_EOF fi # end of overwriting check echo shar: extracting "'std.h'" '(278 characters)' if test -f 'std.h' then echo shar: will not over-write existing file "'std.h'" else sed 's/^X//' << \SHAR_EOF > 'std.h' 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 SHAR_EOF fi # end of overwriting check echo shar: extracting "'mem_image.h'" '(282 characters)' if test -f 'mem_image.h' then echo shar: will not over-write existing file "'mem_image.h'" else sed 's/^X//' << \SHAR_EOF > 'mem_image.h' X/* X * mem_image.h X */ X Xstruct mem_image { X int* colourmap; X int* mapmap; X int maplen; X char* data; X int width; X int height; X int depth; X struct imgfile* imf; X struct mem_image* next; X X /* extras */ X int gif_interlaced; X int x_off; X int y_off; X int background; X int seq; X}; SHAR_EOF fi # end of overwriting check echo shar: extracting "'newsmap.h'" '(75 characters)' if test -f 'newsmap.h' then echo shar: will not over-write existing file "'newsmap.h'" else sed 's/^X//' << \SHAR_EOF > 'newsmap.h' X/* X * newsmap.h X */ X Xextern void init_newsmap(); Xextern int rgb2newsmap(); SHAR_EOF fi # end of overwriting check echo shar: extracting "'imgfile.h'" '(164 characters)' if test -f 'imgfile.h' then echo shar: will not over-write existing file "'imgfile.h'" else sed 's/^X//' << \SHAR_EOF > 'imgfile.h' X/* X * imgfile.h X */ X Xstruct imgfile { X char* filename; X char* name; X FILE* stream; X int width; X int height; X struct mem_image* imglist; X struct imgfile* next; X}; SHAR_EOF fi # end of overwriting check # End of shell archive exit 0