home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR2
/
DVPG30FS.ZIP
/
JJRDGIF.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-03
|
19KB
|
606 lines
/*
* jrdgif.c
*
* Copyright (C) 1991, 1992, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains routines to read input images in GIF format.
*
* These routines may need modification for non-Unix environments or
* specialized applications. As they stand, they assume input from
* an ordinary stdio stream. They further assume that reading begins
* at the start of the file; input_init may need work if the
* user interface has already read some data (e.g., to determine that
* the file is indeed GIF format).
*
* These routines are invoked via the methods get_input_row
* and input_init/term.
*/
/*
* This code is loosely based on giftoppm from the PBMPLUS distribution
* of Feb. 1991. That file contains the following copyright notice:
* +-------------------------------------------------------------------+
* | Copyright 1990, David Koblas. |
* | Permission to use, copy, modify, and distribute this software |
* | and its documentation for any purpose and without fee is hereby |
* | granted, provided that the above copyright notice appear in all |
* | copies and that both that copyright notice and this permission |
* | notice appear in supporting documentation. This software is |
* | provided "as is" without express or implied warranty. |
* +-------------------------------------------------------------------+
*
* We are also required to state that
* "The Graphics Interchange Format(c) is the Copyright property of
* CompuServe Incorporated. GIF(sm) is a Service Mark property of
* CompuServe Incorporated."
*/
/*#include "jinclude.h"*/
#include "extern.h" /* jpeg viewer vars + includes jinclude.h */
#ifdef GIF_SUPPORTED
JSAMPARRAY gif_colormap; /* colormap pointer */
int /* vars to aid viewing of interlaced GIF */
step_size, /* increment for current pass */
index, /* current index ie the n'th count for pass y */
pass_num; /* the current pass */
#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */
#define NUMCOLORS 3 /* # of colors */
#define CM_RED 0 /* color component numbers */
#define CM_GREEN 1
#define CM_BLUE 2
#define MAX_LZW_BITS 12 /* maximum LZW code size */
#define LZW_TABLE_SIZE (1<<MAX_LZW_BITS) /* # of possible LZW symbols */
/* 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 */
/* Eric addition - storage for 1 row of GIF */
static JSAMPIMAGE row_ptr;
static decompress_info_ptr cinfo_global;
FILE * infile;
static int temp_var;
char *fetch_buf;
#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
/* Static vars for GetCode and LZWReadByte */
static char code_buf[256+4]; /* current input data block */
static int last_byte; /* # of bytes in code_buf */
static int last_bit; /* # of bits in code_buf */
static int cur_bit; /* next bit index to read */
static boolean out_of_blocks; /* TRUE if hit terminator data block */
static int input_code_size; /* codesize given in GIF file */
static int clear_code,end_code; /* values for Clear and End codes */
static int code_size; /* current actual code size */
static int limit_code; /* 2^code_size */
static int max_code; /* first unused code value */
static boolean first_time; /* flags first call to LZWReadByte */
/* LZW decompression tables:
* symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)
* symbol_tail[K] = suffix byte of any LZW symbol K (0..LZW_TABLE_SIZE-1)
* Note that entries 0..end_code of the above tables are not used,
* since those symbols represent raw bytes or special codes.
*
* The stack represents the not-yet-used expansion of the last LZW symbol.
* In the worst case, a symbol could expand to as many bytes as there are
* LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.
* (This is conservative since that number includes the raw-byte symbols.)
*
* The tables are allocated from FAR heap space since they would use up
* rather a lot of the near data space in a PC.
*/
static UINT16 *symbol_head; /* => table of prefix symbols */
static UINT8 *symbol_tail; /* => table of suffix bytes */
static UINT8 *symbol_stack; /* stack for symbol expansions */
static UINT8 *sp; /* stack pointer */
/* Static state for interlaced image processing */
static boolean is_interlaced; /* TRUE if have interlaced image */
/* Forward declarations */
METHODDEF void load_interlaced_image PP((decompress_info_ptr cinfo, JSAMPIMAGE pixel_row));
/* declarations */
int near ReadByte (void);
int near GetCode (void);
int near LZWReadByte (void);
void near DoExtension (void);
void near SkipDataBlocks (void);
int near GetDataBlock (void);
int near ReadByte (void) /* was LOCAL */
/* Read next byte from GIF file */
{
if ((temp_var = getc(infile)) == EOF)
ERREXIT(cinfo_global->emethods, "Premature EOF in GIF file");
return temp_var;
}
LOCAL int near
GetDataBlock ()
/* Read a GIF data block, which has a leading count byte */
/* A zero-length block marks the end of a data block sequence */
{
/* use the fact that the data is in temp_var */
ReadByte();
if (temp_var > 0) {
if (! ReadOK(cinfo_global->input_file, fetch_buf, temp_var))
ERREXIT(cinfo_global->emethods, "Premature EOF in GIF file");
}
return temp_var;
}
LOCAL void near
SkipDataBlocks (void)
/* Skip a series of data blocks, until a block terminator is found */
{
char buf[256];
fetch_buf = buf; /* set pointer to temp buffer */
while (GetDataBlock() > 0)
/* skip */;
}
LOCAL void
ReInitLZW (void)
/* (Re)initialize LZW state; shared code for startup and Clear processing */
{
code_size = input_code_size+1;
limit_code = clear_code << 1; /* 2^code_size */
max_code = clear_code + 2; /* first unused code value */
sp = symbol_stack; /* init stack to empty */
}
LOCAL void
InitLZWCode (void)
/* Initialize for a series of LZWReadByte (and hence GetCode) calls */
{
/* GetCode initialization */
last_byte = 2; /* make safe to "recopy last two bytes" */
last_bit = 0; /* nothing in the buffer */
cur_bit = 0; /* force buffer load on first call */
out_of_blocks = FALSE;
/* LZWReadByte initialization */
clear_code = 1 << input_code_size; /* compute special code values */
end_code = clear_code + 1; /* note that these do not change */
first_time = TRUE;
ReInitLZW();
}
LOCAL int near
GetCode (void)
/* Fetch the next code_size bits from the GIF data */
/* We assume code_size is less than 16 */
{
register INT32 accum;
int offs, ret, count;
if ( (cur_bit+code_size) > last_bit) {
/* Time to reload the buffer */
if (out_of_blocks) {
WARNMS(cinfo_global->emethods, "Ran out of GIF bits");
return end_code; /* fake something useful */
}
/* preserve last two bytes of what we have -- assume code_size <= 16 */
code_buf[0] = code_buf[last_byte-2];
code_buf[1] = code_buf[last_byte-1];
/* Load more bytes; set flag if we reach the terminator block */
fetch_buf = &code_buf[2];
if ((count = GetDataBlock()) == 0) {
out_of_blocks = TRUE;
WARNMS(cinfo_global->emethods, "Ran out of GIF bits");
return end_code; /* fake something useful */
}
/* Reset counters */
cur_bit = (cur_bit - last_bit) + 16;
last_byte = 2 + count;
last_bit = last_byte * 8;
}
/* Form up next 24 bits in accum */
offs = cur_bit >> 3; /* byte containing cur_bit */
#ifdef CHAR_IS_UNSIGNED
accum = code_buf[offs+2];
accum <<= 8;
accum |= code_buf[offs+1];
accum <<= 8;
accum |= code_buf[offs];
#else
accum = code_buf[offs+2] & 0xFF;
accum <<= 8;
accum |= code_buf[offs+1] & 0xFF;
accum <<= 8;
accum |= code_buf[offs] & 0xFF;
#endif
/* Right-align cur_bit in accum, then mask off desired number of bits */
accum >>= (cur_bit & 7);
ret = ((int) accum) & ((1 << code_size) - 1);
cur_bit += code_size;
return ret;
}
LOCAL int near
LZWReadByte (void)
/* Read an LZW-compressed byte */
{
static int oldcode; /* previous LZW symbol */
static int firstcode; /* first byte of oldcode's expansion */
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 (first_time) goto first_time_called;
/* If any codes are stacked from a previously read symbol, return them */
if (sp > symbol_stack) goto early_return;
/* Time to read a new symbol */
code = GetCode();
if (code == clear_code) goto got_clear_code;
if (code == end_code) goto got_end_code;
/* Got normal raw byte or LZW symbol */
incode = code; /* save for a moment */
if (code >= max_code) { /* special case for not-yet-defined symbol */
/* code == max_code is OK; anything bigger is bad data */
if (code > max_code) {
WARNMS(cinfo_global->emethods, "Corrupt data in GIF file");
incode = 0; /* prevent creation of loops in symbol table */
}
*sp++ = (UINT8) firstcode; /* it will be defined as oldcode/firstcode */
code = oldcode;
}
/* If it's a symbol, expand it into the stack */
while (code >= clear_code) {
*sp++ = symbol_tail[code]; /* tail of symbol: a simple byte value */
code = symbol_head[code]; /* head of symbol: another LZW symbol */
}
/* At this point code just represents a raw byte */
firstcode = code; /* save for possible future use */
/* If there's room in table, */
if ((code = max_code) < LZW_TABLE_SIZE) {
/* Define a new symbol = prev sym + head of this sym's expansion */
symbol_head[code] = oldcode;
symbol_tail[code] = (UINT8) firstcode;
max_code++;
/* Is it time to increase code_size? */
if ((max_code >= limit_code) && (code_size < MAX_LZW_BITS)) {
code_size++;
limit_code <<= 1; /* keep equal to 2^code_size */
}
}
oldcode = incode; /* save last input symbol for future use */
return firstcode; /* return first byte of symbol's expansion */
early_return:
return (int) *(--sp);
first_time_called:
first_time = FALSE;
/* code = clear_code; /* enables sharing code with Clear case */
got_clear_code:
/* Reinit static state, swallow any extra Clear codes, and */
/* return next code, which is expected to be a raw byte. */
ReInitLZW();
do {
code = GetCode();
} while (code == clear_code);
if (code > clear_code) { /* make sure it is a raw byte */
WARNMS(cinfo_global->emethods, "Corrupt data in GIF file");
code = 0; /* use something valid */
}
firstcode = oldcode = code; /* make firstcode, oldcode valid! */
return code;
got_end_code:
/* Skip the rest of the image, unless GetCode already read terminator */
if (! out_of_blocks) {
SkipDataBlocks();
out_of_blocks = TRUE;
}
/* Complain that there's not enough data */
WARNMS(cinfo_global->emethods, "Premature end of GIF image");
/* Pad data with 0's */
return 0; /* fake something usable */
}
LOCAL void
ReadColorMap (decompress_info_ptr cinfo, int cmaplen, JSAMPARRAY cmap)
/* Read a GIF colormap */
{
int i;
for (i = 0; i < cmaplen; i++) {
cmap[CM_RED][i] = (JSAMPLE) ReadByte();
cmap[CM_GREEN][i] = (JSAMPLE) ReadByte();
cmap[CM_BLUE][i] = (JSAMPLE) ReadByte();
}
}
LOCAL void near
DoExtension (void)
/* Process an extension block */
/* Currently we ignore 'em all */
{
int extlabel;
/* Read extension label byte */
extlabel = ReadByte();
TRACEMS1(cinfo_global->emethods, 1, "Ignoring GIF extension block of type 0x%02x",
extlabel);
/* Skip the data block(s) associated with the extension */
SkipDataBlocks();
}
/*
* Read the file header; return image size and component count.
*/
METHODDEF void
input_init (decompress_info_ptr cinfo)
{
char hdrbuf[10]; /* workspace for reading control blocks */
UINT16 width, height; /* image dimensions */
int colormaplen, aspectRatio;
int c;
/* Allocate space to store the colormap */
gif_colormap = (*cinfo->emethods->alloc_small_sarray)
((long) MAXCOLORMAPSIZE, (long) NUMCOLORS);
/* Read and verify GIF Header */
if (! ReadOK(cinfo->input_file, hdrbuf, 6))
ERREXIT(cinfo->emethods, "Not a GIF file");
if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')
ERREXIT(cinfo->emethods, "Not a GIF file");
/* Check for expected version numbers.
* If unknown version, give warning and try to process anyway;
* this is per recommendation in GIF89a standard.
*/
if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&
(hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))
TRACEMS3(cinfo->emethods, 1,
"Warning: unexpected GIF version number '%c%c%c'",
hdrbuf[3], hdrbuf[4], hdrbuf[5]);
/* Read and decipher Logical Screen Descriptor */
if (! ReadOK(cinfo->input_file, hdrbuf, 7))
ERREXIT(cinfo->emethods, "Premature EOF in GIF file");
width = LM_to_uint(hdrbuf[0],hdrbuf[1]);
height = LM_to_uint(hdrbuf[2],hdrbuf[3]);
colormaplen = 2 << (hdrbuf[4] & 0x07);
/* we ignore the color resolution, sort flag, and background color index */
aspectRatio = hdrbuf[6] & 0xFF;
if (aspectRatio != 0 && aspectRatio != 49)
TRACEMS(cinfo->emethods, 1, "Warning: nonsquare pixels in input");
/* Read global colormap if header indicates it is present */
if (BitSet(hdrbuf[4], COLORMAPFLAG))
ReadColorMap(cinfo, colormaplen, gif_colormap);
/* Scan until we reach start of desired image.
* We don't currently support skipping images, but could add it easily.
*/
for (;;) {
c = ReadByte();
if (c == ';') /* GIF terminator?? */
ERREXIT(cinfo->emethods, "Too few images in GIF file");
if (c == '!') { /* Extension */
DoExtension();
continue;
}
if (c != ',') { /* Not an image separator? */
TRACEMS1(cinfo->emethods, 1, "Bogus input char 0x%02x, ignoring", c);
continue;
}
/* Read and decipher Local Image Descriptor */
if (! ReadOK(cinfo->input_file, hdrbuf, 9))
ERREXIT(cinfo->emethods, "Premature EOF in GIF file");
/* we ignore top/left position info, also sort flag */
width = LM_to_uint(hdrbuf[4],hdrbuf[5]);
height = LM_to_uint(hdrbuf[6],hdrbuf[7]);
is_interlaced = BitSet(hdrbuf[8], INTERLACE);
/* Read local colormap if header indicates it is present */
/* Note: if we wanted to support skipping images, */
/* we'd need to skip rather than read colormap for ignored images */
if (BitSet(hdrbuf[8], COLORMAPFLAG)) {
colormaplen = 2 << (hdrbuf[8] & 0x07);
ReadColorMap(cinfo, colormaplen, gif_colormap);
}
input_code_size = ReadByte(); /* get minimum-code-size byte */
if (input_code_size < 2 || input_code_size >= MAX_LZW_BITS)
ERREXIT1(cinfo->emethods, "Bogus codesize %d", input_code_size);
/* Reached desired image, so break out of loop */
/* If we wanted to skip this image, */
/* we'd call SkipDataBlocks and then continue the loop */
break;
}
/* Prepare to read selected image: first initialize LZW decompressor */
symbol_head = (*cinfo->emethods->alloc_small)
(LZW_TABLE_SIZE * SIZEOF(UINT16));
/* symbol_tail = (UINT8 FAR *) (*cinfo->emethods->alloc_medium)
(LZW_TABLE_SIZE * SIZEOF(UINT8));
symbol_stack = (UINT8 FAR *) (*cinfo->emethods->alloc_medium)
(LZW_TABLE_SIZE * SIZEOF(UINT8));
*/
symbol_tail = (*cinfo->emethods->alloc_small)
(LZW_TABLE_SIZE * SIZEOF(UINT8));
symbol_stack = (*cinfo->emethods->alloc_small)
(LZW_TABLE_SIZE * SIZEOF(UINT8));
InitLZWCode();
/*
* If image is interlaced, we read it into a full-size sample array,
* decompressing as we go; then get_input_row selects rows from the
* sample array in the proper order.
*/
if (is_interlaced) {
row_ordering = INTERLACED;
cinfo->methods->get_input_row = load_interlaced_image;
/* setup for an interlaced GIF */
step_size = 8;
index = -8; /* make sure it counts to 0 the first time */
pass_num = 0;
}
/* Return info about the image. */
cinfo->colormap = gif_colormap;
cinfo->color_map_present = 1;
cinfo->actual_number_of_colors = 256;
cinfo->color_out_comps = NUMCOLORS;
cinfo->final_out_comps = NUMCOLORS;
cinfo->out_color_space = CS_RGB; /* indicate as color */
cinfo->image_width = width;
cinfo->image_height = height;
cinfo->data_precision = 8; /* always, even if 12-bit JSAMPLEs */
cinfo->final_out_comps = 1; /* this is a color pallet picture - always */
TRACEMS3(cinfo->emethods, 1, "%ux%ux%d GIF image",
(unsigned int) width, (unsigned int) height, colormaplen);
}
/*
* Read one row of pixels.
* This version is used for noninterlaced GIF images:
* we read directly from the GIF file.
*/
METHODDEF void
get_input_row (decompress_info_ptr cinfo, JSAMPIMAGE pixel_row)
{
register JSAMPROW ptr0;
register int col;
ptr0 = pixel_row[0][0];
for (col = picture_x_size; col > 0; col--)
*ptr0++ = LZWReadByte();
/* data_ref_ptr = *((*cinfo->emethods->access_big_sarray) (raw_pic_ptr, read_row++, TRUE));
_fmemcpy((void FAR *) data_ref_ptr, (void FAR *) data_ptr, (size_t) bytes_per_line);
}
draw_line(gr_row++, data_ptr, line_buffer_ptr);
*/
}
/*
* Read one row of pixels.
* This version is used for the calls to get_input_row when
* reading an interlaced image
*/
METHODDEF void
load_interlaced_image (decompress_info_ptr cinfo, JSAMPIMAGE pixel_row)
{
JSAMPROW ptr0;
int col;
ptr0 = pixel_row[0][0];
for (col = picture_x_size; col > 0; col--)
*ptr0++ = LZWReadByte();
index += step_size;
gr_row = index;
if (index >= picture_y_size)
switch(++pass_num){
case 1:
index = gr_row = 4;
break;
case 2:
index = gr_row = 2;
step_size = 4;
break;
case 3:
index = gr_row = 1;
step_size = 2;
break;
}
}
/*
* The method selection routine for GIF format input.
* Note that this must be called by the user interface before calling
* jpeg_compress. If multiple input formats are supported, the
* user interface is responsible for discovering the file format and
* calling the appropriate method selection routine.
*/
GLOBAL void
selrgif (decompress_info_ptr cinfo)
{
/* new to speed things up */
cinfo_global = cinfo;
infile = cinfo->input_file;
cinfo->num_components = 1; /* defaults to make GIF work */
cinfo->jpeg_color_space = CS_RGB; /* always assume color - mainly signals that the color pallet has 3 components */
cinfo->out_color_space = CS_RGB; /* ie default to color not grayscale */
cinfo->methods->read_file_header = input_init;
cinfo->methods->get_input_row = get_input_row; /* assume uninterlaced */
}
#endif /* GIF_SUPPORTED */