added giflib sources
This commit is contained in:
parent
08c3bd9e2b
commit
b2f5dab913
6
Makefile
6
Makefile
|
@ -48,8 +48,7 @@ LINUX_LINKER_FLAGS= \
|
||||||
-lm \
|
-lm \
|
||||||
-lpthread \
|
-lpthread \
|
||||||
-lrt \
|
-lrt \
|
||||||
-lz \
|
-lz
|
||||||
-lgif
|
|
||||||
|
|
||||||
MINGW_OUTPUT=bin/tic.exe
|
MINGW_OUTPUT=bin/tic.exe
|
||||||
|
|
||||||
|
@ -118,6 +117,7 @@ SOURCES_EXT= \
|
||||||
src/html.c
|
src/html.c
|
||||||
|
|
||||||
LPEG_SRC= src/ext/lpeg/*.c
|
LPEG_SRC= src/ext/lpeg/*.c
|
||||||
|
GIF_SRC= src/ext/gif/*.c
|
||||||
|
|
||||||
DEMO_ASSETS= \
|
DEMO_ASSETS= \
|
||||||
bin/assets/fire.tic.dat \
|
bin/assets/fire.tic.dat \
|
||||||
|
@ -287,7 +287,7 @@ arm-flto:
|
||||||
$(CC) $(OPT_ARM) $(SOURCES) $(TIC80_SRC) $(OPT) $(INCLUDES) $(LINUX_ARM_LIBS) $(LINUX_LINKER_FLAGS) -flto -o bin/tic
|
$(CC) $(OPT_ARM) $(SOURCES) $(TIC80_SRC) $(OPT) $(INCLUDES) $(LINUX_ARM_LIBS) $(LINUX_LINKER_FLAGS) -flto -o bin/tic
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
$(CC) $(LINUX_INCLUDES) $(SOURCES) $(LPEG_SRC) $(SOURCES_EXT) $(TIC80_SRC) $(OPT) $(INCLUDES) $(LINUX_LIBS) $(LINUX_LINKER_FLAGS) -o bin/tic
|
$(CC) $(LINUX_INCLUDES) $(SOURCES) $(LPEG_SRC) $(GIF_SRC) $(SOURCES_EXT) $(TIC80_SRC) $(OPT) $(INCLUDES) $(LINUX_LIBS) $(LINUX_LINKER_FLAGS) -o bin/tic
|
||||||
|
|
||||||
macosx:
|
macosx:
|
||||||
$(CC) $(SOURCES) $(TIC80_SRC) $(SOURCES_EXT) src/ext/file_dialog.m $(OPT) $(MACOSX_OPT) $(INCLUDES) $(MACOSX_LIBS) -o bin/tic
|
$(CC) $(SOURCES) $(TIC80_SRC) $(SOURCES_EXT) src/ext/file_dialog.m $(OPT) $(MACOSX_OPT) $(INCLUDES) $(MACOSX_LIBS) -o bin/tic
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,97 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
gif_err.c - handle error reporting for the GIF library.
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "gif_lib.h"
|
||||||
|
#include "gif_lib_private.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Return a string description of the last GIF error
|
||||||
|
*****************************************************************************/
|
||||||
|
const char *
|
||||||
|
GifErrorString(int ErrorCode)
|
||||||
|
{
|
||||||
|
const char *Err;
|
||||||
|
|
||||||
|
switch (ErrorCode) {
|
||||||
|
case E_GIF_ERR_OPEN_FAILED:
|
||||||
|
Err = "Failed to open given file";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_WRITE_FAILED:
|
||||||
|
Err = "Failed to write to given file";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_HAS_SCRN_DSCR:
|
||||||
|
Err = "Screen descriptor has already been set";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_HAS_IMAG_DSCR:
|
||||||
|
Err = "Image descriptor is still active";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_NO_COLOR_MAP:
|
||||||
|
Err = "Neither global nor local color map";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_DATA_TOO_BIG:
|
||||||
|
Err = "Number of pixels bigger than width * height";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_NOT_ENOUGH_MEM:
|
||||||
|
Err = "Failed to allocate required memory";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_DISK_IS_FULL:
|
||||||
|
Err = "Write failed (disk full?)";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_CLOSE_FAILED:
|
||||||
|
Err = "Failed to close given file";
|
||||||
|
break;
|
||||||
|
case E_GIF_ERR_NOT_WRITEABLE:
|
||||||
|
Err = "Given file was not opened for write";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_OPEN_FAILED:
|
||||||
|
Err = "Failed to open given file";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_READ_FAILED:
|
||||||
|
Err = "Failed to read from given file";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NOT_GIF_FILE:
|
||||||
|
Err = "Data is not in GIF format";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NO_SCRN_DSCR:
|
||||||
|
Err = "No screen descriptor detected";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NO_IMAG_DSCR:
|
||||||
|
Err = "No Image Descriptor detected";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NO_COLOR_MAP:
|
||||||
|
Err = "Neither global nor local color map";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_WRONG_RECORD:
|
||||||
|
Err = "Wrong record type detected";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_DATA_TOO_BIG:
|
||||||
|
Err = "Number of pixels bigger than width * height";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NOT_ENOUGH_MEM:
|
||||||
|
Err = "Failed to allocate required memory";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_CLOSE_FAILED:
|
||||||
|
Err = "Failed to close given file";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_NOT_READABLE:
|
||||||
|
Err = "Given file was not opened for read";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_IMAGE_DEFECT:
|
||||||
|
Err = "Image is defective, decoding aborted";
|
||||||
|
break;
|
||||||
|
case D_GIF_ERR_EOF_TOO_SOON:
|
||||||
|
Err = "Image EOF detected before image complete";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Err = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,259 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
gif_font.c - utility font handling and simple drawing for the GIF library
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "gif_lib.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Ascii 8 by 8 regular font - only first 128 characters are supported.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each array entry holds the bits for 8 horizontal scan lines, topmost
|
||||||
|
* first. The most significant bit of each constant is the leftmost bit of
|
||||||
|
* the scan line.
|
||||||
|
*/
|
||||||
|
/*@+charint@*/
|
||||||
|
const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH] = {
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* Ascii 0 */
|
||||||
|
{0x3c, 0x42, 0xa5, 0x81, 0xbd, 0x42, 0x3c, 0x00}, /* Ascii 1 */
|
||||||
|
{0x3c, 0x7e, 0xdb, 0xff, 0xc3, 0x7e, 0x3c, 0x00}, /* Ascii 2 */
|
||||||
|
{0x00, 0xee, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 3 */
|
||||||
|
{0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 4 */
|
||||||
|
{0x00, 0x3c, 0x18, 0xff, 0xff, 0x08, 0x18, 0x00}, /* Ascii 5 */
|
||||||
|
{0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x10, 0x38, 0x00}, /* Ascii 6 */
|
||||||
|
{0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, 0x00, 0x00}, /* Ascii 7 */
|
||||||
|
{0xff, 0xff, 0xe7, 0xc3, 0xe7, 0xff, 0xff, 0xff}, /* Ascii 8 */
|
||||||
|
{0x00, 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c, 0x00}, /* Ascii 9 */
|
||||||
|
{0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0xbd, 0xc3, 0xff}, /* Ascii 10 */
|
||||||
|
{0x1f, 0x07, 0x0d, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* Ascii 11 */
|
||||||
|
{0x00, 0x7e, 0xc3, 0xc3, 0x7e, 0x18, 0x7e, 0x18}, /* Ascii 12 */
|
||||||
|
{0x04, 0x06, 0x07, 0x04, 0x04, 0xfc, 0xf8, 0x00}, /* Ascii 13 */
|
||||||
|
{0x0c, 0x0a, 0x0d, 0x0b, 0xf9, 0xf9, 0x1f, 0x1f}, /* Ascii 14 */
|
||||||
|
{0x00, 0x92, 0x7c, 0x44, 0xc6, 0x7c, 0x92, 0x00}, /* Ascii 15 */
|
||||||
|
{0x00, 0x00, 0x60, 0x78, 0x7e, 0x78, 0x60, 0x00}, /* Ascii 16 */
|
||||||
|
{0x00, 0x00, 0x06, 0x1e, 0x7e, 0x1e, 0x06, 0x00}, /* Ascii 17 */
|
||||||
|
{0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18}, /* Ascii 18 */
|
||||||
|
{0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, /* Ascii 19 */
|
||||||
|
{0xff, 0xb6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x00}, /* Ascii 20 */
|
||||||
|
{0x7e, 0xc1, 0xdc, 0x22, 0x22, 0x1f, 0x83, 0x7e}, /* Ascii 21 */
|
||||||
|
{0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}, /* Ascii 22 */
|
||||||
|
{0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x00, 0xff}, /* Ascii 23 */
|
||||||
|
{0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* Ascii 24 */
|
||||||
|
{0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x00}, /* Ascii 25 */
|
||||||
|
{0x00, 0x04, 0x06, 0xff, 0x06, 0x04, 0x00, 0x00}, /* Ascii 26 */
|
||||||
|
{0x00, 0x20, 0x60, 0xff, 0x60, 0x20, 0x00, 0x00}, /* Ascii 27 */
|
||||||
|
{0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xff, 0x00}, /* Ascii 28 */
|
||||||
|
{0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, /* Ascii 29 */
|
||||||
|
{0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00}, /* Ascii 30 */
|
||||||
|
{0x00, 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 31 */
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
|
||||||
|
{0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00}, /* ! */
|
||||||
|
{0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
|
||||||
|
{0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, /* # */
|
||||||
|
{0x10, 0x7c, 0xd2, 0x7c, 0x86, 0x7c, 0x10, 0x00}, /* $ */
|
||||||
|
{0xf0, 0x96, 0xfc, 0x18, 0x3e, 0x72, 0xde, 0x00}, /* % */
|
||||||
|
{0x30, 0x48, 0x30, 0x78, 0xce, 0xcc, 0x78, 0x00}, /* & */
|
||||||
|
{0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
|
||||||
|
{0x10, 0x60, 0xc0, 0xc0, 0xc0, 0x60, 0x10, 0x00}, /* ( */
|
||||||
|
{0x10, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x10, 0x00}, /* ) */
|
||||||
|
{0x00, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x00, 0x00}, /* * */
|
||||||
|
{0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00}, /* + */
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x70}, /* , */
|
||||||
|
{0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}, /* - */
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00}, /* . */
|
||||||
|
{0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00}, /* / */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* 0 */
|
||||||
|
{0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* 1 */
|
||||||
|
{0x7c, 0xc6, 0x06, 0x0c, 0x30, 0x60, 0xfe, 0x00}, /* 2 */
|
||||||
|
{0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00}, /* 3 */
|
||||||
|
{0x0e, 0x1e, 0x36, 0x66, 0xfe, 0x06, 0x06, 0x00}, /* 4 */
|
||||||
|
{0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xfc, 0x00}, /* 5 */
|
||||||
|
{0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00}, /* 6 */
|
||||||
|
{0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00}, /* 7 */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* 8 */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00}, /* 9 */
|
||||||
|
{0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}, /* : */
|
||||||
|
{0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00}, /* }, */
|
||||||
|
{0x00, 0x1c, 0x30, 0x60, 0x30, 0x1c, 0x00, 0x00}, /* < */
|
||||||
|
{0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}, /* = */
|
||||||
|
{0x00, 0x70, 0x18, 0x0c, 0x18, 0x70, 0x00, 0x00}, /* > */
|
||||||
|
{0x7c, 0xc6, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, /* ? */
|
||||||
|
{0x7c, 0x82, 0x9a, 0xaa, 0xaa, 0x9e, 0x7c, 0x00}, /* @ */
|
||||||
|
{0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, /* A */
|
||||||
|
{0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x00}, /* B */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00}, /* C */
|
||||||
|
{0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00}, /* D */
|
||||||
|
{0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xfe, 0x00}, /* E */
|
||||||
|
{0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* F */
|
||||||
|
{0x7c, 0xc6, 0xc0, 0xce, 0xc6, 0xc6, 0x7e, 0x00}, /* G */
|
||||||
|
{0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00}, /* H */
|
||||||
|
{0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, /* I */
|
||||||
|
{0x1e, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00}, /* J */
|
||||||
|
{0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x00}, /* K */
|
||||||
|
{0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00}, /* L */
|
||||||
|
{0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00}, /* M */
|
||||||
|
{0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, /* N */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* O */
|
||||||
|
{0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* P */
|
||||||
|
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x06}, /* Q */
|
||||||
|
{0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0x00}, /* R */
|
||||||
|
{0x78, 0xcc, 0x60, 0x30, 0x18, 0xcc, 0x78, 0x00}, /* S */
|
||||||
|
{0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, /* T */
|
||||||
|
{0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* U */
|
||||||
|
{0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* V */
|
||||||
|
{0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, /* W */
|
||||||
|
{0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00}, /* X */
|
||||||
|
{0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00}, /* Y */
|
||||||
|
{0xfe, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00}, /* Z */
|
||||||
|
{0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00}, /* [ */
|
||||||
|
{0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x00}, /* \ */
|
||||||
|
{0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00}, /* ] */
|
||||||
|
{0x00, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, /* ^ */
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /* _ */
|
||||||
|
{0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
|
||||||
|
{0x00, 0x00, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00}, /* a */
|
||||||
|
{0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0x00}, /* b */
|
||||||
|
{0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0x7e, 0x00}, /* c */
|
||||||
|
{0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x00}, /* d */
|
||||||
|
{0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7e, 0x00}, /* e */
|
||||||
|
{0x1e, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x00}, /* f */
|
||||||
|
{0x00, 0x00, 0x7e, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* g */
|
||||||
|
{0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* */
|
||||||
|
{0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* i */
|
||||||
|
{0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0xf0}, /* j */
|
||||||
|
{0xc0, 0xc0, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0x00}, /* k */
|
||||||
|
{0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* l */
|
||||||
|
{0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, /* m */
|
||||||
|
{0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* n */
|
||||||
|
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* o */
|
||||||
|
{0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0xc0}, /* p */
|
||||||
|
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x06}, /* q */
|
||||||
|
{0x00, 0x00, 0x6e, 0x70, 0x60, 0x60, 0x60, 0x00}, /* r */
|
||||||
|
{0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00}, /* s */
|
||||||
|
{0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x1c, 0x00}, /* t */
|
||||||
|
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00}, /* u */
|
||||||
|
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* v */
|
||||||
|
{0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x00}, /* w */
|
||||||
|
{0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, /* x */
|
||||||
|
{0x00, 0x00, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* y */
|
||||||
|
{0x00, 0x00, 0xfc, 0x18, 0x30, 0x60, 0xfc, 0x00}, /* z */
|
||||||
|
{0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00}, /* { */
|
||||||
|
{0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */
|
||||||
|
{0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, /* } */
|
||||||
|
{0x00, 0x00, 0x70, 0x9a, 0x0e, 0x00, 0x00, 0x00}, /* ~ */
|
||||||
|
{0x00, 0x00, 0x18, 0x3c, 0x66, 0xff, 0x00, 0x00} /* Ascii 127 */
|
||||||
|
};
|
||||||
|
/*@=charint@*/
|
||||||
|
|
||||||
|
void
|
||||||
|
GifDrawText8x8(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const char *legend,
|
||||||
|
const int color)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int base;
|
||||||
|
const char *cp;
|
||||||
|
|
||||||
|
for (i = 0; i < GIF_FONT_HEIGHT; i++) {
|
||||||
|
base = Image->ImageDesc.Width * (y + i) + x;
|
||||||
|
|
||||||
|
for (cp = legend; *cp; cp++)
|
||||||
|
for (j = 0; j < GIF_FONT_WIDTH; j++) {
|
||||||
|
if (GifAsciiTable8x8[(short)(*cp)][i] & (1 << (GIF_FONT_WIDTH - j)))
|
||||||
|
Image->RasterBits[base] = color;
|
||||||
|
base++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GifDrawBox(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const int w, const int d,
|
||||||
|
const int color)
|
||||||
|
{
|
||||||
|
int j, base = Image->ImageDesc.Width * y + x;
|
||||||
|
|
||||||
|
for (j = 0; j < w; j++)
|
||||||
|
Image->RasterBits[base + j] =
|
||||||
|
Image->RasterBits[base + (d * Image->ImageDesc.Width) + j] = color;
|
||||||
|
|
||||||
|
for (j = 0; j < d; j++)
|
||||||
|
Image->RasterBits[base + j * Image->ImageDesc.Width] =
|
||||||
|
Image->RasterBits[base + j * Image->ImageDesc.Width + w] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GifDrawRectangle(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const int w, const int d,
|
||||||
|
const int color)
|
||||||
|
{
|
||||||
|
unsigned char *bp = Image->RasterBits + Image->ImageDesc.Width * y + x;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < d; i++)
|
||||||
|
memset(bp + (i * Image->ImageDesc.Width), color, (size_t)w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GifDrawBoxedText8x8(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const char *legend,
|
||||||
|
const int border,
|
||||||
|
const int bg, const int fg)
|
||||||
|
{
|
||||||
|
int j = 0, LineCount = 0, TextWidth = 0;
|
||||||
|
const char *cp;
|
||||||
|
char *dup;
|
||||||
|
|
||||||
|
/* compute size of text to box */
|
||||||
|
for (cp = legend; *cp; cp++)
|
||||||
|
if (*cp == '\r') {
|
||||||
|
if (j > TextWidth)
|
||||||
|
TextWidth = j;
|
||||||
|
j = 0;
|
||||||
|
LineCount++;
|
||||||
|
} else if (*cp != '\t')
|
||||||
|
++j;
|
||||||
|
LineCount++; /* count last line */
|
||||||
|
if (j > TextWidth) /* last line might be longer than any previous */
|
||||||
|
TextWidth = j;
|
||||||
|
|
||||||
|
/* draw the text */
|
||||||
|
dup = malloc(strlen(legend)+1);
|
||||||
|
/* FIXME: should return bad status, but that would require API change */
|
||||||
|
if (dup != NULL) {
|
||||||
|
int i = 0;
|
||||||
|
/* fill the box */
|
||||||
|
GifDrawRectangle(Image, x + 1, y + 1,
|
||||||
|
border + TextWidth * GIF_FONT_WIDTH + border - 1,
|
||||||
|
border + LineCount * GIF_FONT_HEIGHT + border - 1, bg);
|
||||||
|
(void)strcpy(dup, (char *)legend);
|
||||||
|
cp = strtok((char *)dup, "\r\n");
|
||||||
|
do {
|
||||||
|
int leadspace = 0;
|
||||||
|
|
||||||
|
if (cp[0] == '\t')
|
||||||
|
leadspace = (TextWidth - strlen(++cp)) / 2;
|
||||||
|
|
||||||
|
GifDrawText8x8(Image, x + border + (leadspace * GIF_FONT_WIDTH),
|
||||||
|
y + border + (GIF_FONT_HEIGHT * i++), cp, fg);
|
||||||
|
cp = strtok((char *)NULL, "\r\n");
|
||||||
|
} while (cp);
|
||||||
|
(void)free((void *)dup);
|
||||||
|
|
||||||
|
/* outline the box */
|
||||||
|
GifDrawBox(Image, x, y, border + TextWidth * GIF_FONT_WIDTH + border,
|
||||||
|
border + LineCount * GIF_FONT_HEIGHT + border, fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
gif_hash.c -- module to support the following operations:
|
||||||
|
|
||||||
|
1. InitHashTable - initialize hash table.
|
||||||
|
2. ClearHashTable - clear the hash table to an empty state.
|
||||||
|
2. InsertHashTable - insert one item into data structure.
|
||||||
|
3. ExistsHashTable - test if item exists in data structure.
|
||||||
|
|
||||||
|
This module is used to hash the GIF codes during encoding.
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gif_lib.h"
|
||||||
|
#include "gif_hash.h"
|
||||||
|
#include "gif_lib_private.h"
|
||||||
|
|
||||||
|
/* #define DEBUG_HIT_RATE Debug number of misses per hash Insert/Exists. */
|
||||||
|
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
static long NumberOfTests = 0,
|
||||||
|
NumberOfMisses = 0;
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
|
||||||
|
static int KeyItem(uint32_t Item);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Initialize HashTable - allocate the memory needed and clear it. *
|
||||||
|
******************************************************************************/
|
||||||
|
GifHashTableType *_InitHashTable(void)
|
||||||
|
{
|
||||||
|
GifHashTableType *HashTable;
|
||||||
|
|
||||||
|
if ((HashTable = (GifHashTableType *) malloc(sizeof(GifHashTableType)))
|
||||||
|
== NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
_ClearHashTable(HashTable);
|
||||||
|
|
||||||
|
return HashTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Routine to clear the HashTable to an empty state. *
|
||||||
|
This part is a little machine depended. Use the commented part otherwise. *
|
||||||
|
******************************************************************************/
|
||||||
|
void _ClearHashTable(GifHashTableType *HashTable)
|
||||||
|
{
|
||||||
|
memset(HashTable -> HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Routine to insert a new Item into the HashTable. The data is assumed to be *
|
||||||
|
new one. *
|
||||||
|
******************************************************************************/
|
||||||
|
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code)
|
||||||
|
{
|
||||||
|
int HKey = KeyItem(Key);
|
||||||
|
uint32_t *HTable = HashTable -> HTable;
|
||||||
|
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
NumberOfTests++;
|
||||||
|
NumberOfMisses++;
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
|
||||||
|
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
NumberOfMisses++;
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||||
|
}
|
||||||
|
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Routine to test if given Key exists in HashTable and if so returns its code *
|
||||||
|
Returns the Code if key was found, -1 if not. *
|
||||||
|
******************************************************************************/
|
||||||
|
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key)
|
||||||
|
{
|
||||||
|
int HKey = KeyItem(Key);
|
||||||
|
uint32_t *HTable = HashTable -> HTable, HTKey;
|
||||||
|
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
NumberOfTests++;
|
||||||
|
NumberOfMisses++;
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
|
||||||
|
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
NumberOfMisses++;
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
if (Key == HTKey) return HT_GET_CODE(HTable[HKey]);
|
||||||
|
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Routine to generate an HKey for the hashtable out of the given unique key. *
|
||||||
|
The given Key is assumed to be 20 bits as follows: lower 8 bits are the *
|
||||||
|
new postfix character, while the upper 12 bits are the prefix code. *
|
||||||
|
Because the average hit ratio is only 2 (2 hash references per entry), *
|
||||||
|
evaluating more complex keys (such as twin prime keys) does not worth it! *
|
||||||
|
******************************************************************************/
|
||||||
|
static int KeyItem(uint32_t Item)
|
||||||
|
{
|
||||||
|
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_HIT_RATE
|
||||||
|
/******************************************************************************
|
||||||
|
Debugging routine to print the hit ratio - number of times the hash table *
|
||||||
|
was tested per operation. This routine was used to test the KeyItem routine *
|
||||||
|
******************************************************************************/
|
||||||
|
void HashTablePrintHitRatio(void)
|
||||||
|
{
|
||||||
|
printf("Hash Table Hit Ratio is %ld/%ld = %ld%%.\n",
|
||||||
|
NumberOfMisses, NumberOfTests,
|
||||||
|
NumberOfMisses * 100 / NumberOfTests);
|
||||||
|
}
|
||||||
|
#endif /* DEBUG_HIT_RATE */
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,39 @@
|
||||||
|
/******************************************************************************
|
||||||
|
|
||||||
|
gif_hash.h - magfic constants and declarations for GIF LZW
|
||||||
|
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GIF_HASH_H_
|
||||||
|
#define _GIF_HASH_H_
|
||||||
|
|
||||||
|
//#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
|
||||||
|
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
|
||||||
|
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
|
||||||
|
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
|
||||||
|
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||||
|
|
||||||
|
/* The 32 bits of the long are divided into two parts for the key & code: */
|
||||||
|
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
|
||||||
|
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
|
||||||
|
/* The key is the upper 20 bits. The code is the lower 12. */
|
||||||
|
#define HT_GET_KEY(l) (l >> 12)
|
||||||
|
#define HT_GET_CODE(l) (l & 0x0FFF)
|
||||||
|
#define HT_PUT_KEY(l) (l << 12)
|
||||||
|
#define HT_PUT_CODE(l) (l & 0x0FFF)
|
||||||
|
|
||||||
|
typedef struct GifHashTableType {
|
||||||
|
uint32_t HTable[HT_SIZE];
|
||||||
|
} GifHashTableType;
|
||||||
|
|
||||||
|
GifHashTableType *_InitHashTable(void);
|
||||||
|
void _ClearHashTable(GifHashTableType *HashTable);
|
||||||
|
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code);
|
||||||
|
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key);
|
||||||
|
|
||||||
|
#endif /* _GIF_HASH_H_ */
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,312 @@
|
||||||
|
/******************************************************************************
|
||||||
|
|
||||||
|
gif_lib.h - service library for decoding and encoding GIF images
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GIF_LIB_H_
|
||||||
|
#define _GIF_LIB_H_ 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define GIFLIB_MAJOR 5
|
||||||
|
#define GIFLIB_MINOR 1
|
||||||
|
#define GIFLIB_RELEASE 4
|
||||||
|
|
||||||
|
#define GIF_ERROR 0
|
||||||
|
#define GIF_OK 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||||
|
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||||
|
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||||
|
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||||
|
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
|
||||||
|
|
||||||
|
typedef unsigned char GifPixelType;
|
||||||
|
typedef unsigned char *GifRowType;
|
||||||
|
typedef unsigned char GifByteType;
|
||||||
|
typedef unsigned int GifPrefixType;
|
||||||
|
typedef int GifWord;
|
||||||
|
|
||||||
|
typedef struct GifColorType {
|
||||||
|
GifByteType Red, Green, Blue;
|
||||||
|
} GifColorType;
|
||||||
|
|
||||||
|
typedef struct ColorMapObject {
|
||||||
|
int ColorCount;
|
||||||
|
int BitsPerPixel;
|
||||||
|
bool SortFlag;
|
||||||
|
GifColorType *Colors; /* on malloc(3) heap */
|
||||||
|
} ColorMapObject;
|
||||||
|
|
||||||
|
typedef struct GifImageDesc {
|
||||||
|
GifWord Left, Top, Width, Height; /* Current image dimensions. */
|
||||||
|
bool Interlace; /* Sequential/Interlaced lines. */
|
||||||
|
ColorMapObject *ColorMap; /* The local color map */
|
||||||
|
} GifImageDesc;
|
||||||
|
|
||||||
|
typedef struct ExtensionBlock {
|
||||||
|
int ByteCount;
|
||||||
|
GifByteType *Bytes; /* on malloc(3) heap */
|
||||||
|
int Function; /* The block function code */
|
||||||
|
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
|
||||||
|
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
|
||||||
|
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
|
||||||
|
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
|
||||||
|
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block */
|
||||||
|
} ExtensionBlock;
|
||||||
|
|
||||||
|
typedef struct SavedImage {
|
||||||
|
GifImageDesc ImageDesc;
|
||||||
|
GifByteType *RasterBits; /* on malloc(3) heap */
|
||||||
|
int ExtensionBlockCount; /* Count of extensions before image */
|
||||||
|
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
|
||||||
|
} SavedImage;
|
||||||
|
|
||||||
|
typedef struct GifFileType {
|
||||||
|
GifWord SWidth, SHeight; /* Size of virtual canvas */
|
||||||
|
GifWord SColorResolution; /* How many colors can we generate? */
|
||||||
|
GifWord SBackGroundColor; /* Background color for virtual canvas */
|
||||||
|
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
|
||||||
|
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
|
||||||
|
int ImageCount; /* Number of current image (both APIs) */
|
||||||
|
GifImageDesc Image; /* Current image (low-level API) */
|
||||||
|
SavedImage *SavedImages; /* Image sequence (high-level API) */
|
||||||
|
int ExtensionBlockCount; /* Count extensions past last image */
|
||||||
|
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
|
||||||
|
int Error; /* Last error condition reported */
|
||||||
|
void *UserData; /* hook to attach user data (TVT) */
|
||||||
|
void *Private; /* Don't mess with this! */
|
||||||
|
} GifFileType;
|
||||||
|
|
||||||
|
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UNDEFINED_RECORD_TYPE,
|
||||||
|
SCREEN_DESC_RECORD_TYPE,
|
||||||
|
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||||
|
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||||
|
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||||
|
} GifRecordType;
|
||||||
|
|
||||||
|
/* func type to read gif data from arbitrary sources (TVT) */
|
||||||
|
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
|
||||||
|
|
||||||
|
/* func type to write gif data to arbitrary targets.
|
||||||
|
* Returns count of bytes written. (MRB)
|
||||||
|
*/
|
||||||
|
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
GIF89 structures
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct GraphicsControlBlock {
|
||||||
|
int DisposalMode;
|
||||||
|
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
|
||||||
|
#define DISPOSE_DO_NOT 1 /* Leave image in place */
|
||||||
|
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
|
||||||
|
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
|
||||||
|
bool UserInputFlag; /* User confirmation required before disposal */
|
||||||
|
int DelayTime; /* pre-display delay in 0.01sec units */
|
||||||
|
int TransparentColor; /* Palette index for transparency, -1 if none */
|
||||||
|
#define NO_TRANSPARENT_COLOR -1
|
||||||
|
} GraphicsControlBlock;
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
GIF encoding routines
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* Main entry points */
|
||||||
|
GifFileType *EGifOpenFileName(const char *GifFileName,
|
||||||
|
const bool GifTestExistence, int *Error);
|
||||||
|
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
|
||||||
|
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
|
||||||
|
int EGifSpew(GifFileType * GifFile);
|
||||||
|
const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
|
||||||
|
int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
|
||||||
|
|
||||||
|
#define E_GIF_SUCCEEDED 0
|
||||||
|
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||||
|
#define E_GIF_ERR_WRITE_FAILED 2
|
||||||
|
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||||
|
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||||
|
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||||
|
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||||
|
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||||
|
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||||
|
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||||
|
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||||
|
|
||||||
|
/* These are legacy. You probably do not want to call them directly */
|
||||||
|
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||||
|
const int GifWidth, const int GifHeight,
|
||||||
|
const int GifColorRes,
|
||||||
|
const int GifBackGround,
|
||||||
|
const ColorMapObject *GifColorMap);
|
||||||
|
int EGifPutImageDesc(GifFileType *GifFile,
|
||||||
|
const int GifLeft, const int GifTop,
|
||||||
|
const int GifWidth, const int GifHeight,
|
||||||
|
const bool GifInterlace,
|
||||||
|
const ColorMapObject *GifColorMap);
|
||||||
|
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
|
||||||
|
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
|
||||||
|
int GifLineLen);
|
||||||
|
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
|
||||||
|
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
|
||||||
|
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
|
||||||
|
int EGifPutExtensionBlock(GifFileType *GifFile,
|
||||||
|
const int GifExtLen, const void *GifExtension);
|
||||||
|
int EGifPutExtensionTrailer(GifFileType *GifFile);
|
||||||
|
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
|
||||||
|
const int GifExtLen,
|
||||||
|
const void *GifExtension);
|
||||||
|
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||||
|
const GifByteType *GifCodeBlock);
|
||||||
|
int EGifPutCodeNext(GifFileType *GifFile,
|
||||||
|
const GifByteType *GifCodeBlock);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
GIF decoding routines
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* Main entry points */
|
||||||
|
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
|
||||||
|
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
|
||||||
|
int DGifSlurp(GifFileType * GifFile);
|
||||||
|
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
|
||||||
|
int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
|
||||||
|
|
||||||
|
#define D_GIF_SUCCEEDED 0
|
||||||
|
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||||
|
#define D_GIF_ERR_READ_FAILED 102
|
||||||
|
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||||
|
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||||
|
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||||
|
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||||
|
#define D_GIF_ERR_WRONG_RECORD 107
|
||||||
|
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||||
|
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||||
|
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||||
|
#define D_GIF_ERR_NOT_READABLE 111
|
||||||
|
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||||
|
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||||
|
|
||||||
|
/* These are legacy. You probably do not want to call them directly */
|
||||||
|
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||||
|
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||||
|
int DGifGetImageDesc(GifFileType *GifFile);
|
||||||
|
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||||
|
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||||
|
int DGifGetComment(GifFileType *GifFile, char *GifComment);
|
||||||
|
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||||
|
GifByteType **GifExtension);
|
||||||
|
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
|
||||||
|
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||||
|
GifByteType **GifCodeBlock);
|
||||||
|
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||||
|
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Color table quantization (deprecated)
|
||||||
|
******************************************************************************/
|
||||||
|
int GifQuantizeBuffer(unsigned int Width, unsigned int Height,
|
||||||
|
int *ColorMapSize, GifByteType * RedInput,
|
||||||
|
GifByteType * GreenInput, GifByteType * BlueInput,
|
||||||
|
GifByteType * OutputBuffer,
|
||||||
|
GifColorType * OutputColorMap);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Error handling and reporting.
|
||||||
|
******************************************************************************/
|
||||||
|
extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Everything below this point is new after version 1.2, supporting `slurp
|
||||||
|
mode' for doing I/O in two big belts with all the image-bashing in core.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Color map handling from gif_alloc.c
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
extern ColorMapObject *GifMakeMapObject(int ColorCount,
|
||||||
|
const GifColorType *ColorMap);
|
||||||
|
extern void GifFreeMapObject(ColorMapObject *Object);
|
||||||
|
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||||
|
const ColorMapObject *ColorIn2,
|
||||||
|
GifPixelType ColorTransIn2[]);
|
||||||
|
extern int GifBitSize(int n);
|
||||||
|
|
||||||
|
extern void *
|
||||||
|
reallocarray(void *optr, size_t nmemb, size_t size);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Support for the in-core structures allocation (slurp mode).
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
|
||||||
|
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
|
||||||
|
ExtensionBlock **ExtensionBlocks,
|
||||||
|
int Function,
|
||||||
|
unsigned int Len, unsigned char ExtData[]);
|
||||||
|
extern void GifFreeExtensions(int *ExtensionBlock_Count,
|
||||||
|
ExtensionBlock **ExtensionBlocks);
|
||||||
|
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
|
||||||
|
const SavedImage *CopyFrom);
|
||||||
|
extern void GifFreeSavedImages(GifFileType *GifFile);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
5.x functions for GIF89 graphics control blocks
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
int DGifExtensionToGCB(const size_t GifExtensionLength,
|
||||||
|
const GifByteType *GifExtension,
|
||||||
|
GraphicsControlBlock *GCB);
|
||||||
|
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
|
||||||
|
GifByteType *GifExtension);
|
||||||
|
|
||||||
|
int DGifSavedExtensionToGCB(GifFileType *GifFile,
|
||||||
|
int ImageIndex,
|
||||||
|
GraphicsControlBlock *GCB);
|
||||||
|
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
|
||||||
|
GifFileType *GifFile,
|
||||||
|
int ImageIndex);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
The library's internal utility font
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define GIF_FONT_WIDTH 8
|
||||||
|
#define GIF_FONT_HEIGHT 8
|
||||||
|
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
|
||||||
|
|
||||||
|
extern void GifDrawText8x8(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const char *legend, const int color);
|
||||||
|
|
||||||
|
extern void GifDrawBox(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const int w, const int d, const int color);
|
||||||
|
|
||||||
|
extern void GifDrawRectangle(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const int w, const int d, const int color);
|
||||||
|
|
||||||
|
extern void GifDrawBoxedText8x8(SavedImage *Image,
|
||||||
|
const int x, const int y,
|
||||||
|
const char *legend,
|
||||||
|
const int border, const int bg, const int fg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* _GIF_LIB_H */
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,59 @@
|
||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
gif_lib_private.h - internal giflib routines and structures
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GIF_LIB_PRIVATE_H
|
||||||
|
#define _GIF_LIB_PRIVATE_H
|
||||||
|
|
||||||
|
#include "gif_lib.h"
|
||||||
|
#include "gif_hash.h"
|
||||||
|
|
||||||
|
#define EXTENSION_INTRODUCER 0x21
|
||||||
|
#define DESCRIPTOR_INTRODUCER 0x2c
|
||||||
|
#define TERMINATOR_INTRODUCER 0x3b
|
||||||
|
|
||||||
|
#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||||
|
#define LZ_BITS 12
|
||||||
|
|
||||||
|
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
|
||||||
|
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
|
||||||
|
#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
|
||||||
|
|
||||||
|
#define FILE_STATE_WRITE 0x01
|
||||||
|
#define FILE_STATE_SCREEN 0x02
|
||||||
|
#define FILE_STATE_IMAGE 0x04
|
||||||
|
#define FILE_STATE_READ 0x08
|
||||||
|
|
||||||
|
#define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ)
|
||||||
|
#define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
|
||||||
|
|
||||||
|
typedef struct GifFilePrivateType {
|
||||||
|
GifWord FileState, FileHandle, /* Where all this data goes to! */
|
||||||
|
BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
|
||||||
|
ClearCode, /* The CLEAR LZ code. */
|
||||||
|
EOFCode, /* The EOF LZ code. */
|
||||||
|
RunningCode, /* The next code algorithm can generate. */
|
||||||
|
RunningBits, /* The number of bits required to represent RunningCode. */
|
||||||
|
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
|
||||||
|
LastCode, /* The code before the current code. */
|
||||||
|
CrntCode, /* Current algorithm code. */
|
||||||
|
StackPtr, /* For character stack (see below). */
|
||||||
|
CrntShiftState; /* Number of bits in CrntShiftDWord. */
|
||||||
|
unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
|
||||||
|
unsigned long PixelCount; /* Number of pixels in image. */
|
||||||
|
FILE *File; /* File as stream. */
|
||||||
|
InputFunc Read; /* function to read gif input (TVT) */
|
||||||
|
OutputFunc Write; /* function to write gif output (MRB) */
|
||||||
|
GifByteType Buf[256]; /* Compressed input is buffered here. */
|
||||||
|
GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
|
||||||
|
GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
|
||||||
|
GifPrefixType Prefix[LZ_MAX_CODE + 1];
|
||||||
|
GifHashTableType *HashTable;
|
||||||
|
bool gif89;
|
||||||
|
} GifFilePrivateType;
|
||||||
|
|
||||||
|
#endif /* _GIF_LIB_PRIVATE_H */
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,412 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
GIF construction tools
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gif_lib.h"
|
||||||
|
|
||||||
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Miscellaneous utility functions
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* return smallest bitfield size n will fit in */
|
||||||
|
int
|
||||||
|
GifBitSize(int n)
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
for (i = 1; i <= 8; i++)
|
||||||
|
if ((1 << i) >= n)
|
||||||
|
break;
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Color map object functions
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a color map of given size; initialize with contents of
|
||||||
|
* ColorMap if that pointer is non-NULL.
|
||||||
|
*/
|
||||||
|
ColorMapObject *
|
||||||
|
GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
|
||||||
|
{
|
||||||
|
ColorMapObject *Object;
|
||||||
|
|
||||||
|
/*** FIXME: Our ColorCount has to be a power of two. Is it necessary to
|
||||||
|
* make the user know that or should we automatically round up instead? */
|
||||||
|
if (ColorCount != (1 << GifBitSize(ColorCount))) {
|
||||||
|
return ((ColorMapObject *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
|
||||||
|
if (Object == (ColorMapObject *) NULL) {
|
||||||
|
return ((ColorMapObject *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
|
||||||
|
if (Object->Colors == (GifColorType *) NULL) {
|
||||||
|
free(Object);
|
||||||
|
return ((ColorMapObject *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object->ColorCount = ColorCount;
|
||||||
|
Object->BitsPerPixel = GifBitSize(ColorCount);
|
||||||
|
Object->SortFlag = false;
|
||||||
|
|
||||||
|
if (ColorMap != NULL) {
|
||||||
|
memcpy((char *)Object->Colors,
|
||||||
|
(char *)ColorMap, ColorCount * sizeof(GifColorType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
Free a color map object
|
||||||
|
*******************************************************************************/
|
||||||
|
void
|
||||||
|
GifFreeMapObject(ColorMapObject *Object)
|
||||||
|
{
|
||||||
|
if (Object != NULL) {
|
||||||
|
(void)free(Object->Colors);
|
||||||
|
(void)free(Object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
DumpColorMap(ColorMapObject *Object,
|
||||||
|
FILE * fp)
|
||||||
|
{
|
||||||
|
if (Object != NULL) {
|
||||||
|
int i, j, Len = Object->ColorCount;
|
||||||
|
|
||||||
|
for (i = 0; i < Len; i += 4) {
|
||||||
|
for (j = 0; j < 4 && j < Len; j++) {
|
||||||
|
(void)fprintf(fp, "%3d: %02x %02x %02x ", i + j,
|
||||||
|
Object->Colors[i + j].Red,
|
||||||
|
Object->Colors[i + j].Green,
|
||||||
|
Object->Colors[i + j].Blue);
|
||||||
|
}
|
||||||
|
(void)fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
Compute the union of two given color maps and return it. If result can't
|
||||||
|
fit into 256 colors, NULL is returned, the allocated union otherwise.
|
||||||
|
ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
|
||||||
|
copied iff they didn't exist before. ColorTransIn2 maps the old
|
||||||
|
ColorIn2 into the ColorUnion color map table./
|
||||||
|
*******************************************************************************/
|
||||||
|
ColorMapObject *
|
||||||
|
GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||||
|
const ColorMapObject *ColorIn2,
|
||||||
|
GifPixelType ColorTransIn2[])
|
||||||
|
{
|
||||||
|
int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
|
||||||
|
ColorMapObject *ColorUnion;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't worry about duplicates within either color map; if
|
||||||
|
* the caller wants to resolve those, he can perform unions
|
||||||
|
* with an empty color map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Allocate table which will hold the result for sure. */
|
||||||
|
ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
|
||||||
|
ColorIn2->ColorCount) * 2, NULL);
|
||||||
|
|
||||||
|
if (ColorUnion == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy ColorIn1 to ColorUnion.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ColorIn1->ColorCount; i++)
|
||||||
|
ColorUnion->Colors[i] = ColorIn1->Colors[i];
|
||||||
|
CrntSlot = ColorIn1->ColorCount;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Potentially obnoxious hack:
|
||||||
|
*
|
||||||
|
* Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
|
||||||
|
* of table 1. This is very useful if your display is limited to
|
||||||
|
* 16 colors.
|
||||||
|
*/
|
||||||
|
while (ColorIn1->Colors[CrntSlot - 1].Red == 0
|
||||||
|
&& ColorIn1->Colors[CrntSlot - 1].Green == 0
|
||||||
|
&& ColorIn1->Colors[CrntSlot - 1].Blue == 0)
|
||||||
|
CrntSlot--;
|
||||||
|
|
||||||
|
/* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
|
||||||
|
for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
|
||||||
|
/* Let's see if this color already exists: */
|
||||||
|
for (j = 0; j < ColorIn1->ColorCount; j++)
|
||||||
|
if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
|
||||||
|
sizeof(GifColorType)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (j < ColorIn1->ColorCount)
|
||||||
|
ColorTransIn2[i] = j; /* color exists in Color1 */
|
||||||
|
else {
|
||||||
|
/* Color is new - copy it to a new slot: */
|
||||||
|
ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
|
||||||
|
ColorTransIn2[i] = CrntSlot++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CrntSlot > 256) {
|
||||||
|
GifFreeMapObject(ColorUnion);
|
||||||
|
return ((ColorMapObject *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
NewGifBitSize = GifBitSize(CrntSlot);
|
||||||
|
RoundUpTo = (1 << NewGifBitSize);
|
||||||
|
|
||||||
|
if (RoundUpTo != ColorUnion->ColorCount) {
|
||||||
|
register GifColorType *Map = ColorUnion->Colors;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zero out slots up to next power of 2.
|
||||||
|
* We know these slots exist because of the way ColorUnion's
|
||||||
|
* start dimension was computed.
|
||||||
|
*/
|
||||||
|
for (j = CrntSlot; j < RoundUpTo; j++)
|
||||||
|
Map[j].Red = Map[j].Green = Map[j].Blue = 0;
|
||||||
|
|
||||||
|
/* perhaps we can shrink the map? */
|
||||||
|
if (RoundUpTo < ColorUnion->ColorCount) {
|
||||||
|
GifColorType *new_map = (GifColorType *)reallocarray(Map,
|
||||||
|
RoundUpTo, sizeof(GifColorType));
|
||||||
|
if( new_map == NULL ) {
|
||||||
|
GifFreeMapObject(ColorUnion);
|
||||||
|
return ((ColorMapObject *) NULL);
|
||||||
|
}
|
||||||
|
ColorUnion->Colors = new_map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorUnion->ColorCount = RoundUpTo;
|
||||||
|
ColorUnion->BitsPerPixel = NewGifBitSize;
|
||||||
|
|
||||||
|
return (ColorUnion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
Apply a given color translation to the raster bits of an image
|
||||||
|
*******************************************************************************/
|
||||||
|
void
|
||||||
|
GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
|
||||||
|
|
||||||
|
for (i = 0; i < RasterSize; i++)
|
||||||
|
Image->RasterBits[i] = Translation[Image->RasterBits[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Extension record functions
|
||||||
|
******************************************************************************/
|
||||||
|
int
|
||||||
|
GifAddExtensionBlock(int *ExtensionBlockCount,
|
||||||
|
ExtensionBlock **ExtensionBlocks,
|
||||||
|
int Function,
|
||||||
|
unsigned int Len,
|
||||||
|
unsigned char ExtData[])
|
||||||
|
{
|
||||||
|
ExtensionBlock *ep;
|
||||||
|
|
||||||
|
if (*ExtensionBlocks == NULL)
|
||||||
|
*ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
|
||||||
|
else {
|
||||||
|
ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
|
||||||
|
(*ExtensionBlocks, (*ExtensionBlockCount + 1),
|
||||||
|
sizeof(ExtensionBlock));
|
||||||
|
if( ep_new == NULL )
|
||||||
|
return (GIF_ERROR);
|
||||||
|
*ExtensionBlocks = ep_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ExtensionBlocks == NULL)
|
||||||
|
return (GIF_ERROR);
|
||||||
|
|
||||||
|
ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
|
||||||
|
|
||||||
|
ep->Function = Function;
|
||||||
|
ep->ByteCount=Len;
|
||||||
|
ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
|
||||||
|
if (ep->Bytes == NULL)
|
||||||
|
return (GIF_ERROR);
|
||||||
|
|
||||||
|
if (ExtData != NULL) {
|
||||||
|
memcpy(ep->Bytes, ExtData, Len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GIF_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GifFreeExtensions(int *ExtensionBlockCount,
|
||||||
|
ExtensionBlock **ExtensionBlocks)
|
||||||
|
{
|
||||||
|
ExtensionBlock *ep;
|
||||||
|
|
||||||
|
if (*ExtensionBlocks == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (ep = *ExtensionBlocks;
|
||||||
|
ep < (*ExtensionBlocks + *ExtensionBlockCount);
|
||||||
|
ep++)
|
||||||
|
(void)free((char *)ep->Bytes);
|
||||||
|
(void)free((char *)*ExtensionBlocks);
|
||||||
|
*ExtensionBlocks = NULL;
|
||||||
|
*ExtensionBlockCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Image block allocation functions
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* Private Function:
|
||||||
|
* Frees the last image in the GifFile->SavedImages array
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
FreeLastSavedImage(GifFileType *GifFile)
|
||||||
|
{
|
||||||
|
SavedImage *sp;
|
||||||
|
|
||||||
|
if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Remove one SavedImage from the GifFile */
|
||||||
|
GifFile->ImageCount--;
|
||||||
|
sp = &GifFile->SavedImages[GifFile->ImageCount];
|
||||||
|
|
||||||
|
/* Deallocate its Colormap */
|
||||||
|
if (sp->ImageDesc.ColorMap != NULL) {
|
||||||
|
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||||
|
sp->ImageDesc.ColorMap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate the image data */
|
||||||
|
if (sp->RasterBits != NULL)
|
||||||
|
free((char *)sp->RasterBits);
|
||||||
|
|
||||||
|
/* Deallocate any extensions */
|
||||||
|
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||||
|
|
||||||
|
/*** FIXME: We could realloc the GifFile->SavedImages structure but is
|
||||||
|
* there a point to it? Saves some memory but we'd have to do it every
|
||||||
|
* time. If this is used in GifFreeSavedImages then it would be inefficient
|
||||||
|
* (The whole array is going to be deallocated.) If we just use it when
|
||||||
|
* we want to free the last Image it's convenient to do it here.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append an image block to the SavedImages array
|
||||||
|
*/
|
||||||
|
SavedImage *
|
||||||
|
GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
|
||||||
|
{
|
||||||
|
if (GifFile->SavedImages == NULL)
|
||||||
|
GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
||||||
|
else
|
||||||
|
GifFile->SavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
|
||||||
|
(GifFile->ImageCount + 1), sizeof(SavedImage));
|
||||||
|
|
||||||
|
if (GifFile->SavedImages == NULL)
|
||||||
|
return ((SavedImage *)NULL);
|
||||||
|
else {
|
||||||
|
SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
|
||||||
|
memset((char *)sp, '\0', sizeof(SavedImage));
|
||||||
|
|
||||||
|
if (CopyFrom != NULL) {
|
||||||
|
memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make our own allocated copies of the heap fields in the
|
||||||
|
* copied record. This guards against potential aliasing
|
||||||
|
* problems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* first, the local color map */
|
||||||
|
if (sp->ImageDesc.ColorMap != NULL) {
|
||||||
|
sp->ImageDesc.ColorMap = GifMakeMapObject(
|
||||||
|
CopyFrom->ImageDesc.ColorMap->ColorCount,
|
||||||
|
CopyFrom->ImageDesc.ColorMap->Colors);
|
||||||
|
if (sp->ImageDesc.ColorMap == NULL) {
|
||||||
|
FreeLastSavedImage(GifFile);
|
||||||
|
return (SavedImage *)(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next, the raster */
|
||||||
|
sp->RasterBits = (unsigned char *)reallocarray(NULL,
|
||||||
|
(CopyFrom->ImageDesc.Height *
|
||||||
|
CopyFrom->ImageDesc.Width),
|
||||||
|
sizeof(GifPixelType));
|
||||||
|
if (sp->RasterBits == NULL) {
|
||||||
|
FreeLastSavedImage(GifFile);
|
||||||
|
return (SavedImage *)(NULL);
|
||||||
|
}
|
||||||
|
memcpy(sp->RasterBits, CopyFrom->RasterBits,
|
||||||
|
sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
|
||||||
|
CopyFrom->ImageDesc.Width);
|
||||||
|
|
||||||
|
/* finally, the extension blocks */
|
||||||
|
if (sp->ExtensionBlocks != NULL) {
|
||||||
|
sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
|
||||||
|
CopyFrom->ExtensionBlockCount,
|
||||||
|
sizeof(ExtensionBlock));
|
||||||
|
if (sp->ExtensionBlocks == NULL) {
|
||||||
|
FreeLastSavedImage(GifFile);
|
||||||
|
return (SavedImage *)(NULL);
|
||||||
|
}
|
||||||
|
memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
|
||||||
|
sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GifFreeSavedImages(GifFileType *GifFile)
|
||||||
|
{
|
||||||
|
SavedImage *sp;
|
||||||
|
|
||||||
|
if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (sp = GifFile->SavedImages;
|
||||||
|
sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
|
||||||
|
if (sp->ImageDesc.ColorMap != NULL) {
|
||||||
|
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||||
|
sp->ImageDesc.ColorMap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp->RasterBits != NULL)
|
||||||
|
free((char *)sp->RasterBits);
|
||||||
|
|
||||||
|
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||||
|
}
|
||||||
|
free((char *)GifFile->SavedImages);
|
||||||
|
GifFile->SavedImages = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end */
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#define SIZE_MAX ((size_t) - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
|
||||||
|
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
|
||||||
|
*/
|
||||||
|
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
|
||||||
|
|
||||||
|
void *
|
||||||
|
reallocarray(void *optr, size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||||
|
nmemb > 0 && SIZE_MAX / nmemb < size) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return realloc(optr, size * nmemb);
|
||||||
|
}
|
|
@ -0,0 +1,330 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
quantize.c - quantize a high resolution image into lower one
|
||||||
|
|
||||||
|
Based on: "Color Image Quantization for frame buffer Display", by
|
||||||
|
Paul Heckbert SIGGRAPH 1982 page 297-307.
|
||||||
|
|
||||||
|
This doesn't really belong in the core library, was undocumented,
|
||||||
|
and was removed in 4.2. Then it turned out some client apps were
|
||||||
|
actually using it, so it was restored in 5.0.
|
||||||
|
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "gif_lib.h"
|
||||||
|
#include "gif_lib_private.h"
|
||||||
|
|
||||||
|
#define ABS(x) ((x) > 0 ? (x) : (-(x)))
|
||||||
|
|
||||||
|
#define COLOR_ARRAY_SIZE 32768
|
||||||
|
#define BITS_PER_PRIM_COLOR 5
|
||||||
|
#define MAX_PRIM_COLOR 0x1f
|
||||||
|
|
||||||
|
static int SortRGBAxis;
|
||||||
|
|
||||||
|
typedef struct QuantizedColorType {
|
||||||
|
GifByteType RGB[3];
|
||||||
|
GifByteType NewColorIndex;
|
||||||
|
long Count;
|
||||||
|
struct QuantizedColorType *Pnext;
|
||||||
|
} QuantizedColorType;
|
||||||
|
|
||||||
|
typedef struct NewColorMapType {
|
||||||
|
GifByteType RGBMin[3], RGBWidth[3];
|
||||||
|
unsigned int NumEntries; /* # of QuantizedColorType in linked list below */
|
||||||
|
unsigned long Count; /* Total number of pixels in all the entries */
|
||||||
|
QuantizedColorType *QuantizedColors;
|
||||||
|
} NewColorMapType;
|
||||||
|
|
||||||
|
static int SubdivColorMap(NewColorMapType * NewColorSubdiv,
|
||||||
|
unsigned int ColorMapSize,
|
||||||
|
unsigned int *NewColorMapSize);
|
||||||
|
static int SortCmpRtn(const void *Entry1, const void *Entry2);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Quantize high resolution image into lower one. Input image consists of a
|
||||||
|
2D array for each of the RGB colors with size Width by Height. There is no
|
||||||
|
Color map for the input. Output is a quantized image with 2D array of
|
||||||
|
indexes into the output color map.
|
||||||
|
Note input image can be 24 bits at the most (8 for red/green/blue) and
|
||||||
|
the output has 256 colors at the most (256 entries in the color map.).
|
||||||
|
ColorMapSize specifies size of color map up to 256 and will be updated to
|
||||||
|
real size before returning.
|
||||||
|
Also non of the parameter are allocated by this routine.
|
||||||
|
This function returns GIF_OK if successful, GIF_ERROR otherwise.
|
||||||
|
******************************************************************************/
|
||||||
|
int
|
||||||
|
GifQuantizeBuffer(unsigned int Width,
|
||||||
|
unsigned int Height,
|
||||||
|
int *ColorMapSize,
|
||||||
|
GifByteType * RedInput,
|
||||||
|
GifByteType * GreenInput,
|
||||||
|
GifByteType * BlueInput,
|
||||||
|
GifByteType * OutputBuffer,
|
||||||
|
GifColorType * OutputColorMap) {
|
||||||
|
|
||||||
|
unsigned int Index, NumOfEntries;
|
||||||
|
int i, j, MaxRGBError[3];
|
||||||
|
unsigned int NewColorMapSize;
|
||||||
|
long Red, Green, Blue;
|
||||||
|
NewColorMapType NewColorSubdiv[256];
|
||||||
|
QuantizedColorType *ColorArrayEntries, *QuantizedColor;
|
||||||
|
|
||||||
|
ColorArrayEntries = (QuantizedColorType *)malloc(
|
||||||
|
sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE);
|
||||||
|
if (ColorArrayEntries == NULL) {
|
||||||
|
return GIF_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
|
||||||
|
ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR);
|
||||||
|
ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) &
|
||||||
|
MAX_PRIM_COLOR;
|
||||||
|
ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
|
||||||
|
ColorArrayEntries[i].Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sample the colors and their distribution: */
|
||||||
|
for (i = 0; i < (int)(Width * Height); i++) {
|
||||||
|
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||||
|
(2 * BITS_PER_PRIM_COLOR)) +
|
||||||
|
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||||
|
BITS_PER_PRIM_COLOR) +
|
||||||
|
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||||
|
ColorArrayEntries[Index].Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put all the colors in the first entry of the color map, and call the
|
||||||
|
* recursive subdivision process. */
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
NewColorSubdiv[i].QuantizedColors = NULL;
|
||||||
|
NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
NewColorSubdiv[i].RGBMin[j] = 0;
|
||||||
|
NewColorSubdiv[i].RGBWidth[j] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the non empty entries in the color table and chain them: */
|
||||||
|
for (i = 0; i < COLOR_ARRAY_SIZE; i++)
|
||||||
|
if (ColorArrayEntries[i].Count > 0)
|
||||||
|
break;
|
||||||
|
QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
|
||||||
|
NumOfEntries = 1;
|
||||||
|
while (++i < COLOR_ARRAY_SIZE)
|
||||||
|
if (ColorArrayEntries[i].Count > 0) {
|
||||||
|
QuantizedColor->Pnext = &ColorArrayEntries[i];
|
||||||
|
QuantizedColor = &ColorArrayEntries[i];
|
||||||
|
NumOfEntries++;
|
||||||
|
}
|
||||||
|
QuantizedColor->Pnext = NULL;
|
||||||
|
|
||||||
|
NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */
|
||||||
|
NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */
|
||||||
|
NewColorMapSize = 1;
|
||||||
|
if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) !=
|
||||||
|
GIF_OK) {
|
||||||
|
free((char *)ColorArrayEntries);
|
||||||
|
return GIF_ERROR;
|
||||||
|
}
|
||||||
|
if (NewColorMapSize < *ColorMapSize) {
|
||||||
|
/* And clear rest of color map: */
|
||||||
|
for (i = NewColorMapSize; i < *ColorMapSize; i++)
|
||||||
|
OutputColorMap[i].Red = OutputColorMap[i].Green =
|
||||||
|
OutputColorMap[i].Blue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Average the colors in each entry to be the color to be used in the
|
||||||
|
* output color map, and plug it into the output color map itself. */
|
||||||
|
for (i = 0; i < NewColorMapSize; i++) {
|
||||||
|
if ((j = NewColorSubdiv[i].NumEntries) > 0) {
|
||||||
|
QuantizedColor = NewColorSubdiv[i].QuantizedColors;
|
||||||
|
Red = Green = Blue = 0;
|
||||||
|
while (QuantizedColor) {
|
||||||
|
QuantizedColor->NewColorIndex = i;
|
||||||
|
Red += QuantizedColor->RGB[0];
|
||||||
|
Green += QuantizedColor->RGB[1];
|
||||||
|
Blue += QuantizedColor->RGB[2];
|
||||||
|
QuantizedColor = QuantizedColor->Pnext;
|
||||||
|
}
|
||||||
|
OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||||
|
OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||||
|
OutputColorMap[i].Blue = (Blue << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally scan the input buffer again and put the mapped index in the
|
||||||
|
* output buffer. */
|
||||||
|
MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
|
||||||
|
for (i = 0; i < (int)(Width * Height); i++) {
|
||||||
|
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||||
|
(2 * BITS_PER_PRIM_COLOR)) +
|
||||||
|
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||||
|
BITS_PER_PRIM_COLOR) +
|
||||||
|
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||||
|
Index = ColorArrayEntries[Index].NewColorIndex;
|
||||||
|
OutputBuffer[i] = Index;
|
||||||
|
if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
|
||||||
|
MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
|
||||||
|
if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
|
||||||
|
MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
|
||||||
|
if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
|
||||||
|
MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr,
|
||||||
|
"Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
|
||||||
|
MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
free((char *)ColorArrayEntries);
|
||||||
|
|
||||||
|
*ColorMapSize = NewColorMapSize;
|
||||||
|
|
||||||
|
return GIF_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
Routine to subdivide the RGB space recursively using median cut in each
|
||||||
|
axes alternatingly until ColorMapSize different cubes exists.
|
||||||
|
The biggest cube in one dimension is subdivide unless it has only one entry.
|
||||||
|
Returns GIF_ERROR if failed, otherwise GIF_OK.
|
||||||
|
*******************************************************************************/
|
||||||
|
static int
|
||||||
|
SubdivColorMap(NewColorMapType * NewColorSubdiv,
|
||||||
|
unsigned int ColorMapSize,
|
||||||
|
unsigned int *NewColorMapSize) {
|
||||||
|
|
||||||
|
int MaxSize;
|
||||||
|
unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor;
|
||||||
|
long Sum, Count;
|
||||||
|
QuantizedColorType *QuantizedColor, **SortArray;
|
||||||
|
|
||||||
|
while (ColorMapSize > *NewColorMapSize) {
|
||||||
|
/* Find candidate for subdivision: */
|
||||||
|
MaxSize = -1;
|
||||||
|
for (i = 0; i < *NewColorMapSize; i++) {
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) &&
|
||||||
|
(NewColorSubdiv[i].NumEntries > 1)) {
|
||||||
|
MaxSize = NewColorSubdiv[i].RGBWidth[j];
|
||||||
|
Index = i;
|
||||||
|
SortRGBAxis = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaxSize == -1)
|
||||||
|
return GIF_OK;
|
||||||
|
|
||||||
|
/* Split the entry Index into two along the axis SortRGBAxis: */
|
||||||
|
|
||||||
|
/* Sort all elements in that entry along the given axis and split at
|
||||||
|
* the median. */
|
||||||
|
SortArray = (QuantizedColorType **)malloc(
|
||||||
|
sizeof(QuantizedColorType *) *
|
||||||
|
NewColorSubdiv[Index].NumEntries);
|
||||||
|
if (SortArray == NULL)
|
||||||
|
return GIF_ERROR;
|
||||||
|
for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
|
||||||
|
j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
|
||||||
|
j++, QuantizedColor = QuantizedColor->Pnext)
|
||||||
|
SortArray[j] = QuantizedColor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because qsort isn't stable, this can produce differing
|
||||||
|
* results for the order of tuples depending on platform
|
||||||
|
* details of how qsort() is implemented.
|
||||||
|
*
|
||||||
|
* We mitigate this problem by sorting on all three axes rather
|
||||||
|
* than only the one specied by SortRGBAxis; that way the instability
|
||||||
|
* can only become an issue if there are multiple color indices
|
||||||
|
* referring to identical RGB tuples. Older versions of this
|
||||||
|
* sorted on only the one axis.
|
||||||
|
*/
|
||||||
|
qsort(SortArray, NewColorSubdiv[Index].NumEntries,
|
||||||
|
sizeof(QuantizedColorType *), SortCmpRtn);
|
||||||
|
|
||||||
|
/* Relink the sorted list into one: */
|
||||||
|
for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
|
||||||
|
SortArray[j]->Pnext = SortArray[j + 1];
|
||||||
|
SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL;
|
||||||
|
NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
|
||||||
|
free((char *)SortArray);
|
||||||
|
|
||||||
|
/* Now simply add the Counts until we have half of the Count: */
|
||||||
|
Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count;
|
||||||
|
NumEntries = 1;
|
||||||
|
Count = QuantizedColor->Count;
|
||||||
|
while (QuantizedColor->Pnext != NULL &&
|
||||||
|
(Sum -= QuantizedColor->Pnext->Count) >= 0 &&
|
||||||
|
QuantizedColor->Pnext->Pnext != NULL) {
|
||||||
|
QuantizedColor = QuantizedColor->Pnext;
|
||||||
|
NumEntries++;
|
||||||
|
Count += QuantizedColor->Count;
|
||||||
|
}
|
||||||
|
/* Save the values of the last color of the first half, and first
|
||||||
|
* of the second half so we can update the Bounding Boxes later.
|
||||||
|
* Also as the colors are quantized and the BBoxes are full 0..255,
|
||||||
|
* they need to be rescaled.
|
||||||
|
*/
|
||||||
|
MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */
|
||||||
|
/* coverity[var_deref_op] */
|
||||||
|
MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */
|
||||||
|
MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||||
|
MinColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||||
|
|
||||||
|
/* Partition right here: */
|
||||||
|
NewColorSubdiv[*NewColorMapSize].QuantizedColors =
|
||||||
|
QuantizedColor->Pnext;
|
||||||
|
QuantizedColor->Pnext = NULL;
|
||||||
|
NewColorSubdiv[*NewColorMapSize].Count = Count;
|
||||||
|
NewColorSubdiv[Index].Count -= Count;
|
||||||
|
NewColorSubdiv[*NewColorMapSize].NumEntries =
|
||||||
|
NewColorSubdiv[Index].NumEntries - NumEntries;
|
||||||
|
NewColorSubdiv[Index].NumEntries = NumEntries;
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
|
||||||
|
NewColorSubdiv[Index].RGBMin[j];
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
|
||||||
|
NewColorSubdiv[Index].RGBWidth[j];
|
||||||
|
}
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor;
|
||||||
|
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
|
||||||
|
|
||||||
|
NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
|
||||||
|
MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
|
||||||
|
|
||||||
|
(*NewColorMapSize)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GIF_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Routine called by qsort to compare two entries.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
SortCmpRtn(const void *Entry1,
|
||||||
|
const void *Entry2) {
|
||||||
|
QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1));
|
||||||
|
QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2));
|
||||||
|
|
||||||
|
/* sort on all axes of the color space! */
|
||||||
|
int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256
|
||||||
|
+ entry1->RGB[(SortRGBAxis+1) % 3] * 256
|
||||||
|
+ entry1->RGB[(SortRGBAxis+2) % 3];
|
||||||
|
int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256
|
||||||
|
+ entry2->RGB[(SortRGBAxis+1) % 3] * 256
|
||||||
|
+ entry2->RGB[(SortRGBAxis+2) % 3];
|
||||||
|
|
||||||
|
return hash1 - hash2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end */
|
Loading…
Reference in New Issue