home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************/
- /* LZWDecode.c - source code for LZW decoding of GIF files */
- /* Used in ViewGif2 Application */
- /* This is not very elegant code, but it allows the decoding to be broken */
- /* up into arbitrary pieces, thus being nice to system resources */
- /* January 1990 Carl F. Sutter */
- /***************************************************************************/
-
- #include <stdio.h>
- #include <streams/streams.h>
-
- /* some global data types and constants */
- #define BYTE unsigned char
- #define WORD unsigned short
- #define DWORD unsigned long
- #define BOOL int
- #define TRUE 1
- #define FALSE 0
- #define MAXCODES 4096
-
- /* LZW variables */
- WORD wCodeClear;
- WORD wCodeEOI;
- WORD wCodeLength;
- WORD wTablePointer;
- WORD wCurrentTablePointerMax;
-
- /* LZW stack implementation */
- BYTE byStack[MAXCODES];
- WORD wStackPointer;
- WORD wFirstCode[MAXCODES];
- WORD wSecondCode[MAXCODES];
-
- BYTE byCodeSize;
- long lNumPixelsDecoded;
-
- /* functions in this code */
- void StartLZW( BYTE byCodeSizeIn, NXStream *stream,
- BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
- int width, int height, BOOL bInter );
- long ContinueLZW( int nNumCodes );
- void InitializeLZWTable( void );
- BOOL ReadNextCode( BOOL bInitialize, WORD *wCode );
- BOOL FillStack( WORD wCode );
- BOOL AddToTable( WORD wFirst, WORD wSecond );
- WORD FirstCode( WORD wCode );
- BOOL IsInTable( WORD wCode, BOOL *bResult );
- BOOL ReadNextDataByte( NXStream *stream, BYTE *byReturn );
- BOOL WriteStack( BYTE byStack[], WORD *wPointer,
- BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
- int width, int height, BOOL bInter );
-
-
- /***************************************************************************/
- /* StartLZW - handle all initialization of the LZW dedcoder */
- /***************************************************************************/
- void StartLZW( BYTE byCodeSizeIn, NXStream *stream,
- BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
- int width, int height, BOOL bInter )
- {
- /* save input parameters */
- byCodeSize = byCodeSizeIn;
-
- /* set the constant clear and EOI codes, and the pixel count */
- wCodeClear = 1;
- wCodeClear <<= byCodeSize; /* Clear Code = 2^CodeSize */
- wCodeEOI = wCodeClear + 1;
- lNumPixelsDecoded = 0;
-
- /* initialize the following functions */
- ReadNextCode( TRUE, NULL );
- ReadNextDataByte( stream, NULL );
- WriteStack( NULL, NULL, byR, byG, byB, byMap, width, height, bInter );
-
- /* set the LZW values in case the first code is not a clear code */
- InitializeLZWTable();
- } /* StartLZW 1/24/90 CFS */
-
-
- /***************************************************************************/
- /* ContinueLZW - keep decoding the LZW encoded data stream */
- /***************************************************************************/
- long ContinueLZW( int nNumCodes )
- {
- static WORD wCode, wOldCode;
- int nNumCodesRead;
- BOOL bInTable;
-
- nNumCodesRead = 0;
- while ( (nNumCodesRead < nNumCodes) && (ReadNextCode( FALSE, &wCode )) &&
- (wCode != wCodeEOI) )
- {
- nNumCodesRead++;
- if (wCode == wCodeClear)
- {
- InitializeLZWTable();
- if (!ReadNextCode( FALSE, &wCode )) break;
- if (wCode == wCodeEOI) break;
- nNumCodesRead++;
- if (!FillStack( wCode )) break;
- }
- else /* not clear code */
- {
- if (!IsInTable( wCode, &bInTable )) break;
- if (bInTable)
- {
- if (!FillStack( wCode )) break;
- if (!AddToTable( wOldCode, FirstCode( wCode ) )) break;
- }
- else /* code is not in table */
- {
- if (!FillStack( wOldCode )) break;
- if (!FillStack( FirstCode( wOldCode ) )) break;
- if (!AddToTable( wOldCode, FirstCode( wOldCode ) )) break;
- }
- } /* not clear code */
- wOldCode = wCode;
- } /* while loop */
-
- /* return value depends on clean codes up to EOI */
- /* note: even if errors were found, some of the image may be OK */
- if (wCode == wCodeEOI) return( 0 );
- if (nNumCodesRead == nNumCodes) return( lNumPixelsDecoded );
- /* else something went wrong, signal caller to quit */
- return( -1 );
- } /* LZWDecode 10/16/89 CFS */
-
-
- /***************************************************************************/
- /* InitializeLZWTable - init the table and global pointers and counters */
- /***************************************************************************/
- void InitializeLZWTable( void )
- {
- wCodeLength = byCodeSize + 1;
- wCurrentTablePointerMax = 1; /* wCurrentTablePointer = */
- wCurrentTablePointerMax <<= wCodeLength; /* 2^wCodeLength */
- wTablePointer = wCodeEOI + 1;
- } /* InitializeLZWTable 10/5/89 CFS */
-
-
- /***************************************************************************/
- /* ReadNextCode - get the next LZW code from the file */
- /***************************************************************************/
- BOOL ReadNextCode( BOOL bInitialize, WORD *wCode )
- {
- static WORD wMask[] = { 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F,
- 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF };
- static DWORD dwStorage;
- static BYTE byBitsAvail;
- WORD wNextCode;
- BYTE byNextByte;
-
- /* initialize if requested */
- if (bInitialize == TRUE)
- {
- dwStorage = 0;
- byBitsAvail = 0;
- return( TRUE );
- }
-
- /* get enough data in the storage variable to handle the request */
- while ((WORD)byBitsAvail < wCodeLength)
- {
- if (!ReadNextDataByte( NULL, &byNextByte )) return( FALSE );
- dwStorage |= (DWORD)byNextByte << (DWORD)byBitsAvail;
- byBitsAvail += 8;
- }
-
- /* now get the bits for the new code, and shift out the used bits */
- wNextCode = (WORD)(dwStorage & (DWORD)wMask[wCodeLength - 1]);
- dwStorage >>= (DWORD)wCodeLength;
- byBitsAvail -= (BYTE)wCodeLength;
- *wCode = wNextCode;
- return( TRUE );
- } /* ReadNextCode 10/5/89 CFS */
-
-
- /***************************************************************************/
- /* FillStack - start with the given code, and put colors on the stack */
- /***************************************************************************/
- BOOL FillStack( WORD wCode )
- {
- wStackPointer = 0;
-
- /* check first whether the code is just a pixel color */
- if (wCode < wCodeClear)
- byStack[wStackPointer++] = (BYTE)wCode;
-
- /* make sure the code is in a valid range */
- else if ((wCode <= wCodeEOI) || (wCode >= wTablePointer))
- {
- fprintf( stderr,
- "ViewGif LZWDecode error - FillStack code is not a valid table entry.\n" );
- return( FALSE );
- }
-
- /* the code is from the table, trace the codes and collect pixels */
- else
- {
- while (wFirstCode[wCode] > wCodeClear)
- {
- byStack[wStackPointer++] = (BYTE)wSecondCode[wCode];
- wCode = wFirstCode[wCode];
- }
- byStack[wStackPointer++] = (BYTE)wSecondCode[wCode];
- byStack[wStackPointer++] = (BYTE)wFirstCode[wCode];
- }
-
- /* all went well, so pop the stack of pixels into the bitmap buffers */
- return( WriteStack( byStack, &wStackPointer,
- (BYTE *)NULL, (BYTE *)NULL, (BYTE *)NULL, (BYTE *)NULL,
- (int)NULL, (int)NULL, (BOOL)NULL ) );
- } /* FillStack 10/6/89 CFS */
-
-
- /***************************************************************************/
- /* AddToTable - add the code to the tables */
- /***************************************************************************/
- BOOL AddToTable( WORD wFirst, WORD wSecond )
- {
- /* save data at the wTablePointer location */
- wFirstCode[wTablePointer] = wFirst;
- wSecondCode[wTablePointer] = wSecond;
-
- /* increment the table pointer */
- wTablePointer++;
- if (wTablePointer > MAXCODES)
- {
- fprintf( stderr, "ViewGif LZWDecode error - LZW table up to 4095\n" );
- return( FALSE );
- }
-
- /* if the table pointer is about to exceed the code length, up it */
- if (wTablePointer == wCurrentTablePointerMax)
- {
- if (wCodeLength < 12) wCodeLength += 1;
- wCurrentTablePointerMax = 1; /* wCurrentTablePointer = */
- wCurrentTablePointerMax <<= wCodeLength; /* 2^wCodeLength */
- }
-
- return( TRUE );
- } /* AddToTable 10/6/89 CFS */
-
-
- /***************************************************************************/
- /* FirstCode - trace the code back to it's first pixel color */
- /***************************************************************************/
- WORD FirstCode( WORD wCode )
- {
- /* check first whether the code is just a pixel color */
- if (wCode < wCodeClear) return( wCode );
-
- /* if not, trace back the first codes until it is a color */
- while (wFirstCode[wCode] > wCodeClear)
- wCode = wFirstCode[wCode];
- return( wFirstCode[wCode] );
- } /* FirstCode 10/5/89 CFS */
-
-
- /***************************************************************************/
- /* IsInTable - return true if the code is a pixel color, or in the table */
- /***************************************************************************/
- BOOL IsInTable( WORD wCode, BOOL *bResult )
- {
- /* check first whether the code is just a pixel color */
- if (wCode < wCodeClear)
- {
- *bResult = TRUE;
- return( TRUE );
- }
-
- /* make sure the code is not a special one, or bigger than the */
- /* next table entry */
- if ((wCode <= wCodeEOI) || (wCode > wTablePointer))
- {
- fprintf( stderr,
- "ViewGif LZWDecode error - IsInTable code is not a valid table entry.\n" );
- return( FALSE );
- }
-
- /* if the code will be the next table entry, OK, but return false */
- if (wCode == wTablePointer)
- {
- *bResult = FALSE;
- return( TRUE );
- }
-
- /* finally, the code must be already in the table EOI < code < TP */
- *bResult = TRUE;
- return( TRUE );
- } /* IsInTable 10/5/89 CFS */
-
-
- /***************************************************************************/
- /* ReadNextDataByte - get the next image data byte from the file */
- /***************************************************************************/
- BOOL ReadNextDataByte( NXStream *stream, BYTE *byReturn )
- {
- #define MAX_BLOCK_SIZE 255
- static BYTE byBlockSize = 0;
- static BYTE byData[MAX_BLOCK_SIZE];
- static NXStream *fileStream;
- static BYTE byLeft;
- int nError;
-
- /* if the stream is not NULL, initialize this function */
- if (stream != NULL)
- {
- byLeft = 0;
- fileStream = stream;
- return( TRUE );
- }
-
- /* get the next block of data if necessary */
- if (byLeft == 0)
- {
- nError = NXRead( fileStream, &byBlockSize, 1 );
- if (nError <= 0)
- {
- fprintf( stderr,
- "ViewGif2 LZWDecode error - ReadNextDataByte unexpected end of file.\n" );
- return( FALSE );
- }
- byLeft = byBlockSize;
- nError = NXRead( fileStream, byData, byBlockSize );
- if (nError <= 0)
- {
- fprintf( stderr,
- "ViewGif2 LZWDecode error - ReadNextDataByte unexpected end of file.\n" );
- return( FALSE );
- }
- }
- /* return the data byte and decrement the number left */
- *byReturn = byData[byBlockSize - byLeft--];
- return( TRUE );
- } /* ReadNextDataByte 10/16/89 CFS */
-
-
- /***************************************************************************/
- /* WriteStack - pop the pixel stack and color in the pixels */
- /***************************************************************************/
- BOOL WriteStack( BYTE byStack[], WORD *wPointer,
- BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
- int width, int height, BOOL bInter )
- {
- static int nLines[] = { 0, 4, 2, 1 };
- static int nJump[] = { 8, 8, 4, 2 };
- int nColorIndex;
- DWORD dwDataIndex;
-
- static BYTE *byDataR, *byDataG, *byDataB;
- static BYTE *byColorMap;
- static int nWidth, nHeight;
- static BOOL bInterlaced;
- static DWORD dwCurX, dwCurY;
- static int nCurInterlace;
-
- /* initialize the function if the stack is NULL */
- if (byStack == NULL)
- {
- byDataR = byR; byDataG = byG; byDataB = byB;
- byColorMap = byMap;
- nWidth = width; nHeight = height;
- bInterlaced = bInter;
- dwCurX = dwCurY = 0;
- nCurInterlace = 0;
- return( TRUE );
- }
-
- while (*wPointer > 0)
- {
- (*wPointer)--;
- lNumPixelsDecoded++;
-
- /* put the pixel color in the data arrays */
- nColorIndex = (int)byStack[*wPointer] * 3;
- dwDataIndex = dwCurY * (long)nWidth + dwCurX;
- byDataR[dwDataIndex] = byColorMap[ nColorIndex];
- byDataG[dwDataIndex] = byColorMap[++nColorIndex];
- byDataB[dwDataIndex] = byColorMap[++nColorIndex];
-
- /* increment the counters */
- if (++dwCurX == nWidth)
- {
- dwCurX = 0;
- if (bInterlaced)
- {
- dwCurY += nJump[nCurInterlace];
- if (dwCurY>=nHeight)
- dwCurY = nLines[++nCurInterlace];
- }
- else dwCurY++;
- }
- }
- return( TRUE );
- } /* WriteStack 10/16/89 CFS */
-
-