📄 gifcls.cpp
字号:
for (i = 0; i <= len; i++) {
k = startloc + i;
j = (unsigned int) (k & pixels_per_bytem1);
k = k >> pixelshift_per_byte;
pixels[k] = (pixels[k] & win_notmask[j]) +
(((BYTE) (localvalues[i] % colors)) << win_bitshift[j]);
}
}
// StorePixel(leftpt, rownum, localvalues[0]);
return (1);
}
// GIF::OutputLine
// Output a line of pixels.
// This is where the code to handle interlaced images has been added - CAM
int GIF::OutputLine( BYTE FAR *localvalues, int nNumberOfDots )
{
int nResult; // result code
// Output the line of pixels.
nResult = StorePixelLine( wRowCount, 0, nNumberOfDots, localvalues);
// If the image is non-interlaced, simply increment the row number.
if (!bInterlaced)
wRowCount++;
else {
// If the image is interlaced, the row number is changed according
// to the interlacing pass we're currently on.
switch (nPassNumber) {
// On the first pass, output every 8th row, starting at row 0.
case 0:
wRowCount += 8;
// If we've gone beyond the end of the image, we're now on
// the second pass:
if (wRowCount>=wHeight) {
nPassNumber = 1;
wRowCount = 4;
}
break;
// On the second pass, output every 8th row, starting at row 4.
case 1:
wRowCount += 8;
// If we've gone beyond the end of the image, we're now on
// the 3rd pass:
if (wRowCount>=wHeight) {
nPassNumber = 2;
wRowCount = 2;
}
break;
// On the third pass, output every 4th row, starting at row 2.
case 2:
wRowCount += 4;
// If we've gone beyond the end of the image, we're now on
// the 4th pass:
if (wRowCount>=wHeight) {
nPassNumber = 3;
wRowCount = 1;
}
break;
// On the 4th pass, output every 2nd row starting at row 1.
case 3:
wRowCount += 2;
break;
}
}
return nResult;
}
// GIF::CleanData
// Clean up in preparation for a "graceful" exit after an error.
void GIF::CleanData()
{
// Close the file.
_lclose(hFile);
hFile=NULL;
}
/* DECODE.C - An LZW decoder for GIF
* Copyright (C) 1987, by Steven A. Bennett
*
* Permission is given by the author to freely redistribute and include
* this code in any program as long as this credit is given where due.
*
* In accordance with the above, I want to credit Steve Wilhite who wrote
* the code which this is heavily inspired by...
*
* GIF and 'Graphics Interchange Format' are trademarks (tm) of
* Compuserve, Incorporated, an H&R Block Company.
*
* Release Notes: This file contains a decoder routine for GIF images
* which is similar, structurally, to the original routine by Steve Wilhite.
* It is, however, somewhat noticably faster in most cases.
*
== This routine was modified for use in FRACTINT in two ways.
==
== 1) The original #includes were folded into the routine strictly to hold
== down the number of files we were dealing with.
==
== 2) The 'stack', 'suffix', 'prefix', and 'buf' arrays were changed from
== static and 'malloc()'ed to external only so that the assembler
== program could use the same array space for several independent
== chunks of code. Also, 'stack' was renamed to 'dstack' for TASM
== compatibility.
==
== 3) The 'out_line()' external function has been changed to reference
== '*outln()' for flexibility (in particular, 3D transformations)
==
== 4) A call to 'keypressed()' has been added after the 'outln()' calls
== to check for the presenc of a key-press as a bail-out signal
==
== (Bert Tyler and Timothy Wegner)
*/
/* Various error codes used by decoder
* and my own routines... It's okay
* for you to define whatever you want,
* as long as it's negative... It will be
* returned intact up the various subroutine
* levels...
*/
#define OUT_OF_MEMORY -10
#define BAD_CODE_SIZE -20
#define READ_ERROR -1
#define WRITE_ERROR -2
#define OPEN_ERROR -3
#define CREATE_ERROR -4
const LONG code_mask[13] = {
0,
0x0001, 0x0003,
0x0007, 0x000F,
0x001F, 0x003F,
0x007F, 0x00FF,
0x01FF, 0x03FF,
0x07FF, 0x0FFF
};
// GIF::InitializeDecoder
// Initialize the LZW decoder.
void GIF::InitializeDecoder( short size )
// Input arguments:
// size Initial code size, in bits.
{
curr_size = size + 1;
top_slot = 1 << curr_size;
clear = 1 << size;
ending = clear + 1;
slot = newcodes = ending + 1;
navail_bytes = nbits_left = 0;
}
// GIF::GetNextCode
// Retrieve the next code from the file. Return the code,
// or else a negative number in the case of a file error.
short GIF::GetNextCode()
{
short i, x;
DWORD ret;
if (nbits_left == 0) {
if (navail_bytes <= 0) {
/* Out of bytes in current block, so read next block
*/
pbytes = byte_buff;
if ((navail_bytes = GetByte()) < 0)
return (navail_bytes);
else if (navail_bytes) {
for (i = 0; i < navail_bytes; ++i) {
if ((x = GetByte()) < 0)
return (x);
byte_buff[i] =(BYTE)x;
}
}
}
b1 = *pbytes++;
nbits_left = 8;
--navail_bytes;
}
ret = b1 >> (8 - nbits_left);
while (curr_size > nbits_left) {
if (navail_bytes <= 0) {
/* Out of bytes in current block, so read next block
*/
pbytes = byte_buff;
if ((navail_bytes = GetByte()) < 0)
return (navail_bytes);
else if (navail_bytes) {
for (i = 0; i < navail_bytes; ++i) {
if ((x = GetByte()) < 0)
return (x);
byte_buff[i] =(BYTE)x;
}
}
}
b1 = *pbytes++;
ret |= b1 << nbits_left;
nbits_left += 8;
--navail_bytes;
}
nbits_left -= curr_size;
ret &= code_mask[curr_size];
return ((short) (ret));
}
/* - This function decodes an LZW image, according to the method used
* in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded
* will generate a call to out_line(), which is a user specific function
* to display a line of pixels. The function gets its codes from
* get_next_code() which is responsible for reading blocks of data and
* seperating them into the proper size codes. Finally, GetByte() is
* the global routine to read the next byte from the GIF file.
*
* It is generally a good idea to have linewidth correspond to the actual
* width of a line (as specified in the Image header) to make your own
* code a bit simpler, but it isn't absolutely necessary.
*
* Returns: 0 if successful, else negative. (See ERRS.H)
*
*/
// I've changed this function so that all the memory used (which was
// previously global) is now allocated and freed locally.
// Windows applications have local heap space restrictions!!!!
// - CAM
short GIF::Decoder( short linewidth )
{
BYTE FAR *sp; // stack pointer
BYTE FAR *bufptr; // pointer to decoder buffer
BYTE FAR *buf; // pointer to decoder buffer
BYTE FAR *dstack; // decoder stack
BYTE FAR *suffix; // suffix array
BYTE FAR *decoderline; // decoded pixels array
WORD FAR *prefix; // prefix array
int nBufferLength; // length of output buffer
short code, fc, oc, bufcnt;
short c, size, ret;
short xskip, yskip;
const int MAX_CODES = 4095; // size of LZW code table
navail_bytes = 0; /* # bytes left in block */
nbits_left = 0; /* # bits left in current byte */
bad_code_count = 0;
skipxdots = 0;
skipydots = 0;
// Initialize for decoding a new image.
// Read the initial code size from the data stream.
if ((size = GetByte()) < 0)
return (size);
if (size<2 || size>9)
return (BAD_CODE_SIZE);
InitializeDecoder( size );
xskip = yskip = 0;
// Allocate buffers.
decoderline = (BYTE FAR *) GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT,
2049 );
dstack = (BYTE FAR *) GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT,
MAX_CODES+1 );
suffix = (BYTE FAR *) GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT,
MAX_CODES+1 );
prefix = (WORD FAR *) GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT,
(MAX_CODES+1)*sizeof(WORD) );
/* Initialize in case they forgot to put in a clear code.
* (This shouldn't happen, but we'll try and decode it anyway...)
*/
oc = fc = 0;
// Set up the initial pointers.
buf = decoderline;
sp = dstack;
bufptr = buf;
bufcnt = linewidth;
/* This is the main loop. For each code we get we pass through the
* linked list of prefix codes, pushing the corresponding "character" for
* each code onto the stack. When the list reaches a single "character"
* we push that on the stack too, and then start unstacking each
* character for output in the correct order. Special handling is
* included for the clear code, and the whole thing ends when we get
* an ending code.
*/
while ((c=GetNextCode()) != ending) {
/* If we had a file error, return without completing the decode
*/
if (c < 0)
return (0);
/* If the code is a clear code, reinitialize all necessary items.
*/
if (c == clear) {
curr_size = size + 1;
slot = newcodes;
top_slot = 1 << curr_size;
/* Continue reading codes until we get a non-clear code
* (Another unlikely, but possible case...)
*/
while ((c = GetNextCode()) == clear)
;
/* If we get an ending code immediately after a clear code
* (Yet another unlikely case), then break out of the loop.
*/
if (c == ending)
break;
/* Finally, if the code is beyond the range of already set codes,
* (This one had better NOT happen... I have no idea what will
* result from this, but I doubt it will look good...) then set it
* to color zero.
*/
if (c >= slot)
c = 0;
oc = fc = c;
/* And let us not forget to put the char into the buffer... */
*sp++ = (BYTE)c; /* let the common code outside the if else stuff it */
}
else {
/* In this case, it's not a clear code or an ending code, so
* it must be a code code... So we can now decode the code into
* a stack of character codes. (Clear as mud, right?)
*/
code = c;
/* Here we go again with one of those off chances... If, on the
* off chance, the code we got is beyond the range of those already
* set up (Another thing which had better NOT happen...) we trick
* the decoder into thinking it actually got the last code read.
* (Hmmn... I'm not sure why this works... But it does...)
*/
if (code >= slot) {
if (code > slot)
++bad_code_count;
code = oc;
*sp++ = (BYTE)fc;
}
/* Here we scan back along the linked list of prefixes, pushing
* helpless characters (ie. suffixes) onto the stack as we do so.
*/
while (code >= newcodes) {
*sp++ = suffix[code];
code = prefix[code];
}
/* Push the last character on the stack, and set up the new
* prefix and suffix, and if the required slot number is greater
* than that allowed by the current bit size, increase the bit
* size. (NOTE - If we are all full, we *don't* save the new
* suffix and prefix... I'm not certain if this is correct...
* it might be more proper to overwrite the last code...
*/
*sp++ = (BYTE)code;
if (slot < top_slot) {
fc = code;
suffix[slot] = (BYTE)fc;
prefix[slot++] = oc;
oc = c;
}
if (slot >= top_slot) {
if (curr_size < 12) {
top_slot <<= 1;
++curr_size;
}
}
}
/* Now that we've pushed the decoded string (in reverse order)
* onto the stack, lets pop it off and put it into our decode
* buffer... And when the decode buffer is full, write another
* line...
*/
while (sp > dstack) {
--sp;
if (--xskip < 0) {
xskip = skipxdots;
*bufptr++ = *sp;
}
if (--bufcnt == 0) /* finished an input row? */
{
if (--yskip < 0) {
nBufferLength = (int) (bufptr - buf);
if ((ret = OutputLine(buf, nBufferLength)) < 0)
return (ret);
yskip = skipydots;
}
bufptr = buf;
bufcnt = linewidth;
xskip = 0;
}
}
}
/* PB note that if last line is incomplete, we're not going to try
to emit it; original code did, but did so via out_line and therefore
couldn't have worked well in all cases... */
// Free the allocated memory.
GlobalFreePtr( decoderline );
GlobalFreePtr( dstack );
GlobalFreePtr( suffix );
GlobalFreePtr( prefix );
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -