summaryrefslogtreecommitdiff
path: root/common/im_gif.cpp
diff options
context:
space:
mode:
authorleo2000-09-16 17:18:01 +0000
committerleo2000-09-16 17:18:01 +0000
commit5c325a1966c2e165fc399748702bc838cad07818 (patch)
tree7ccb8b41817fb1a788fc4c6550a835ce273437a1 /common/im_gif.cpp
parente67c8b2a40808e972a3185696236a0d50f53008b (diff)
Moved jpg and gif functions to separate files
Fixed warnings related to setjmp() git-svn-id: http://svn.leocad.org/trunk@118 c7d43263-9d01-0410-8a33-9dba5d9f93d6
Diffstat (limited to 'common/im_gif.cpp')
-rw-r--r--common/im_gif.cpp699
1 files changed, 699 insertions, 0 deletions
diff --git a/common/im_gif.cpp b/common/im_gif.cpp
new file mode 100644
index 0000000..2f1fbe4
--- /dev/null
+++ b/common/im_gif.cpp
@@ -0,0 +1,699 @@
+#include <stdlib.h>
+#include <string.h>
+#include "image.h"
+#include "quant.h"
+#include "file.h"
+extern "C" {
+#include <jpeglib.h>
+}
+
+// =============================================================================
+
+typedef struct
+{
+ unsigned char colormap[3][256];
+
+ // State for GetCode and LZWReadByte
+ char code_buf[256+4];
+ int last_byte; // # of bytes in code_buf
+ int last_bit; // # of bits in code_buf
+ int cur_bit; // next bit index to read
+ bool out_of_blocks; // true if hit terminator data block
+
+ int input_code_size; // codesize given in GIF file
+ int clear_code,end_code;// values for Clear and End codes
+
+ int code_size; // current actual code size
+ int limit_code; // 2^code_size
+ int max_code; // first unused code value
+ bool first_time; // flags first call to LZWReadByte
+
+ // Private state for LZWReadByte
+ int oldcode; // previous LZW symbol
+ int firstcode; // first byte of oldcode's expansion
+
+ // LZW symbol table and expansion stack
+ UINT16 FAR *symbol_head; // => table of prefix symbols
+ UINT8 FAR *symbol_tail; // => table of suffix bytes
+ UINT8 FAR *symbol_stack; // => stack for symbol expansions
+ UINT8 FAR *sp; // stack pointer
+
+ // State for interlaced image processing
+ bool is_interlaced; // true if have interlaced image
+// jvirt_sarray_ptr interlaced_image; // full image in interlaced order
+ unsigned char* interlaced_image;
+ JDIMENSION cur_row_number; // need to know actual row number
+ JDIMENSION pass2_offset; // # of pixel rows in pass 1
+ JDIMENSION pass3_offset; // # of pixel rows in passes 1&2
+ JDIMENSION pass4_offset; // # of pixel rows in passes 1,2,3
+
+ File* input_file;
+ bool first_interlace;
+ unsigned char* buffer;//JSAMPARRAY buffer;
+ unsigned int width, height;
+} gif_source_struct;
+
+typedef gif_source_struct *gif_source_ptr;
+
+// Macros for extracting header data --- note we assume chars may be signed
+#define LM_to_uint(a,b) ((((b)&0xFF) << 8) | ((a)&0xFF))
+#define BitSet(byte, bit) ((byte) & (bit))
+#define INTERLACE 0x40 // mask for bit signifying interlaced image
+#define COLORMAPFLAG 0x80 // mask for bit signifying colormap presence
+
+#undef LZW_TABLE_SIZE
+#define MAX_LZW_BITS 12 // maximum LZW code size
+#define LZW_TABLE_SIZE (1<<MAX_LZW_BITS) // # of possible LZW symbols
+
+static int GetDataBlock (gif_source_ptr sinfo, char *buf)
+{
+ int count = sinfo->input_file->GetChar();
+ if (count > 0)
+ sinfo->input_file->Read(buf, count);
+ return count;
+}
+
+static int GetCode (gif_source_ptr sinfo)
+{
+ register INT32 accum;
+ int offs, ret, count;
+
+ while ((sinfo->cur_bit + sinfo->code_size) > sinfo->last_bit)
+ {
+ if (sinfo->out_of_blocks)
+ return sinfo->end_code; // fake something useful
+ sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];
+ sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];
+ if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0)
+ {
+ sinfo->out_of_blocks = true;
+ return sinfo->end_code; // fake something useful
+ }
+ sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;
+ sinfo->last_byte = 2 + count;
+ sinfo->last_bit = sinfo->last_byte * 8;
+ }
+
+ offs = sinfo->cur_bit >> 3; // byte containing cur_bit
+ accum = sinfo->code_buf[offs+2] & 0xFF;
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs+1] & 0xFF;
+ accum <<= 8;
+ accum |= sinfo->code_buf[offs] & 0xFF;
+ accum >>= (sinfo->cur_bit & 7);
+ ret = ((int) accum) & ((1 << sinfo->code_size) - 1);
+
+ sinfo->cur_bit += sinfo->code_size;
+ return ret;
+}
+
+static int LZWReadByte (gif_source_ptr sinfo)
+{
+ register int code; // current working code
+ int incode; // saves actual input code
+
+ // First time, just eat the expected Clear code(s) and return next code,
+ // which is expected to be a raw byte.
+ if (sinfo->first_time)
+ {
+ sinfo->first_time = false;
+ code = sinfo->clear_code; // enables sharing code with Clear case
+ }
+ else
+ {
+ // If any codes are stacked from a previously read symbol, return them
+ if (sinfo->sp > sinfo->symbol_stack)
+ return (int) *(-- sinfo->sp);
+
+ // Time to read a new symbol
+ code = GetCode(sinfo);
+ }
+
+ if (code == sinfo->clear_code)
+ {
+ sinfo->code_size = sinfo->input_code_size + 1;
+ sinfo->limit_code = sinfo->clear_code << 1; // 2^code_size
+ sinfo->max_code = sinfo->clear_code + 2; // first unused code value
+ sinfo->sp = sinfo->symbol_stack; // init stack to empty
+ do
+ {
+ code = GetCode(sinfo);
+ } while (code == sinfo->clear_code);
+
+ if (code > sinfo->clear_code)
+ code = 0; // use something valid
+ sinfo->firstcode = sinfo->oldcode = code;
+ return code;
+ }
+
+ if (code == sinfo->end_code)
+ {
+ if (!sinfo->out_of_blocks)
+ {
+ char buf[256];
+ while (GetDataBlock(sinfo, buf) > 0)
+ ; // skip
+ sinfo->out_of_blocks = true;
+ }
+ return 0; // fake something usable
+ }
+
+ incode = code; // save for a moment
+
+ if (code >= sinfo->max_code)
+ {
+ // special case for not-yet-defined symbol
+ // code == max_code is OK; anything bigger is bad data
+ if (code > sinfo->max_code)
+ incode = 0; // prevent creation of loops in symbol table
+ // this symbol will be defined as oldcode/firstcode
+ *(sinfo->sp++) = (UINT8) sinfo->firstcode;
+ code = sinfo->oldcode;
+ }
+
+ while (code >= sinfo->clear_code)
+ {
+ *(sinfo->sp++) = sinfo->symbol_tail[code]; // tail is a byte value
+ code = sinfo->symbol_head[code]; // head is another LZW symbol
+ }
+ sinfo->firstcode = code; // save for possible future use
+
+ if ((code = sinfo->max_code) < LZW_TABLE_SIZE)
+ {
+ sinfo->symbol_head[code] = sinfo->oldcode;
+ sinfo->symbol_tail[code] = (UINT8) sinfo->firstcode;
+ sinfo->max_code++;
+ if ((sinfo->max_code >= sinfo->limit_code) &&
+ (sinfo->code_size < MAX_LZW_BITS))
+ {
+ sinfo->code_size++;
+ sinfo->limit_code <<= 1; // keep equal to 2^code_size
+ }
+ }
+
+ sinfo->oldcode = incode; // save last input symbol for future use
+ return sinfo->firstcode; // return first byte of symbol's expansion
+}
+
+LC_IMAGE* OpenGIF(File* file)
+{
+ gif_source_ptr source;
+ source = (gif_source_ptr)malloc (sizeof(gif_source_struct));
+ source->input_file = file;
+
+ char hdrbuf[10];
+ unsigned int width, height;
+ int colormaplen, aspectRatio;
+ int c;
+
+ source->input_file->Read(hdrbuf, 6);
+ if ((hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F') ||
+ ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
+ (hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a')))
+ return NULL;
+
+ source->input_file->Read(hdrbuf, 7);
+ width = LM_to_uint(hdrbuf[0],hdrbuf[1]);
+ height = LM_to_uint(hdrbuf[2],hdrbuf[3]);
+ source->height = height;
+ source->width = width;
+ colormaplen = 2 << (hdrbuf[4] & 0x07);
+ aspectRatio = hdrbuf[6] & 0xFF;
+
+ if (BitSet(hdrbuf[4], COLORMAPFLAG))
+ for (int i = 0; i < colormaplen; i++)
+ {
+ source->colormap[0][i] = source->input_file->GetChar();
+ source->colormap[1][i] = source->input_file->GetChar();
+ source->colormap[2][i] = source->input_file->GetChar();
+ }
+
+ for (;;)
+ {
+ c = source->input_file->GetChar();
+
+// if (c == ';')
+// ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);
+
+ if (c == '!')
+ {
+ int extlabel;
+ char buf[256];
+
+ extlabel = source->input_file->GetChar();
+ while (GetDataBlock(source, buf) > 0)
+ ; // skip
+ continue;
+ }
+
+ if (c != ',')
+ continue;
+
+ source->input_file->Read(hdrbuf, 9);
+ width = LM_to_uint(hdrbuf[4],hdrbuf[5]);
+ height = LM_to_uint(hdrbuf[6],hdrbuf[7]);
+ source->is_interlaced = (hdrbuf[8] & INTERLACE) != 0;
+
+ if (BitSet(hdrbuf[8], COLORMAPFLAG))
+ {
+ colormaplen = 2 << (hdrbuf[8] & 0x07);
+ for (int i = 0; i < colormaplen; i++)
+ {
+ source->colormap[0][i] = source->input_file->GetChar();
+ source->colormap[1][i] = source->input_file->GetChar();
+ source->colormap[2][i] = source->input_file->GetChar();
+ }
+ }
+
+ source->input_code_size = source->input_file->GetChar();
+// if (source->input_code_size < 2 || source->input_code_size >= MAX_LZW_BITS)
+// ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);
+
+ break;
+ }
+
+ source->symbol_head = (UINT16 FAR *) malloc(LZW_TABLE_SIZE * sizeof(UINT16));
+ source->symbol_tail = (UINT8 FAR *) malloc (LZW_TABLE_SIZE * sizeof(UINT8));
+ source->symbol_stack = (UINT8 FAR *) malloc (LZW_TABLE_SIZE * sizeof(UINT8));
+ source->last_byte = 2; // make safe to "recopy last two bytes"
+ source->last_bit = 0; // nothing in the buffer
+ source->cur_bit = 0; // force buffer load on first call
+ source->out_of_blocks = false;
+ source->clear_code = 1 << source->input_code_size;
+ source->end_code = source->clear_code + 1;
+ source->first_time = true;
+ source->code_size = source->input_code_size + 1;
+ source->limit_code = source->clear_code << 1; // 2^code_size
+ source->max_code = source->clear_code + 2; // first unused code value
+ source->sp = source->symbol_stack; // init stack to empty
+
+ if (source->is_interlaced)
+ {
+ source->first_interlace = true;
+ source->interlaced_image = (unsigned char*)malloc(width*height);
+ }
+ else
+ source->first_interlace = false;
+
+ source->buffer = (unsigned char*)malloc(width*3);
+ LC_IMAGE* image = (LC_IMAGE*)malloc(width*height*3 + sizeof(LC_IMAGE));
+ image->width = width;
+ image->height = height;
+ image->bits = (char*)image + sizeof(LC_IMAGE);
+ unsigned char* buf = (unsigned char*)image->bits;
+
+ for (unsigned long scanline = 0; scanline < height; scanline++)
+ {
+ if (source->is_interlaced)
+ {
+ if (source->first_interlace)
+ {
+ register JSAMPROW sptr;
+ register JDIMENSION col;
+ JDIMENSION row;
+
+ for (row = 0; row < source->height; row++)
+ {
+ sptr = &source->interlaced_image[row*source->width];
+ for (col = source->width; col > 0; col--)
+ *sptr++ = (JSAMPLE) LZWReadByte(source);
+ }
+
+ source->first_interlace = false;
+ source->cur_row_number = 0;
+ source->pass2_offset = (source->height + 7) / 8;
+ source->pass3_offset = source->pass2_offset + (source->height + 3) / 8;
+ source->pass4_offset = source->pass3_offset + (source->height + 1) / 4;
+ }
+
+ register int c;
+ register JSAMPROW sptr, ptr;
+ register JDIMENSION col;
+ JDIMENSION irow;
+
+ // Figure out which row of interlaced image is needed, and access it.
+ switch ((int) (source->cur_row_number & 7))
+ {
+ case 0: // first-pass row
+ irow = source->cur_row_number >> 3;
+ break;
+ case 4: // second-pass row
+ irow = (source->cur_row_number >> 3) + source->pass2_offset;
+ break;
+ case 2: // third-pass row
+ case 6:
+ irow = (source->cur_row_number >> 2) + source->pass3_offset;
+ break;
+ default: // fourth-pass row
+ irow = (source->cur_row_number >> 1) + source->pass4_offset;
+ break;
+ }
+ sptr = &source->interlaced_image[irow*source->width];
+ ptr = source->buffer;
+ for (col = source->width; col > 0; col--)
+ {
+ c = GETJSAMPLE(*sptr++);
+ *ptr++ = source->colormap[0][c];
+ *ptr++ = source->colormap[1][c];
+ *ptr++ = source->colormap[2][c];
+ }
+ source->cur_row_number++; // for next time
+ }
+ else
+ {
+ register int c;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->buffer;
+ for (col = source->width; col > 0; col--)
+ {
+ c = LZWReadByte(source);
+ *ptr++ = source->colormap[0][c];
+ *ptr++ = source->colormap[1][c];
+ *ptr++ = source->colormap[2][c];
+ }
+ }
+
+ memcpy (buf+(width*scanline*3), source->buffer, 3*width);
+ }
+
+ if (source->is_interlaced)
+ free(source->interlaced_image);
+ free(source->buffer);
+ free(source->symbol_head);
+ free(source->symbol_tail);
+ free(source->symbol_stack);
+ free(source);
+
+ return image;
+}
+
+// =============================================================================
+
+#undef LZW_TABLE_SIZE
+#define MAX_LZW_BITS 12
+typedef INT16 code_int;
+#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS)
+#define HSIZE 5003
+typedef int hash_int;
+#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
+typedef INT32 hash_entry;
+#define HASH_ENTRY(prefix,suffix) ((((hash_entry) (prefix)) << 8) | (suffix))
+
+typedef struct
+{
+ int n_bits;
+ code_int maxcode;
+ int init_bits;
+ INT32 cur_accum;
+ int cur_bits;
+ code_int waiting_code;
+ bool first_byte;
+ code_int ClearCode;
+ code_int EOFCode;
+ code_int free_code;
+ code_int *hash_code;
+ hash_entry FAR *hash_value;
+ int bytesinpkt;
+ char packetbuf[256];
+ File* output_file;
+ void* buffer;//JSAMPARRAY buffer;
+} gif_dest_struct;
+
+typedef gif_dest_struct* gif_dest_ptr;
+
+// Emit a 16-bit word, LSB first
+static void put_word(File* output_file, unsigned int w)
+{
+ output_file->PutChar(w & 0xFF);
+ output_file->PutChar((w >> 8) & 0xFF);
+}
+
+static void flush_packet(gif_dest_ptr dinfo)
+{
+ if (dinfo->bytesinpkt > 0)
+ {
+ dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
+ dinfo->output_file->Write(dinfo->packetbuf, dinfo->bytesinpkt);
+ dinfo->bytesinpkt = 0;
+ }
+}
+
+static void output(gif_dest_ptr dinfo, code_int code)
+{
+ dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
+ dinfo->cur_bits += dinfo->n_bits;
+
+ while (dinfo->cur_bits >= 8)
+ {
+ (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (dinfo->cur_accum & 0xFF);
+ if ((dinfo)->bytesinpkt >= 255)
+ flush_packet(dinfo);
+
+ dinfo->cur_accum >>= 8;
+ dinfo->cur_bits -= 8;
+ }
+
+ if (dinfo->free_code > dinfo->maxcode)
+ {
+ dinfo->n_bits++;
+ if (dinfo->n_bits == MAX_LZW_BITS)
+ dinfo->maxcode = LZW_TABLE_SIZE;
+ else
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ }
+}
+
+// Accept and compress one 8-bit byte
+static void compress_byte (gif_dest_ptr dinfo, int c)
+{
+ register hash_int i;
+ register hash_int disp;
+ register hash_entry probe_value;
+
+ if (dinfo->first_byte)
+ {
+ dinfo->waiting_code = c;
+ dinfo->first_byte = FALSE;
+ return;
+ }
+
+ i = ((hash_int) c << (MAX_LZW_BITS-8)) + dinfo->waiting_code;
+ if (i >= HSIZE)
+ i -= HSIZE;
+
+ probe_value = HASH_ENTRY(dinfo->waiting_code, c);
+
+ if (dinfo->hash_code[i] != 0)
+ {
+ if (dinfo->hash_value[i] == probe_value)
+ {
+ dinfo->waiting_code = dinfo->hash_code[i];
+ return;
+ }
+ if (i == 0)
+ disp = 1;
+ else
+ disp = HSIZE - i;
+ for (;;)
+ {
+ i -= disp;
+ if (i < 0)
+ i += HSIZE;
+ if (dinfo->hash_code[i] == 0)
+ break;
+ if (dinfo->hash_value[i] == probe_value)
+ {
+ dinfo->waiting_code = dinfo->hash_code[i];
+ return;
+ }
+ }
+ }
+
+ output(dinfo, dinfo->waiting_code);
+ if (dinfo->free_code < LZW_TABLE_SIZE)
+ {
+ dinfo->hash_code[i] = dinfo->free_code++;
+ dinfo->hash_value[i] = probe_value;
+ }
+ else
+ {
+ memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int));
+ dinfo->free_code = dinfo->ClearCode + 2;
+ output(dinfo, dinfo->ClearCode);
+ dinfo->n_bits = dinfo->init_bits;
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ }
+ dinfo->waiting_code = c;
+}
+
+bool SaveGIF(File* file, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background)
+{
+ int InitCodeSize, FlagByte, i;
+ unsigned char pal[3][256];
+ unsigned char* colormappedbuffer = (unsigned char*)malloc(image->width*image->height);
+ dl1quant((unsigned char*)image->bits, colormappedbuffer, image->width, image->height, 256, true, pal);
+
+ gif_dest_ptr dinfo;
+ dinfo = (gif_dest_ptr) malloc (sizeof(gif_dest_struct));
+ dinfo->output_file = file;
+ dinfo->buffer = malloc(image->width*sizeof(JDIMENSION));
+ dinfo->hash_code = (code_int*) malloc(HSIZE * sizeof(code_int));
+ dinfo->hash_value = (hash_entry FAR*)malloc(HSIZE*sizeof(hash_entry));
+
+ InitCodeSize = 8;
+ // Write the GIF header.
+ file->PutChar('G');
+ file->PutChar('I');
+ file->PutChar('F');
+ file->PutChar('8');
+ file->PutChar(transparent ? '9' : '7');
+ file->PutChar('a');
+ // Write the Logical Screen Descriptor
+ put_word(file, (unsigned int)image->width);
+ put_word(file, (unsigned int)image->height);
+ FlagByte = 0x80;
+ FlagByte |= (7) << 4; // color resolution
+ FlagByte |= (7); // size of global color table
+ file->PutChar(FlagByte);
+ file->PutChar(0); // Background color index
+ file->PutChar(0); // Reserved (aspect ratio in GIF89)
+ // Write the Global Color Map
+ for (i = 0; i < 256; i++)
+ {
+ file->PutChar(pal[0][i]);
+ file->PutChar(pal[1][i]);
+ file->PutChar(pal[2][i]);
+ }
+
+ // Write out extension for transparent colour index, if necessary.
+ if (transparent)
+ {
+ unsigned char index = 0;
+
+ for (i = 0; i < 256; i++)
+ if (background[0] == pal[0][i] &&
+ background[1] == pal[1][i] &&
+ background[2] == pal[2][i])
+ {
+ index = i;
+ break;
+ }
+
+ file->PutChar('!');
+ file->PutChar(0xf9);
+ file->PutChar(4);
+ file->PutChar(1);
+ file->PutChar(0);
+ file->PutChar(0);
+ file->PutChar(index);
+ file->PutChar(0);
+ }
+
+ // Write image separator and Image Descriptor
+ file->PutChar(',');
+ put_word(file, 0);
+ put_word(file, 0);
+ put_word(file, (unsigned int)image->width);
+ put_word(file, (unsigned int)image->height);
+ // flag byte: interlaced
+ if (interlaced)
+ file->PutChar(0x40);
+ else
+ file->PutChar(0x00);
+ file->PutChar(InitCodeSize);// Write Initial Code Size byte
+
+ // Initialize for LZW compression of image data
+ dinfo->n_bits = dinfo->init_bits = InitCodeSize+1;
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ dinfo->ClearCode = ((code_int) 1 << (InitCodeSize));
+ dinfo->EOFCode = dinfo->ClearCode + 1;
+ dinfo->free_code = dinfo->ClearCode + 2;
+ dinfo->first_byte = TRUE;
+ dinfo->bytesinpkt = 0;
+ dinfo->cur_accum = 0;
+ dinfo->cur_bits = 0;
+ memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int));
+ output(dinfo, dinfo->ClearCode);
+
+ int scanline = 0;
+ int pass = 0;
+ while (scanline < image->height)
+ {
+ memcpy(dinfo->buffer, colormappedbuffer+(scanline*image->width), image->width);
+
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = (unsigned char*)dinfo->buffer;
+ for (col = image->width; col > 0; col--)
+ compress_byte(dinfo, GETJSAMPLE(*ptr++));
+
+ if (interlaced)
+ {
+ switch (pass)
+ {
+ case 0:
+ {
+ scanline += 8;
+ if (scanline >= image->height)
+ {
+ pass++;
+ scanline = 4;
+ }
+ } break;
+
+ case 1:
+ {
+ scanline += 8;
+ if (scanline >= image->height)
+ {
+ pass++;
+ scanline = 2;
+ }
+ } break;
+
+ case 2:
+ {
+ scanline += 4;
+ if (scanline >= image->height)
+ {
+ pass++;
+ scanline = 1;
+ }
+ } break;
+
+ case 3:
+ {
+ scanline += 2;
+ } break;
+ }
+ }
+ else
+ scanline++;
+ }
+
+ // Finish up at the end of the file.
+ if (!dinfo->first_byte)
+ output(dinfo, dinfo->waiting_code);
+ output(dinfo, dinfo->EOFCode);
+ if (dinfo->cur_bits > 0)
+ {
+ (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (dinfo->cur_accum & 0xFF);
+ if ((dinfo)->bytesinpkt >= 255)
+ flush_packet(dinfo);
+ }
+
+ flush_packet(dinfo);
+ file->PutChar(0);
+ file->PutChar(';');
+ file->Flush();
+
+ free(dinfo->buffer);
+ free(dinfo->hash_code);
+ free(dinfo->hash_value);
+ free(dinfo);
+ free(colormappedbuffer);
+ return true;
+}