summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorleo2000-09-16 17:18:01 +0000
committerleo2000-09-16 17:18:01 +0000
commit5c325a1966c2e165fc399748702bc838cad07818 (patch)
tree7ccb8b41817fb1a788fc4c6550a835ce273437a1
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
-rw-r--r--common/im_gif.cpp699
-rw-r--r--common/im_jpg.cpp188
-rwxr-xr-xcommon/im_png.cpp641
-rw-r--r--common/image.cpp1079
-rw-r--r--common/module.mk16
5 files changed, 1332 insertions, 1291 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;
+}
diff --git a/common/im_jpg.cpp b/common/im_jpg.cpp
new file mode 100644
index 0000000..9940839
--- /dev/null
+++ b/common/im_jpg.cpp
@@ -0,0 +1,188 @@
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "image.h"
+extern "C" {
+#include <jpeglib.h>
+}
+
+typedef struct bt_jpeg_error_mgr
+{
+ struct jpeg_error_mgr pub; // "public" fields
+ jmp_buf setjmp_buffer; // for return to caller
+} bt_jpeg_error_mgr;
+
+static void bt_jpeg_error_exit (j_common_ptr cinfo)
+{
+ bt_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message) (cinfo, buffer);
+// MessageBox(NULL, buffer, "JPEG Fatal Error", MB_ICONSTOP);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+// stash a scanline
+static void j_putRGBScanline(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
+{
+ int offset = row * widthPix * 3;
+ int count;
+ for (count = 0; count < widthPix; count++)
+ {
+ unsigned char iRed, iBlu, iGrn;
+ unsigned char *oRed, *oBlu, *oGrn;
+
+ iRed = *(jpegline + count * 3 + 0);
+ iGrn = *(jpegline + count * 3 + 1);
+ iBlu = *(jpegline + count * 3 + 2);
+
+ oRed = outBuf + offset + count * 3 + 0;
+ oGrn = outBuf + offset + count * 3 + 1;
+ oBlu = outBuf + offset + count * 3 + 2;
+
+ *oRed = iRed;
+ *oGrn = iGrn;
+ *oBlu = iBlu;
+ }
+}
+
+// stash a gray scanline
+static void j_putGrayScanlineToRGB(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
+{
+ int offset = row * widthPix * 3;
+ int count;
+ for (count = 0; count < widthPix; count++)
+ {
+ unsigned char iGray;
+ unsigned char *oRed, *oBlu, *oGrn;
+
+ // get our grayscale value
+ iGray = *(jpegline + count);
+
+ oRed = outBuf + offset + count * 3;
+ oGrn = outBuf + offset + count * 3 + 1;
+ oBlu = outBuf + offset + count * 3 + 2;
+
+ *oRed = iGray;
+ *oGrn = iGray;
+ *oBlu = iGray;
+ }
+}
+
+// =============================================================================
+
+LC_IMAGE* OpenJPG (char* filename)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct bt_jpeg_error_mgr jerr;
+ FILE* infile = NULL;
+ JSAMPARRAY buffer; // Output row buffer
+ int row_stride; // physical row width in output buffer
+
+ if ((infile = fopen(filename, "rb")) == NULL)
+ return NULL;
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = bt_jpeg_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+
+ if (infile != NULL)
+ fclose(infile);
+ return NULL;
+ }
+
+ jpeg_create_decompress(&cinfo);
+ jpeg_stdio_src(&cinfo, infile);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // get our buffer set to hold data
+ LC_IMAGE* image = (LC_IMAGE*)malloc(cinfo.output_width*cinfo.output_height*3 + sizeof(LC_IMAGE));
+
+ if (image == NULL)
+ {
+// MessageBox(NULL, "Error", "Cannot allocate memory", MB_ICONSTOP);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return NULL;
+ }
+
+ image->width = cinfo.output_width;
+ image->height = cinfo.output_height;
+ image->bits = (char*)image + sizeof(LC_IMAGE);
+
+ row_stride = cinfo.output_width * cinfo.output_components;
+ buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ jpeg_read_scanlines(&cinfo, buffer, 1);
+
+ if (cinfo.out_color_components == 3)
+ j_putRGBScanline(buffer[0], image->width, (unsigned char*)image->bits, cinfo.output_scanline-1);
+ else if (cinfo.out_color_components == 1)
+ j_putGrayScanlineToRGB(buffer[0], image->width, (unsigned char*)image->bits, cinfo.output_scanline-1);
+ }
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+
+ return image;
+}
+
+// =============================================================================
+
+bool SaveJPG (char* filename, LC_IMAGE* image, int quality, bool progressive)
+{
+ struct jpeg_compress_struct cinfo;
+ struct bt_jpeg_error_mgr jerr;
+ int row_stride; // physical row widthPix in image buffer
+ FILE* outfile;
+
+ // allocate and initialize JPEG compression object
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = bt_jpeg_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ // jpeg_destroy_compress(&cinfo);
+ // if (outfile != NULL)
+ // fclose(outfile);
+ return false;
+ }
+
+ jpeg_create_compress(&cinfo);
+ if ((outfile = fopen(filename, "wb")) == NULL)
+ return false;
+
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ cinfo.image_width = image->width;
+ cinfo.image_height = image->height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, quality, TRUE);
+
+ if (progressive)
+ jpeg_simple_progression(&cinfo);
+
+ jpeg_start_compress(&cinfo, TRUE);
+ row_stride = image->width * 3;
+
+ while (cinfo.next_scanline < cinfo.image_height)
+ {
+ unsigned char* outRow = (unsigned char*)image->bits + (cinfo.next_scanline * image->width * 3);
+ jpeg_write_scanlines(&cinfo, &outRow, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ fclose(outfile);
+ jpeg_destroy_compress(&cinfo);
+
+ return true;
+}
diff --git a/common/im_png.cpp b/common/im_png.cpp
index 1fc3512..0dab0cf 100755
--- a/common/im_png.cpp
+++ b/common/im_png.cpp
@@ -9,348 +9,355 @@
(composite) = (unsigned char)((temp + (temp >> 8)) >> 8); \
}
-// ========================================================
+// =============================================================================
LC_IMAGE* OpenPNG(char* filename)
{
- unsigned char sig[8], red, green, blue;
- unsigned char *image_data = NULL;
- unsigned char *src, *dest;
- unsigned char r, g, b, a;
- unsigned long i, row;
- unsigned long image_rowbytes;
- png_color_16p pBackground;
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- png_uint_32 width, height;
- png_bytepp row_pointers = NULL;
- int bit_depth, color_type;
- int image_channels;
- double gamma;
- FILE* f;
-
- f = fopen(filename, "rb");
- if (f == NULL)
- return NULL;
-
- fread(sig, 1, 8, f);
- if (!png_check_sig(sig, 8))
- {
- fclose(f);
- return NULL; // bad signature
- }
-
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- {
- fclose(f);
- return NULL; // out of memory
- }
-
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
- {
- png_destroy_read_struct(&png_ptr, NULL, NULL);
- fclose(f);
- return NULL; // out of memory
- }
-
- if (setjmp(png_ptr->jmpbuf))
- {
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- fclose(f);
- return NULL;
- }
-
- png_init_io(png_ptr, f);
- png_set_sig_bytes(png_ptr, 8); // we already read the 8 signature bytes
+ unsigned char sig[8], red, green, blue;
+ unsigned char *image_data = NULL;
+ unsigned char *src, *dest;
+ unsigned char r, g, b, a;
+ unsigned long i, row;
+ unsigned long image_rowbytes;
+ png_color_16p pBackground;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_uint_32 width, height;
+ png_bytepp row_pointers = NULL;
+ int bit_depth, color_type;
+ int image_channels;
+ double gamma;
+ FILE* f;
+
+ f = fopen(filename, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fread(sig, 1, 8, f);
+ if (!png_check_sig(sig, 8))
+ {
+ fclose(f);
+ return NULL; // bad signature
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ fclose(f);
+ return NULL; // out of memory
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ fclose(f);
+ return NULL; // out of memory
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+ return NULL;
+ }
+
+ png_init_io(png_ptr, f);
+ png_set_sig_bytes(png_ptr, 8); // we already read the 8 signature bytes
+
+ png_read_info(png_ptr, info_ptr); // read all PNG info up to image data
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+ return NULL;
+ }
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
+ {
+ png_get_bKGD(png_ptr, info_ptr, &pBackground);
+
+ if (setjmp (png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+ return NULL;
+ }
- png_read_info(png_ptr, info_ptr); // read all PNG info up to image data
- png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
- NULL, NULL, NULL);
+ // however, it always returns the raw bKGD data, regardless of any
+ // bit-depth transformations, so check depth and adjust if necessary
+ if (bit_depth == 16)
+ {
+ red = pBackground->red >> 8;
+ green = pBackground->green >> 8;
+ blue = pBackground->blue >> 8;
+ }
+ else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ {
+ if (bit_depth == 1)
+ red = green = blue = pBackground->gray? 255 : 0;
+ else if (bit_depth == 2)
+ red = green = blue = (255/3) * pBackground->gray;
+ else // bit_depth == 4
+ red = green = blue = (255/15) * pBackground->gray;
+ }
+ else
+ {
+ red = (unsigned char)pBackground->red;
+ green = (unsigned char)pBackground->green;
+ blue = (unsigned char)pBackground->blue;
+ }
+ }
+ else
+ {
+ if (setjmp (png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+ return NULL;
+ }
- if (setjmp(png_ptr->jmpbuf))
+ red = green = blue = 0;
+ }
+
+ // expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
+ // transparency chunks to full alpha channel; strip 16-bit-per-sample
+ // images to 8 bits per sample; and convert grayscale to RGB[A]
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, 2.2, gamma);
+
+ // all transformations have been registered; now update info_ptr data,
+ // get rowbytes and channels, and allocate image memory
+ png_read_update_info(png_ptr, info_ptr);
+
+ image_rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ image_channels = (int)png_get_channels(png_ptr, info_ptr);
+
+ if ((image_data = (unsigned char*)malloc(image_rowbytes*height)) == NULL)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+ return NULL;
+ }
+
+ if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ free(image_data);
+ fclose(f);
+ return NULL;
+ }
+
+ // set the individual row_pointers to point at the correct offsets
+ for (i = 0; i < height; ++i)
+ row_pointers[i] = image_data + i*image_rowbytes;
+
+ // now we can go ahead and just read the whole image
+ png_read_image(png_ptr, row_pointers);
+
+ // and we're done! (png_read_end() can be omitted if no processing of
+ // post-IDAT text/time/etc. is desired)
+ free(row_pointers);
+ row_pointers = NULL;
+
+ png_read_end(png_ptr, NULL);
+
+ // done with PNG file, so clean up to minimize memory usage
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(f);
+
+ if (!image_data)
+ return NULL;
+
+ // get our buffer set to hold data
+ LC_IMAGE* image = (LC_IMAGE*)malloc(width*height*3 + sizeof(LC_IMAGE));
+
+ if (image == NULL)
+ {
+ free(image_data);
+ return NULL;
+ }
+
+ image->width = (unsigned short)width;
+ image->height = (unsigned short)height;
+ image->bits = (char*)image + sizeof(LC_IMAGE);
+
+ for (row = 0; row < height; row++)
+ {
+ src = image_data + row*image_rowbytes;
+ dest = (unsigned char*)image->bits + row*image_rowbytes;
+ if (image_channels == 3)
+ {
+ for (i = width; i > 0; i--)
+ {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
+ }
+ }
+ else // if (image_channels == 4)
+ {
+ for (i = width; i > 0; i--)
+ {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ a = *src++;
+
+ if (a == 255)
{
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- fclose(f);
- return NULL;
+ *dest++ = r;
+ *dest++ = g;
+ *dest++ = b;
}
-
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
+ else if (a == 0)
{
- png_get_bKGD(png_ptr, info_ptr, &pBackground);
-
- // however, it always returns the raw bKGD data, regardless of any
- // bit-depth transformations, so check depth and adjust if necessary
- if (bit_depth == 16)
- {
- red = pBackground->red >> 8;
- green = pBackground->green >> 8;
- blue = pBackground->blue >> 8;
- }
- else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
- {
- if (bit_depth == 1)
- red = green = blue = pBackground->gray? 255 : 0;
- else if (bit_depth == 2)
- red = green = blue = (255/3) * pBackground->gray;
- else // bit_depth == 4
- red = green = blue = (255/15) * pBackground->gray;
- }
- else
- {
- red = (unsigned char)pBackground->red;
- green = (unsigned char)pBackground->green;
- blue = (unsigned char)pBackground->blue;
- }
+ *dest++ = red;
+ *dest++ = green;
+ *dest++ = blue;
}
else
- red = green = blue = 0;
-
- // decode the image, all at once
- if (setjmp(png_ptr->jmpbuf))
- {
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- fclose(f);
- return NULL;
- }
-
- // expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
- // transparency chunks to full alpha channel; strip 16-bit-per-sample
- // images to 8 bits per sample; and convert grayscale to RGB[A]
- if (color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_expand(png_ptr);
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
- png_set_expand(png_ptr);
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
- png_set_expand(png_ptr);
- if (bit_depth == 16)
- png_set_strip_16(png_ptr);
- if (color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(png_ptr);
-
- if (png_get_gAMA(png_ptr, info_ptr, &gamma))
- png_set_gamma(png_ptr, 2.2, gamma);
-
- // all transformations have been registered; now update info_ptr data,
- // get rowbytes and channels, and allocate image memory
- png_read_update_info(png_ptr, info_ptr);
-
- image_rowbytes = png_get_rowbytes(png_ptr, info_ptr);
- image_channels = (int)png_get_channels(png_ptr, info_ptr);
-
- if ((image_data = (unsigned char*)malloc(image_rowbytes*height)) == NULL)
- {
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- fclose(f);
- return NULL;
- }
-
- if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL)
{
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- free(image_data);
- fclose(f);
- return NULL;
- }
-
- // set the individual row_pointers to point at the correct offsets
- for (i = 0; i < height; ++i)
- row_pointers[i] = image_data + i*image_rowbytes;
-
- // now we can go ahead and just read the whole image
- png_read_image(png_ptr, row_pointers);
-
- // and we're done! (png_read_end() can be omitted if no processing of
- // post-IDAT text/time/etc. is desired)
- free(row_pointers);
- row_pointers = NULL;
-
- png_read_end(png_ptr, NULL);
-
- // done with PNG file, so clean up to minimize memory usage
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- fclose(f);
-
- if (!image_data)
- return NULL;
-
- // get our buffer set to hold data
- LC_IMAGE* image = (LC_IMAGE*)malloc(width*height*3 + sizeof(LC_IMAGE));
-
- if (image == NULL)
- {
- free(image_data);
- return NULL;
- }
-
- image->width = (unsigned short)width;
- image->height = (unsigned short)height;
- image->bits = (char*)image + sizeof(LC_IMAGE);
-
- for (row = 0; row < height; row++)
- {
- src = image_data + row*image_rowbytes;
- dest = (unsigned char*)image->bits + row*image_rowbytes;
- if (image_channels == 3)
- {
- for (i = width; i > 0; i--)
- {
- r = *src++;
- g = *src++;
- b = *src++;
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- }
- }
- else // if (image_channels == 4)
- {
- for (i = width; i > 0; i--)
- {
- r = *src++;
- g = *src++;
- b = *src++;
- a = *src++;
-
- if (a == 255)
- {
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- }
- else if (a == 0)
- {
- *dest++ = red;
- *dest++ = green;
- *dest++ = blue;
- }
- else
- {
- // this macro (copied from png.h) composites the
- // foreground and background values and puts the
- // result into the first argument; there are no
- // side effects with the first argument
- alpha_composite(*dest++, r, a, red);
- alpha_composite(*dest++, g, a, green);
- alpha_composite(*dest++, b, a, blue);
- }
- }
- }
+ // this macro (copied from png.h) composites the
+ // foreground and background values and puts the
+ // result into the first argument; there are no
+ // side effects with the first argument
+ alpha_composite(*dest++, r, a, red);
+ alpha_composite(*dest++, g, a, green);
+ alpha_composite(*dest++, b, a, blue);
}
+ }
+ }
+ }
- free(image_data);
- return image;
+ free(image_data);
+ return image;
}
-// ========================================================
+// =============================================================================
bool SavePNG(char* filename, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background)
{
- FILE *fp;
- png_structp png_ptr;
- png_infop info_ptr;
- png_bytepp row_pointers = NULL;
- png_color_8 sig_bit;
- png_color_16 bg;
- int i;
-
- fp = fopen(filename, "wb");
- if (!fp)
- return false;
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- {
- fclose(fp);
- return false;
- }
-
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
- {
- png_destroy_write_struct(&png_ptr, NULL);
- fclose(fp);
- return false;
- }
-
- if (setjmp(png_ptr->jmpbuf))
- {
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- fclose(fp);
- return false;
- }
-
- png_init_io(png_ptr, fp);
-
- png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 8,
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_bytepp row_pointers = NULL;
+ png_color_8 sig_bit;
+ png_color_16 bg;
+ int i;
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return false;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ fclose(fp);
+ return false;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr, NULL);
+ fclose(fp);
+ return false;
+ }
+
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ fclose(fp);
+ return false;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ png_set_IHDR (png_ptr, info_ptr, image->width, image->height, 8,
transparent ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
- bg.red = background[0];
- bg.green = background[1];
- bg.blue = background[2];
- png_set_bKGD(png_ptr, info_ptr, &bg);
+ bg.red = background[0];
+ bg.green = background[1];
+ bg.blue = background[2];
+ png_set_bKGD(png_ptr, info_ptr, &bg);
+
+ png_write_info(png_ptr, info_ptr);
+
+ // Set the true bit depth of the image data
+ sig_bit.red = 8;
+ sig_bit.green = 8;
+ sig_bit.blue = 8;
+ sig_bit.alpha = 8;
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+ if ((row_pointers = (png_bytepp)malloc(image->height*sizeof(png_bytep))) == NULL)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ fclose(fp);
+ return false;
+ }
+
+ // set the individual row_pointers to point at the correct offsets
+ if (transparent)
+ {
+ unsigned char *buf, *src, *dst, alpha;
+ dst = buf = (unsigned char*)malloc(image->width*image->height*4);
+ src = (unsigned char*)image->bits;
+
+ for (i = 0; i < image->width*image->height; i++)
+ {
+ if ((src[0] == background[0]) &&
+ (src[1] == background[1]) &&
+ (src[2] == background[2]))
+ alpha = 0;
+ else
+ alpha = 255;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = alpha;
+ }
- png_write_info(png_ptr, info_ptr);
+ for (i = 0; i < image->height; i++)
+ row_pointers[i] = buf + i*image->width*4;
+ png_write_image(png_ptr, row_pointers);
- // Set the true bit depth of the image data
- sig_bit.red = 8;
- sig_bit.green = 8;
- sig_bit.blue = 8;
- sig_bit.alpha = 8;
+ free(buf);
+ }
+ else
+ {
+ for (i = 0; i < image->height; i++)
+ row_pointers[i] = (unsigned char*)image->bits + i*image->width*3;
+ png_write_image(png_ptr, row_pointers);
+ }
- png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+ free(row_pointers);
- if ((row_pointers = (png_bytepp)malloc(image->height*sizeof(png_bytep))) == NULL)
- {
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- fclose(fp);
- return false;
- }
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
- // set the individual row_pointers to point at the correct offsets
- if (transparent)
- {
- unsigned char *buf, *src, *dst, alpha;
- dst = buf = (unsigned char*)malloc(image->width*image->height*4);
- src = (unsigned char*)image->bits;
-
- for (i = 0; i < image->width*image->height; i++)
- {
- if ((src[0] == background[0]) &&
- (src[1] == background[1]) &&
- (src[2] == background[2]))
- alpha = 0;
- else
- alpha = 255;
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = alpha;
- }
-
- for (i = 0; i < image->height; i++)
- row_pointers[i] = buf + i*image->width*4;
- png_write_image(png_ptr, row_pointers);
-
- free(buf);
- }
- else
- {
- for (i = 0; i < image->height; i++)
- row_pointers[i] = (unsigned char*)image->bits + i*image->width*3;
- png_write_image(png_ptr, row_pointers);
- }
-
- free(row_pointers);
-
- png_write_end(png_ptr, info_ptr);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- fclose(fp);
-
- return true;
+ return true;
}
-
diff --git a/common/image.cpp b/common/image.cpp
index 950f211..02b9638 100644
--- a/common/image.cpp
+++ b/common/image.cpp
@@ -1,1032 +1,167 @@
// Image I/O routines
//
-#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "image.h"
-#include "quant.h"
#include "file.h"
-extern "C" {
-#include <jpeglib.h>
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// static declarations
-
-static LC_IMAGE* OpenJPG(char* filename);
-LC_IMAGE* OpenBMP(char* filename);
-LC_IMAGE* OpenPNG(char* filename);
-static LC_IMAGE* OpenGIF(File* file);
-
-static bool SaveJPG(char* filename, LC_IMAGE* image, int quality, bool progressive);
-bool SaveBMP(char* filename, LC_IMAGE* image, bool quantize);
-bool SavePNG(char* filename, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background);
-static bool SaveGIF(File* file, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background);
-
-typedef struct bt_jpeg_error_mgr
-{
- struct jpeg_error_mgr pub; // "public" fields
- jmp_buf setjmp_buffer; // for return to caller
-} bt_jpeg_error_mgr;
-
-static void bt_jpeg_error_exit (j_common_ptr cinfo)
-{
- bt_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err;
- char buffer[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message) (cinfo, buffer);
-// MessageBox(NULL, buffer, "JPEG Fatal Error", MB_ICONSTOP);
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-// stash a scanline
-static void j_putRGBScanline(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
-{
- int offset = row * widthPix * 3;
- int count;
- for (count = 0; count < widthPix; count++)
- {
- unsigned char iRed, iBlu, iGrn;
- unsigned char *oRed, *oBlu, *oGrn;
-
- iRed = *(jpegline + count * 3 + 0);
- iGrn = *(jpegline + count * 3 + 1);
- iBlu = *(jpegline + count * 3 + 2);
-
- oRed = outBuf + offset + count * 3 + 0;
- oGrn = outBuf + offset + count * 3 + 1;
- oBlu = outBuf + offset + count * 3 + 2;
-
- *oRed = iRed;
- *oGrn = iGrn;
- *oBlu = iBlu;
- }
-}
-// stash a gray scanline
-static void j_putGrayScanlineToRGB(unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row)
-{
- int offset = row * widthPix * 3;
- int count;
- for (count = 0; count < widthPix; count++)
- {
- unsigned char iGray;
- unsigned char *oRed, *oBlu, *oGrn;
+// =============================================================================
+// Function declarations (functions from the im_xxx.cpp files)
- // get our grayscale value
- iGray = *(jpegline + count);
+LC_IMAGE* OpenJPG (char* filename);
+LC_IMAGE* OpenBMP (char* filename);
+LC_IMAGE* OpenPNG (char* filename);
+LC_IMAGE* OpenGIF (File* file);
- oRed = outBuf + offset + count * 3;
- oGrn = outBuf + offset + count * 3 + 1;
- oBlu = outBuf + offset + count * 3 + 2;
+bool SaveJPG (char* filename, LC_IMAGE* image, int quality, bool progressive);
+bool SaveBMP (char* filename, LC_IMAGE* image, bool quantize);
+bool SavePNG (char* filename, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background);
+bool SaveGIF (File* file, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background);
- *oRed = iGray;
- *oGrn = iGray;
- *oBlu = iGray;
- }
-}
+// =============================================================================
+// Static functions
static LC_IMAGE* ResizeImage(LC_IMAGE* image)
{
- int i, j;
- long shifted_x, shifted_y;
- if (image == NULL)
- return NULL;
+ int i, j;
+ long shifted_x, shifted_y;
+ if (image == NULL)
+ return NULL;
- shifted_x = image->width;
- for (i = 0; ((i < 16) && (shifted_x != 0)); i++)
- shifted_x = shifted_x >> 1;
- shifted_x = (i != 0) ? 1 << (i-1) : 1;
+ shifted_x = image->width;
+ for (i = 0; ((i < 16) && (shifted_x != 0)); i++)
+ shifted_x = shifted_x >> 1;
+ shifted_x = (i != 0) ? 1 << (i-1) : 1;
- shifted_y = image->height;
- for (i = 0; ((i < 16) && (shifted_y != 0)); i++)
- shifted_y = shifted_y >> 1;
- shifted_y = (i != 0) ? 1 << (i-1) : 1;
+ shifted_y = image->height;
+ for (i = 0; ((i < 16) && (shifted_y != 0)); i++)
+ shifted_y = shifted_y >> 1;
+ shifted_y = (i != 0) ? 1 << (i-1) : 1;
- if ((shifted_x == image->width) && (shifted_y == image->height))
- return image;
+ if ((shifted_x == image->width) && (shifted_y == image->height))
+ return image;
- LC_IMAGE* newimage = (LC_IMAGE*)malloc(shifted_x*shifted_y*3+sizeof(LC_IMAGE));
- newimage->width = (unsigned short)shifted_x;
- newimage->height = (unsigned short)shifted_y;
- newimage->bits = (unsigned char*)newimage + sizeof(LC_IMAGE);
- memset(newimage->bits, 0, shifted_x*shifted_y*3);
+ LC_IMAGE* newimage = (LC_IMAGE*)malloc(shifted_x*shifted_y*3+sizeof(LC_IMAGE));
+ newimage->width = (unsigned short)shifted_x;
+ newimage->height = (unsigned short)shifted_y;
+ newimage->bits = (unsigned char*)newimage + sizeof(LC_IMAGE);
+ memset(newimage->bits, 0, shifted_x*shifted_y*3);
- float accumx, accumy;
- int stx, sty;
- unsigned char *oldbits = (unsigned char*)image->bits,
- *newbits = (unsigned char*)newimage->bits;
+ float accumx, accumy;
+ int stx, sty;
+ unsigned char *oldbits = (unsigned char*)image->bits,
+ *newbits = (unsigned char*)newimage->bits;
- for (j = 0; j < image->height; j++)
- {
- accumy = (float)newimage->height*j/(float)image->height;
- sty = (int)floor(accumy);
+ for (j = 0; j < image->height; j++)
+ {
+ accumy = (float)newimage->height*j/(float)image->height;
+ sty = (int)floor(accumy);
- for (i = 0; i < image->width; i++)
- {
- accumx = (float)newimage->width*i/(float)image->width;
- stx = (int)floor(accumx);
+ for (i = 0; i < image->width; i++)
+ {
+ accumx = (float)newimage->width*i/(float)image->width;
+ stx = (int)floor(accumx);
- newbits[(stx+sty*newimage->width)*3] = oldbits[(i+j*image->width)*3];
- newbits[(stx+sty*newimage->width)*3+1] = oldbits[(i+j*image->width)*3+1];
- newbits[(stx+sty*newimage->width)*3+2] = oldbits[(i+j*image->width)*3+2];
- }
- }
+ newbits[(stx+sty*newimage->width)*3] = oldbits[(i+j*image->width)*3];
+ newbits[(stx+sty*newimage->width)*3+1] = oldbits[(i+j*image->width)*3+1];
+ newbits[(stx+sty*newimage->width)*3+2] = oldbits[(i+j*image->width)*3+2];
+ }
+ }
- free(image);
- return newimage;
+ free(image);
+ return newimage;
}
-/////////////////////////////////////////////////////////////////////////////
-// functions
+// =============================================================================
+// Global functions
// Reads a file from disk
LC_IMAGE* OpenImage(char* filename)
{
- char ext[5];
- if (strlen(filename) != 0)
- {
- char *p = strrchr(filename, '.');
- if (p != NULL)
- strcpy (ext, p+1);
- }
- strlwr(ext);
-
- if ((strcmp(ext, "jpg") == 0) || (strcmp (ext, "jpeg") == 0))
- return ResizeImage(OpenJPG(filename));
- if (strcmp(ext, "bmp") == 0)
- return ResizeImage(OpenBMP(filename));
- if (strcmp(ext, "png") == 0)
- return ResizeImage(OpenPNG(filename));
- if ((strcmp (ext, "gif") == 0) || (strcmp (ext, "tmp") == 0))
- {
- FileDisk file;
- if (!file.Open(filename, "rb"))
- return NULL;
- LC_IMAGE* image = ResizeImage(OpenGIF(&file));
- file.Close();
- return image;
- }
+ char ext[5];
+ if (strlen(filename) != 0)
+ {
+ char *p = strrchr(filename, '.');
+ if (p != NULL)
+ strcpy (ext, p+1);
+ }
+ strlwr(ext);
+
+ if ((strcmp(ext, "jpg") == 0) || (strcmp (ext, "jpeg") == 0))
+ return ResizeImage(OpenJPG(filename));
+ if (strcmp(ext, "bmp") == 0)
+ return ResizeImage(OpenBMP(filename));
+ if (strcmp(ext, "png") == 0)
+ return ResizeImage(OpenPNG(filename));
+ if ((strcmp (ext, "gif") == 0) || (strcmp (ext, "tmp") == 0))
+ {
+ FileDisk file;
+ if (!file.Open(filename, "rb"))
+ return NULL;
+ LC_IMAGE* image = ResizeImage(OpenGIF(&file));
+ file.Close();
+ return image;
+ }
// MessageBox (NULL, "Unknown File Format", "Error", MB_ICONSTOP);
- return NULL;
+ return NULL;
}
LC_IMAGE* OpenImage(File* file, unsigned char format)
{
- if (format != LC_IMAGE_GIF)
- return NULL;
- return OpenGIF(file);
+ if (format != LC_IMAGE_GIF)
+ return NULL;
+ return OpenGIF(file);
}
bool SaveImage(char* filename, LC_IMAGE* image, LC_IMAGE_OPTS* opts)
{
- char ext[5];
- if (strlen(filename) != 0)
- {
- char *p = strrchr(filename, '.');
- if (p != NULL)
- strcpy(ext, p+1);
- }
- strlwr(ext);
+ char ext[5];
+ if (strlen(filename) != 0)
+ {
+ char *p = strrchr(filename, '.');
+ if (p != NULL)
+ strcpy(ext, p+1);
+ }
+ strlwr(ext);
- if ((strcmp (ext, "jpg") == 0) || (strcmp (ext, "jpeg") == 0))
- return SaveJPG(filename, image, opts->quality, opts->interlaced);
+ if ((strcmp (ext, "jpg") == 0) || (strcmp (ext, "jpeg") == 0))
+ return SaveJPG(filename, image, opts->quality, opts->interlaced);
- if (strcmp (ext, "gif") == 0)
- {
- FileDisk file;
- if (!file.Open(filename, "wb"))
- return false;
+ if (strcmp (ext, "gif") == 0)
+ {
+ FileDisk file;
+ if (!file.Open(filename, "wb"))
+ return false;
- bool ret = SaveGIF(&file, image, opts->transparent, opts->interlaced, opts->background);
- file.Close();
- return ret;
- }
+ bool ret = SaveGIF(&file, image, opts->transparent, opts->interlaced, opts->background);
+ file.Close();
+ return ret;
+ }
- if (strcmp (ext, "bmp") == 0)
- return SaveBMP(filename, image, opts->truecolor == false);
+ if (strcmp (ext, "bmp") == 0)
+ return SaveBMP(filename, image, opts->truecolor == false);
- if (strcmp (ext, "png") == 0)
- return SavePNG(filename, image, opts->transparent, opts->interlaced, opts->background);
+ if (strcmp (ext, "png") == 0)
+ return SavePNG(filename, image, opts->transparent, opts->interlaced, opts->background);
// MessageBox (NULL, "Could not save file", "Error", MB_ICONSTOP);
- return false;
+ return false;
}
bool SaveImage(File* file, LC_IMAGE* image, LC_IMAGE_OPTS* opts)
{
- if (opts->format != LC_IMAGE_GIF)
- return false;
- return SaveGIF(file, image, opts->transparent, opts->interlaced, opts->background);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// read functions
-
-static LC_IMAGE* OpenJPG(char* filename)
-{
- struct jpeg_decompress_struct cinfo;
- struct bt_jpeg_error_mgr jerr;
- FILE* infile = NULL;
- JSAMPARRAY buffer; // Output row buffer
- int row_stride; // physical row width in output buffer
-
- if ((infile = fopen(filename, "rb")) == NULL)
- return NULL;
-
- cinfo.err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = bt_jpeg_error_exit;
-
- if (setjmp(jerr.setjmp_buffer))
- {
- jpeg_destroy_decompress(&cinfo);
-
- if (infile != NULL)
- fclose(infile);
- return NULL;
- }
-
- jpeg_create_decompress(&cinfo);
- jpeg_stdio_src(&cinfo, infile);
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // get our buffer set to hold data
- LC_IMAGE* image = (LC_IMAGE*)malloc(cinfo.output_width*cinfo.output_height*3 + sizeof(LC_IMAGE));
-
- if (image == NULL)
- {
-// MessageBox(NULL, "Error", "Cannot allocate memory", MB_ICONSTOP);
- jpeg_destroy_decompress(&cinfo);
- fclose(infile);
- return NULL;
- }
-
- image->width = cinfo.output_width;
- image->height = cinfo.output_height;
- image->bits = (char*)image + sizeof(LC_IMAGE);
-
- row_stride = cinfo.output_width * cinfo.output_components;
- buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
-
- while (cinfo.output_scanline < cinfo.output_height)
- {
- jpeg_read_scanlines(&cinfo, buffer, 1);
-
- if (cinfo.out_color_components == 3)
- j_putRGBScanline(buffer[0], image->width, (unsigned char*)image->bits, cinfo.output_scanline-1);
- else if (cinfo.out_color_components == 1)
- j_putGrayScanlineToRGB(buffer[0], image->width, (unsigned char*)image->bits, cinfo.output_scanline-1);
- }
-
- jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- fclose(infile);
-
- return image;
-}
-
-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
-}
-
-static 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;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// save functions
-
-static bool SaveJPG (char* filename, LC_IMAGE* image, int quality, bool progressive)
-{
- struct jpeg_compress_struct cinfo;
- FILE* outfile = NULL;
- int row_stride; // physical row widthPix in image buffer
- struct bt_jpeg_error_mgr jerr;
-
- // allocate and initialize JPEG compression object
- cinfo.err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = bt_jpeg_error_exit;
-
- if (setjmp(jerr.setjmp_buffer))
- {
- jpeg_destroy_compress(&cinfo);
- if (outfile != NULL)
- fclose(outfile);
- return false;
- }
-
- jpeg_create_compress(&cinfo);
- if ((outfile = fopen(filename, "wb")) == NULL)
- return false;
-
- jpeg_stdio_dest(&cinfo, outfile);
-
- cinfo.image_width = image->width;
- cinfo.image_height = image->height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality, TRUE);
-
- if (progressive)
- jpeg_simple_progression(&cinfo);
-
- jpeg_start_compress(&cinfo, TRUE);
- row_stride = image->width * 3;
-
- while (cinfo.next_scanline < cinfo.image_height)
- {
- unsigned char* outRow = (unsigned char*)image->bits + (cinfo.next_scanline * image->width * 3);
- jpeg_write_scanlines(&cinfo, &outRow, 1);
- }
-
- jpeg_finish_compress(&cinfo);
- fclose(outfile);
- jpeg_destroy_compress(&cinfo);
-
- return true;
+ if (opts->format != LC_IMAGE_GIF)
+ return false;
+ return SaveGIF(file, image, opts->transparent, opts->interlaced, opts->background);
}
-#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;
-}
-
-static bool SaveGIF(File* file, LC_IMAGE* image, bool transparent, bool interlaced, unsigned char* background)
-{
- int InitCodeSize, FlagByte;
- int 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;
-}
#ifdef LC_WINDOWS
//#include <windows.h>
diff --git a/common/module.mk b/common/module.mk
index a22bcbe..70ad3fa 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -1,4 +1,16 @@
-SRC += common/camera.cpp common/file.cpp common/globals.cpp common/group.cpp common/image.cpp common/im_bmp.cpp common/im_png.cpp common/library.cpp common/light.cpp common/matrix.cpp common/piece.cpp common/pieceinf.cpp common/project.cpp common/quant.cpp common/terrain.cpp common/texture.cpp common/tr.cpp common/vector.cpp common/opengl.cpp common/object.cpp common/minifig.cpp
+SRC += common/camera.cpp common/file.cpp common/globals.cpp common/group.cpp common/image.cpp common/im_bmp.cpp common/im_gif.cpp common/library.cpp common/light.cpp common/matrix.cpp common/piece.cpp common/pieceinf.cpp common/project.cpp common/quant.cpp common/terrain.cpp common/texture.cpp common/tr.cpp common/vector.cpp common/opengl.cpp common/object.cpp common/minifig.cpp
-LIBS += -ljpeg -lpng -lz -lm
+ifeq ($(HAVE_JPEGLIB), yes)
+ LIBS += -ljpeg
+ SRC += common/im_jpg.cpp
+endif
+
+ifeq ($(HAVE_ZLIB), yes)
+ifeq ($(HAVE_PNGLIB), yes)
+ LIBS += -lpng -lz
+ SRC += common/im_png.cpp
+endif
+endif
+
+LIBS += -lm