/** ** $Header: /roq/libim/imgiflzw.c 1 11/02/99 4:38p Zaphod $ ** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC) ** a division of General Atomics, San Diego, California, USA ** ** Users and possessors of this source code are hereby granted a ** nonexclusive, royalty-free copyright and design patent license to ** use this code in individual software. License is not granted for ** commercial resale, in whole or in part, without prior written ** permission from SDSC. This source is provided "AS IS" without express ** or implied warranty of any kind. ** ** For further information contact: ** E-Mail: info@sds.sdsc.edu ** ** Surface Mail: Information Center ** San Diego Supercomputer Center ** P.O. Box 85608 ** San Diego, CA 92138-5608 ** (619) 534-5000 **/ #define HEADER " $Header: /roq/libim/imgiflzw.c 1 11/02/99 4:38p Zaphod $" /** ** FILE ** imgiflzw.c - Do Lempel-Ziv & Welch uncompress/compress ** ** PROJECT ** libim - SDSC image manipulation library ** ** DESCRIPTION ** imlzw.c contains rountines for decoding and encoding bytes ** using Lempel-Ziv & Welch uncompress/compress algorithm. ** ** PUBLIC CONTENTS ** d =defined constant ** f =function ** m =defined macro ** t =typedef/struct/union ** v =variable ** ? =other ** ** imLzwCompGif f ** ** PRIVATE CONTENTS ** ** imLzwGetCode f ** imLzwError f ** imLzwGifNextPixel f ** imLzwPackBits f ** ** struct str_table_node t ** struct str_table_node t ** strTableNode t ** strTableNodePtr t ** strTable t ** ** ** IMMAX_LWZ_BITS d maximum number of bits allowed by LWZ ** IMMAXIMUMCODE d maximum code size ** IMBLOCKSIZE d maximum block byte count plus one ** IMNULLPREFIX d null prefix ** ** ImGifEasyFail m non fatal error ocurred. report the error. ** ** CODE CREDITS ** David Koblas, 1990. ** Custom development, Soraya Gonzales, Intevep S.A., Venzuela, 1991. ** Extensions, Vinh Le, San Diego Supercomputer Center, 1992. ** Extensions, Dave Nadeau, San Diego Supercomputer Center, 1993. ** ** ** HISTORY ** $Log: /roq/libim/imgiflzw.c $ * * 1 11/02/99 4:38p Zaphod ** Revision 1.11 1995/06/29 00:28:04 bduggan ** updated copyright year ** ** Revision 1.10 1995/06/16 08:43:52 bduggan ** cleaned up code formatting ** ** Revision 1.9 1995/01/10 23:25:55 bduggan ** Updated copyright notice ** ** Revision 1.8 1994/10/03 11:29:39 nadeau ** Updated to ANSI C and C++ compatibility. ** Removed all use of register keyword. ** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char) ** Changed all float arguments to double. ** Added forward declarations. ** Added misc. casts to passify SGI and DEC compilers. ** Changed all macros and defined constants to have names ** starting with IM. ** Updated comments. ** Updated indenting on some code. ** Updated copyright message. ** ** Revision 1.7 92/08/31 17:24:09 vle ** Updated copyright notice. ** ** Revision 1.6 91/10/03 09:03:23 nadeau ** Fixed #includes. ** ** Revision 1.5 91/03/21 08:51:38 nadeau ** ifdef-ed out inclusion of strings.h. Nothing seems ** to need it and it confuses the compiler on SysV vs. ** BSD machines (string.h vs. strings.h). ** ** Revision 1.4 91/03/13 17:11:53 soraya ** *** empty log message *** ** ** Revision 1.3 91/03/11 09:19:07 soraya ** Optimization and comment cleanup. ** ** Revision 1.2 91/01/31 08:34:42 soraya ** Adding comments ** ** ** **/ #if 0 The lines between the dashes are taken directly from the file jrdgif.c: ----------------------------------------------------------------------------- /* * jrdgif.c * * Copyright (C) 1991, 1992, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains routines to read input images in GIF format. * * These routines may need modification for non-Unix environments or * specialized applications. As they stand, they assume input from * an ordinary stdio stream. They further assume that reading begins * at the start of the file; input_init may need work if the * user interface has already read some data (e.g., to determine that * the file is indeed GIF format). * * These routines are invoked via the methods get_input_row * and input_init/term. */ /* * This code is loosely based on giftoppm from the PBMPLUS distribution * of Feb. 1991. That file contains the following copyright notice: * +-------------------------------------------------------------------+ * | Copyright 1990, David Koblas. | * | Permission to use, copy, modify, and distribute this software | * | and its documentation for any purpose and without fee is hereby | * | granted, provided that the above copyright notice appear in all | * | copies and that both that copyright notice and this permission | * | notice appear in supporting documentation. This software is | * | provided "as is" without express or implied warranty. | * +-------------------------------------------------------------------+ * * We are also required to state that * "The Graphics Interchange Format(c) is the Copyright property of * CompuServe Incorporated. GIF(sm) is a Service Mark property of * CompuServe Incorporated." */ ----------------------------------------------------------------------------- #endif /* * imLzwGetCode * imLzwReadByte * * Gif Image decompression - from LZW to Gif * Written by David Koblas. * Copyright 1989 * Modified by Soraya Gonzalez * San Diego Supercomputer Center * to include it in the image library * ================================================================== * imLzwError * imLzwGifNextPixel * imLzwPackBits * imLzwCompGif * * * GIF Image compression - LZW algorithm implemented with Trie type * structure. * Written by Bailey Brown, Jr. * last change May 24, 1990 * Modified by Soraya Gonzalez. * San Diego Supercomputer Center. * December 1990 * to include it in the image library * * */ #ifdef USE_STDLIB_H #include #else #ifdef old #ifdef USE_STRING_H #include #else #include #endif #endif #endif /* USE_STDLIB_H */ #include "iminternal.h" /* * TYPEDEF & STRUCTURE * struct str_table_node * struct str_table_node * strTableNode * strTableNodePtr * strTable * DESCRIPTION * */ typedef struct str_table_entry { int code; int prefix; int suffix; } strTableEntry; typedef struct str_table_node { strTableEntry entry; struct str_table_node *left; struct str_table_node *right; struct str_table_node *children; } strTableNode, *strTableNodePtr, **strTable; /* * CONSTANTS * * IMMAX_LWZ_BITS - maximum number of bits allowed by LWZ * IMMAXIMUMCODE - maximum code size * IMBLOCKSIZE - maximum block byte count plus one * IMNULLPREFIX - null prefix */ #define IMMAX_LWZ_BITS 12 #define IMMAXIMUMCODE 4095 /* 2**maximum_code_size */ #define IMBLOCKSIZE 256 /* max block byte count + 1 */ #define IMNULLPREFIX -1 /* * MACROS * ImGifEasyFail - non fatal error occurred. report the error. */ #define ImGifEasyFail(str,status) \ { \ ImErrorWarning(str,status,IMEUNKNOWN); \ return(status); \ } /* * FILE-WIDE VARIABLE */ static int RasterIndex; /* index over the rasterdata array */ /* * FUNCTION * imLzwGetCode - return the next code from the input stream. * * DESCRIPTION * return the next code from the input stream. The code read * has code_size size. flag is used to initialize * the internal variables. */ static int #ifdef __STDC__ imLzwGetCode(int ioType, int fd, FILE *fp, int code_size, int flag) #else imLzwGetCode(ioType, fd, fp, code_size, flag) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ int code_size; /* current code size used */ int flag; /* used for to initializations */ #endif { static unsigned char buf[280]; static int curbit,lastbit,done,last_byte; int i, j, ret; unsigned char count; if (flag) { curbit = 0; lastbit = 0; done = FALSE; return 0; } if ( (curbit+code_size) >= lastbit) { if (done) if (curbit>=lastbit) ImGifEasyFail("Ran off the end of my bits",-1); buf[0] = buf[last_byte-2]; buf[1] = buf[last_byte-1]; if ( ImBinRead( ioType,fd,fp,&count, UCHAR, 1, 1 ) == -1 ) ImReturnBinError( ); if (count == 0) done = TRUE; else if ( ImBinRead( ioType,fd,fp,&buf[2],UCHAR,1,count ) == -1 ) ImReturnBinError( ); last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2+count)*8 ; } ret = 0; for( i = curbit, j = 0; j < code_size; i++, j++ ) ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } /* * FUNCTION * ImLzwReadByte - return the next decoded pixel * * DESCRIPTION * Return the next decoded pixel value. */ int #ifdef __STDC__ imLzwReadByte(int ioType,int fd,FILE *fp,int flag,int input_code_size) #else imLzwReadByte(ioType,fd,fp,flag,input_code_size) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ int flag; /* to make intializations*/ int input_code_size;/* code size */ #endif { static int fresh=FALSE; int code,incode; unsigned char count,junk; static int code_size,set_code_size; static int max_code,max_code_size; static int firstcode,oldcode; static int clear_code,end_code; static int table[2][(1<< IMMAX_LWZ_BITS)]; static int stack[(1<<(IMMAX_LWZ_BITS))*2],*sp; int i; if (flag) { set_code_size = input_code_size; code_size = set_code_size+1; clear_code = 1 << set_code_size ; end_code = clear_code + 1; max_code_size = 2*clear_code; max_code = clear_code+2; imLzwGetCode(ioType,fd,fp,NULL,TRUE); fresh=TRUE; for (i=0;i stack) return *--sp; while ((code=imLzwGetCode(ioType,fd,fp,code_size,FALSE))>=0) { if (code == clear_code) { for (i=0;i0 && ImBinRead( ioType,fd,fp,&junk,UCHAR,1,1) != -1); if (count!=0) ImGifEasyFail("Missing EOD in data stream (common occurance)",-1); return -1; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) ImGifEasyFail("Circular table entry BIG ERROR",-1); code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code=max_code)<(1<= max_code_size) && (max_code_size < (1< stack) return *--sp; } return code; } /* * FUNCTION * ImLzwError - prints the error ocurred in the standar error file * and return with status equal to -1 */ static int #ifdef __STDC__ imLzwError(char *s) #else imLzwError(s) char *s; #endif { ImErrorFatal(s, -1, IMEUNKNOWN); } /* * FUNCTION * ImLzwGifNextPixel - Return the next pixel from the raster data * * DESCRIPTION * The pixel values are stored in the rasterdata buffer. This * function returns the next pixel value. */ static int #ifdef __STDC__ imLzwGifNextPixel(unsigned char *rasterdata,int size) #else imLzwGifNextPixel( rasterdata,size) unsigned char *rasterdata; int size; #endif { if ( RasterIndex == size ) return (EOF); return( rasterdata[RasterIndex++] ); } /* * FUNCTION * imLzwPackBits - packs the bits of the codes generated * by imLzwCompGif. * DESCRIPTION * imLzwPackBits() packs the bits of the codes generated by ImLzwCompGif * into a 1..256 byte output block. The first byte of the block is the * number 0..255 of data bytes in the block. To flush or initialize * the block, pass a negative argument. */ static int #ifdef __STDC__ imLzwPackBits(int compress_size, int prefix, int ioType, int fd, FILE *fp) #else imLzwPackBits(compress_size, prefix, ioType, fd, fp) int compress_size; int prefix; int ioType; int fd; FILE *fp; #endif { static int cur_bit = 8; static unsigned char block[IMBLOCKSIZE] = { 0 }; int i, left_over_bits; /* if we are about to excede the bounds of block or if the flush code (code_bis < 0) we output the block */ if((cur_bit + compress_size > (IMBLOCKSIZE-1)*8) || (prefix < 0)) { /* handle case of data overlapping blocks */ if ((left_over_bits = (((cur_bit>>3) + ((cur_bit & 7) != 0))<<3) - cur_bit) != 0) { for (i=0; i < left_over_bits; i++) { if (prefix & (1<>3] |= (char)(1<<(cur_bit & 7)); /* note n>>3 == n/8 and n & 7 == n % 8 */ cur_bit++; } } compress_size -= left_over_bits; prefix = prefix>>left_over_bits; block[0] = (unsigned char)((cur_bit>>3) - 1); if (block[0]) if ( ImBinWrite( ioType, fd, fp, block, UCHAR, 1, block[0]+1) == -1) ImReturnBinError(); for(i=0; i < IMBLOCKSIZE; i++) block[i] = 0; cur_bit = 8; } if (prefix >= 0) { for (i=0; i < compress_size; i++) { if (prefix & (1<>3] |= (unsigned char)(1<<(cur_bit & 7)); /* note n>>3 == n/8 and n & 7 == n % 8 */ cur_bit++; } } return (1); } /* * FUNCTION * ImLzwCompGif - compresses and pack the pixels values that are * stored in rasterdata buffer using the * LZW algorithm. * DESCRIPTION * ImLzwCompGif () recieves pointers to a buffer and an output * stream, and the code size as parameters and outputs successive * blocks of LZW compressed gif data. The calling routine should * have aready written the GIF file header out to the output file. * It assumes that there will be no more than 8 bits/pixel and that * each data item comes from successive bytes returned by * ImLzwGifNextPixel(). */ int #ifdef __STDC__ imLzwCompGif(int ioType,int fd,FILE *fp,int code_size, unsigned char *rasterdata, int size) #else imLzwCompGif(ioType,fd,fp,code_size, rasterdata, size) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ int code_size; /* i.e. for 8 bits/pixel code_size = 9; */ unsigned char *rasterdata; /* rasterdata to be compress */ int size; /* size of the raster data */ #endif { strTable heap; /* our very own memory manager */ int heap_index; int clear_code, end_code, cur_code; int i, found, num_colors, prefix, compress_size; int cur_char, end_of_data, bits_per_pix; strTableNodePtr cur_node; strTable root; /* root of string table for LZW compression */ /* is an array of 2**bits_per_pix pointers to atomic nodes */ heap_index = 0; heap = (strTable)malloc(sizeof(strTableNodePtr)*IMMAXIMUMCODE); if (heap == NULL) imLzwError("can't allocate heap"); for (i=0; i < IMMAXIMUMCODE; i++) { heap[i] = (strTableNodePtr)malloc(sizeof(strTableNode)); if (heap[i] == NULL) imLzwError("can't allocate heap"); } bits_per_pix = code_size - 1; compress_size = code_size; num_colors = 1<<(bits_per_pix); clear_code = num_colors; end_code = clear_code + 1; cur_code = end_code + 1; RasterIndex = 0; prefix = IMNULLPREFIX; root = (strTable)malloc(sizeof(strTableNodePtr)*num_colors); if (!root) imLzwError("memory allocation failure (root)"); for(i=0; ientry.code = i; root[i]->entry.prefix = IMNULLPREFIX; root[i]->entry.suffix = i; root[i]->left = NULL; root[i]->right = NULL; root[i]->children = NULL; } /* initialize output block */ imLzwPackBits(compress_size, -1, ioType,fd,fp); imLzwPackBits(compress_size, clear_code, ioType,fd,fp); end_of_data = 0; if ((cur_char = imLzwGifNextPixel(rasterdata,size)) == EOF) imLzwError("premature end of data"); while (!end_of_data) { prefix = cur_char; cur_node = root[prefix]; found = 1; if ((cur_char = imLzwGifNextPixel(rasterdata,size)) == EOF) { end_of_data = 1; break; } while(cur_node->children && found) { cur_node = cur_node->children; while(cur_node->entry.suffix != cur_char) { if (cur_char < cur_node->entry.suffix) { if (cur_node->left) cur_node = cur_node->left; else { cur_node->left = heap[heap_index++]; cur_node = cur_node->left; found = 0; break; } } else { if (cur_node->right) cur_node = cur_node->right; else { cur_node->right = heap[heap_index++]; cur_node = cur_node->right; found = 0; break; } } } if (found) { prefix = cur_node->entry.code; if((cur_char = imLzwGifNextPixel(rasterdata,size)) == EOF) { end_of_data = 1; break; } } } if (end_of_data) break; if (found) { cur_node->children = heap[heap_index++]; cur_node = cur_node->children; } cur_node->children = NULL; cur_node->left = NULL; cur_node->right = NULL; cur_node->entry.code = cur_code; cur_node->entry.prefix = prefix; cur_node->entry.suffix = cur_char; imLzwPackBits(compress_size, prefix, ioType,fd,fp); if (cur_code > ((1<<(compress_size))-1)) compress_size++; if (cur_code < IMMAXIMUMCODE) { cur_code++; } else { heap_index = num_colors; /* reinitialize string table */ for (i=0; i < num_colors; i++ ) root[i]->children = NULL; imLzwPackBits(compress_size, clear_code, ioType,fd,fp); compress_size = bits_per_pix + 1; cur_code = end_code + 1; } } imLzwPackBits(compress_size, prefix, ioType,fd,fp); imLzwPackBits(compress_size, end_code, ioType,fd,fp); imLzwPackBits(compress_size, -1, ioType,fd,fp); for (i=0; i < IMMAXIMUMCODE; i++) free(heap[i]); free(heap); free(root); return (1); }