home *** CD-ROM | disk | FTP | other *** search
- /*
- * gif.c -- read a gif file. scooped from the Linux gif viewer spic by
- * Harm Hanemaayer <hhanemaa@cs.ruu.nl>
- */
-
- #include "ray.h"
- #include "proto.h"
- #include "extern.h"
- #include <string.h>
-
-
- /* Image data is raw byte(s)-per-pixel */
- PRIVATE char *the_data;
-
- #define __memcpy memcpy
- #define __memcpyb memcpy
-
- #define byteindex (bitindex >> 3)
- #define shift (bitindex & 7)
-
-
- PRIVATE byte buffer[258],
- rootsize,
- codesize;
- PRIVATE unsigned long blocklen,
- bitindex,
- code,
- old;
- PRIVATE byte k;
- PRIVATE unsigned long mask,
- CC,
- EOI;
-
- PRIVATE long writebufferindex;
-
- PRIVATE struct {
- unsigned long prefix;
- unsigned long k;
- }
-
- codetable [4096];
-
- PRIVATE unsigned long tablelen;
-
- PRIVATE void
- init_codetable()
- {
- long i;
-
- for (i = 0; i < CC; i++) {
- codetable[i].prefix = 0xFFFF;
- codetable[i].k = i;
- }
-
- for (i = EOI + 1; i < 4096; i++) {
- codetable[i].prefix = 0xFFFF;
- codetable[i].k = 0;
- }
- tablelen = EOI + 1;
- codesize = rootsize + 1;
- mask = (1 << codesize) - 1;
- }
-
- PRIVATE void
- reset_codetable()
- {
- tablelen = EOI + 1;
- codesize = rootsize + 1;
- mask = (1 << codesize) - 1;
- }
-
- PRIVATE char *gifbuf;
-
- PRIVATE void
- bread(char *b, long size, FILE * f)
- {
- PRIVATE char *bufp;
- PRIVATE long bufsize = 0;
-
- if (size > bufsize) {
- long count;
-
- if (bufsize) /* copy remaining bytes to the front */
- __memcpy(gifbuf, bufp, bufsize);
- count = fread(gifbuf + bufsize, 1, BUFFERSIZE - bufsize, f);
- bufsize += count;
- bufp = gifbuf;
- }
- if (size == 1)
- *b = *bufp;
- else
- __memcpy(b, bufp, size);
- bufsize -= size;
- bufp += size;
- }
-
- PRIVATE void
- read_block(FILE * f)
- {
- byte count;
-
- bread(&count, 1, f);
- bread(buffer + 2, count, f);
- blocklen = count + 2;
- }
-
- PRIVATE void
- get_string(unsigned long code, byte *s, unsigned long *len)
- {
- unsigned long i,
- j;
- byte stringbuf[4096];
- long stringlength;
-
- i = 1;
- j = codetable[code].prefix;
- stringbuf[0] = codetable[code].k;
- s[0] = codetable[code].k;
- while (j < 4096) {
- stringbuf[i] = codetable[j].k;
- j = codetable[j].prefix;
- i++;
- }
- stringlength = i;
-
- /* reverse string */
- while (i > 0) {
- s[stringlength - i] = stringbuf[i - 1];
- i--;
- }
- *len = stringlength;
- }
-
- PRIVATE void
- output_string(byte *s, unsigned long len)
- {
- __memcpyb(the_data + writebufferindex, s, len);
-
- writebufferindex += len * 1;/* one byte per pixel */
- }
-
- PRIVATE void
- copystring(unsigned long code, unsigned long prefix, byte k)
- {
- codetable[code].prefix = prefix;
- codetable[code].k = k;
- }
-
- PRIVATE void
- create_picture(FILE * f)
- {
- long quit;
- byte s[4096];
- unsigned long len;
-
- writebufferindex = 0;
- fread(&rootsize, 1, 1, f);
- CC = (1 << rootsize);
- EOI = (1 << rootsize) + 1;
- init_codetable();
- read_block(f);
- bitindex = 16 + codesize; /* Skip first code.. should be CC */
- quit = 0;
-
- for (;;) {
- code = (unsigned long) (((*(unsigned long *) (buffer + byteindex)) >> shift) & mask);
- bitindex += codesize;
- if (code == CC)
- reset_codetable();
- else
- output_string((byte *) (&code), 1);
-
- for (;;) {
- if (bitindex + codesize >= blocklen * 8) { /* New block */
- bitindex -= (blocklen - 2) * 8;
- *(short *) buffer = *(short *) (buffer + blocklen - 2);
- read_block(f);
- }
- old = code;
-
- code = (unsigned long) (((*(unsigned long *) (buffer + byteindex)) >> shift) & mask);
- bitindex += codesize;
- if (code == CC) {
- reset_codetable();
- break;
- }
- if (code == EOI) {
- quit = 1;
- break;
- }
- if (code < tablelen) { /* Code exists in table */
- get_string(code, s, &len);
- output_string(s, len);
- k = s[0];
- copystring(tablelen, old, k);
- tablelen++;
- } else { /* Code does not yet exist */
- get_string(old, s, &len);
- k = s[0];
- copystring(tablelen, old, k);
- s[len++] = k;
- output_string(s, len);
- tablelen++;
- }
-
- if ((tablelen == (1 << codesize)) && (codesize < 12)) {
- codesize++;
- mask = (1 << codesize) - 1;
- }
- }
- if (quit)
- break;
- }
-
- }
-
-
- /* load a gif into a pixmap data structure */
- PUBLIC void
- load_gif(struct pixel_data *image, FILE * f)
- {
- size_t s;
- long i,
- j;
- char buffer[256];
- byte c;
- long gct,
- gct_size,
- lct,
- lct_size;
-
- /* do buffering */
- gifbuf = malloc(BUFFERSIZE * sizeof(char));
-
- CHECK_MEM(gifbuf, "gif buffer");
-
- /* Read Header */
- fread(buffer, 6, 1, f);
- if (memcmp(buffer, "GIF", 3))
- errormsg("File not in GIF format.\n");
-
- /* Read Logical Screen Descriptor (LSD) */
- fread(buffer, 7, 1, f);
-
- c = (byte) buffer[4];
-
- gct = buffer[4] & 128; /* Global color table present ? */
- gct_size = buffer[4] & 7; /* Size of GCT */
-
- /* Read Image Descriptor */
- if (gct) { /* Skip GCT */
- j = 2;
- for (i = 0; i < gct_size; i++)
- j *= 2;
-
- /* Palette data is 256 red, green and blue values (0-63) */
- image->pal = (byte *) malloc(3 * j);
- image->palsize = j;
-
- fread(image->pal, 3 * j, 1, f);
- } else
- image->palsize = 0; /* is this ok? */
-
- fread(buffer, 10, 1, f);
-
- image->imagex = *(unsigned short *) (&(buffer[5]));
- image->imagey = *(unsigned short *) (&(buffer[7]));
-
-
- /* patch from spic 0.6 */
- lct = buffer[9] & 128; /* local color table present ? */
- lct_size = buffer[9] & 7; /* Size of LCT */
- if (lct) { /* Skip LCT */
- j = 2;
- if (lct_size > 0)
- for (i = 0; i < lct_size; i++)
- j *= 2;
-
- image->pal = (byte *) malloc(3 * j);
- image->palsize = j;
-
- fread(image->pal, 3 * j, 1, f);
- }
- s = image->imagex * image->imagey;
- the_data = (byte *) malloc(s);
- CHECK_MEM(the_data, "gif pixels");
-
- create_picture(f);
-
- image->data = the_data;
-
- free(gifbuf);
- }
-
- /* eof */
-