4 * adapted from code by kirk johnson (tuna@athena.mit.edu). most of this
5 * code is unchanged. -- jim frost 12.31.89
11 * routines for reading GIF files
13 * Copyright 1989 Kirk L. Johnson (see the included file
14 * "kljcpyrght.h" for complete copyright information)
22 #define PUSH_PIXEL(p) \
24 if (pstk_idx == PSTK_SIZE) \
25 return GIFIN_ERR_PSO; \
27 pstk[pstk_idx++] = (p); \
31 * push a string (denoted by a code) onto the pixel stack
32 * (returns the code of the first pixel in the string in ps_rslt)
35 int ps_rslt; /* return result */
37 #define GIFIN_PUSH_STRING(code) \
42 while (((unsigned int)ps_code) < STAB_SIZE && prefix[ps_code] != NULL_CODE) \
44 PUSH_PIXEL(extnsn[ps_code]); \
45 ps_code = prefix[ps_code]; \
48 if (((unsigned int)ps_code) >= STAB_SIZE) \
49 return GIFIN_ERR_TAO; \
50 PUSH_PIXEL(extnsn[ps_code]); \
51 ps_rslt = extnsn[ps_code]; \
52 if (((unsigned int)ps_rslt) >= STAB_SIZE) \
53 return GIFIN_ERR_TAO; \
57 * Look up the ascii message coresponding to
60 static char *get_err_string(int errno)
63 for (i=0;gif_err_strings[i].err_no != 0;i++)
65 if (gif_err_strings[i].err_no == errno)
66 return gif_err_strings[i].name;
72 static int interlace_start[4] = /* start line for interlacing */
77 static int interlace_rate[4] = /* rate at which we accelerate vertically */
82 static BYTE file_open = 0; /* status flags */
83 static BYTE image_open = 0;
85 static FILE *ins; /* input stream */
87 static int root_size; /* root code size */
88 static int clr_code; /* clear code */
89 static int eoi_code; /* end of information code */
90 static int code_size; /* current code size */
91 static int code_mask; /* current code mask */
92 static int prev_code; /* previous code */
94 static long work_data; /* working bit buffer */
95 static int work_bits; /* working bit count */
97 static BYTE buf[256]; /* byte buffer */
98 static int buf_cnt; /* byte count */
99 static int buf_idx; /* buffer index */
101 static int table_size; /* string table size */
102 static int prefix[STAB_SIZE]; /* string table : prefixes */
103 static int extnsn[STAB_SIZE]; /* string table : extensions */
105 static BYTE pstk[PSTK_SIZE]; /* pixel stack */
106 static int pstk_idx; /* pixel stack pointer */
109 static int gifin_rast_width; /* raster width */
110 static int gifin_rast_height; /* raster height */
111 static BYTE gifin_g_cmap_flag; /* global colormap flag */
112 static int gifin_g_pixel_bits; /* bits per pixel, global colormap */
113 static int gifin_g_ncolors; /* number of colors, global colormap */
114 static BYTE gifin_g_cmap[3][256]; /* global colormap */
115 static BYTE gifin_g_cmap_sorted; /* global colormap sorted (GIF89a only) */
116 static int gifin_bg_color; /* background color index */
117 static int gifin_color_bits; /* bits of color resolution */
118 static double gifin_aspect; /* pixel aspect ratio (width/height) */
119 static int gifin_version; /* gif file version */
121 static int gifin_img_left; /* image position on raster */
122 static int gifin_img_top; /* image position on raster */
123 static int gifin_img_width; /* image width */
124 static int gifin_img_height; /* image height */
125 static BYTE gifin_l_cmap_flag; /* local colormap flag */
126 static int gifin_l_pixel_bits; /* bits per pixel, local colormap */
127 static int gifin_l_ncolors; /* number of colors, local colormap */
128 static BYTE gifin_l_cmap[3][256]; /* local colormap */
129 static BYTE gifin_interlace_flag; /* interlace image format flag */
132 * open a GIF file, using s as the input stream
135 static int gifin_open_file(FILE *s)
138 /* make sure there isn't already a file open */
140 return GIFIN_ERR_FAO;
142 /* remember that we've got this file open */
146 /* check GIF signature */
147 if (fread(buf, 1, GIF_SIG_LEN, ins) != GIF_SIG_LEN)
148 return GIFIN_ERR_EOF;
150 buf[GIF_SIG_LEN] = '\0';
151 if (strcmp((char *) buf, GIF_SIG) == 0)
152 gifin_version = GIF87a;
153 else if(strcmp((char *) buf, GIF_SIG_89) == 0)
154 gifin_version = GIF89a;
156 return GIFIN_ERR_BAD_SIG;
158 /* read screen descriptor */
159 if (fread(buf, 1, GIF_SD_SIZE, ins) != GIF_SD_SIZE)
160 return GIFIN_ERR_EOF;
162 /* decode screen descriptor */
163 gifin_rast_width = (buf[1] << 8) + buf[0];
164 gifin_rast_height = (buf[3] << 8) + buf[2];
165 gifin_g_cmap_flag = (buf[4] & 0x80) ? 1 : 0;
166 gifin_color_bits = (((int)(buf[4] & 0x70)) >> 4) + 1;
167 gifin_g_pixel_bits = (buf[4] & 0x07) + 1;
168 gifin_bg_color = buf[5];
171 if (gifin_version == GIF87a)
173 if (buf[4] & 0x08 || buf[6] != 0)
174 return GIFIN_ERR_BAD_SD;
178 gifin_g_cmap_sorted = ((buf[4] & 0x08) != 0);
180 gifin_aspect = ((double)buf[6] + 15.0) / 64.0;
183 /* load global colormap */
184 if (gifin_g_cmap_flag)
186 gifin_g_ncolors = (1 << gifin_g_pixel_bits);
188 if ((errno = gifin_load_cmap(gifin_g_cmap, gifin_g_ncolors)) != GIFIN_SUCCESS)
197 return GIFIN_SUCCESS;
202 * open next GIF image in the input stream; returns GIFIN_SUCCESS if
203 * successful. if there are no more images, returns GIFIN_DONE. (might
204 * also return various GIFIN_ERR codes.)
207 static int gifin_open_image()
213 /* make sure there's a file open */
215 return GIFIN_ERR_NFO;
217 /* make sure there isn't already an image open */
219 return GIFIN_ERR_IAO;
221 /* remember that we've got this image open */
224 /* skip over any extension blocks */
227 separator = fgetc(ins);
228 if (separator == GIF_EXTENSION)
230 if ((errno = gifin_skip_extension()) != GIFIN_SUCCESS)
234 while (separator == GIF_EXTENSION);
236 /* check for end of file marker */
237 if (separator == GIF_TERMINATOR)
240 /* make sure we've got an image separator */
241 if (separator != GIF_SEPARATOR)
242 return GIFIN_ERR_BAD_SEP;
244 /* read image descriptor */
245 if (fread(buf, 1, GIF_ID_SIZE, ins) != GIF_ID_SIZE)
246 return GIFIN_ERR_EOF;
248 /* decode image descriptor */
249 gifin_img_left = (buf[1] << 8) + buf[0];
250 gifin_img_top = (buf[3] << 8) + buf[2];
251 gifin_img_width = (buf[5] << 8) + buf[4];
252 gifin_img_height = (buf[7] << 8) + buf[6];
253 gifin_l_cmap_flag = (buf[8] & 0x80) ? 1 : 0;
254 gifin_interlace_flag = (buf[8] & 0x40) ? 1 : 0;
255 gifin_l_pixel_bits = (buf[8] & 0x07) + 1;
257 /* load local colormap */
258 if (gifin_l_cmap_flag)
260 gifin_l_ncolors = (1 << gifin_l_pixel_bits);
262 if ((errno = gifin_load_cmap(gifin_l_cmap, gifin_l_ncolors)) != GIFIN_SUCCESS)
270 /* initialize raster data stream decoder */
271 root_size = fgetc(ins);
272 clr_code = 1 << root_size;
273 eoi_code = clr_code + 1;
274 code_size = root_size + 1;
275 code_mask = (1 << code_size) - 1;
281 /* initialize string table */
282 for (i=0; i<STAB_SIZE; i++)
284 prefix[i] = NULL_CODE;
288 /* initialize pixel stack */
292 return GIFIN_SUCCESS;
296 * try to read next pixel from the raster, return result in *pel
299 static int gifin_get_pixel(pel)
307 /* decode until there are some pixels on the pixel stack */
308 while (pstk_idx == 0)
310 /* load bytes until we have enough bits for another code */
311 while (work_bits < code_size)
313 if (buf_idx == buf_cnt)
315 /* read a new data block */
316 if ((errno = gifin_read_data_block()) != GIFIN_SUCCESS)
320 return GIFIN_ERR_EOD;
323 work_data |= ((long) buf[buf_idx++]) << work_bits;
327 /* get the next code */
328 code = work_data & code_mask;
329 work_data >>= code_size;
330 work_bits -= code_size;
332 /* interpret the code */
333 if (code == clr_code)
335 /* reset decoder stream */
336 code_size = root_size + 1;
337 code_mask = (1 << code_size) - 1;
338 prev_code = NULL_CODE;
339 table_size = eoi_code + 1;
341 else if (code == eoi_code)
343 /* Ooops! no more pixels */
344 return GIFIN_ERR_EOF;
346 else if (prev_code == NULL_CODE)
348 GIFIN_PUSH_STRING(code);
353 if (code < table_size)
355 GIFIN_PUSH_STRING(code);
361 PUSH_PIXEL(NULL_CODE);
362 GIFIN_PUSH_STRING(prev_code);
367 if((errno = gifin_add_string(prev_code, first)) != GIFIN_SUCCESS)
373 /* pop a pixel off the pixel stack */
374 *pel = (int) pstk[--pstk_idx];
377 return GIFIN_SUCCESS;
381 * close an open GIF file
384 static int gifin_close_file()
386 /* make sure there's a file open */
388 return GIFIN_ERR_NFO;
390 /* mark file (and image) as closed */
395 return GIFIN_SUCCESS;
399 * load a colormap from the input stream
402 static int gifin_load_cmap(BYTE cmap[3][256], int ncolors)
406 for (i=0; i<ncolors; i++)
408 if (fread(buf, 1, 3, ins) != 3)
409 return GIFIN_ERR_EOF;
411 cmap[GIF_RED][i] = buf[GIF_RED];
412 cmap[GIF_GRN][i] = buf[GIF_GRN];
413 cmap[GIF_BLU][i] = buf[GIF_BLU];
417 return GIFIN_SUCCESS;
421 * skip an extension block in the input stream
424 static int gifin_skip_extension()
428 /* get the extension function byte */
431 /* skip any remaining raster data */
434 if ((errno = gifin_read_data_block()) != GIFIN_SUCCESS)
440 return GIFIN_SUCCESS;
444 * read a new data block from the input stream
447 static int gifin_read_data_block()
449 /* read the data block header */
450 buf_cnt = fgetc(ins);
452 /* read the data block body */
453 if (fread(buf, 1, buf_cnt, ins) != buf_cnt)
454 return GIFIN_ERR_EOF;
459 return GIFIN_SUCCESS;
464 * add a new string to the string table
467 static int gifin_add_string(int p, int e)
469 prefix[table_size] = p;
470 extnsn[table_size] = e;
472 if ((table_size == code_mask) && (code_size < 12))
475 code_mask = (1 << code_size) - 1;
479 if (table_size > STAB_SIZE)
480 return GIFIN_ERR_TAO;
481 return GIFIN_SUCCESS;
484 /* these are the routines added for interfacing to xli
487 /* tell someone what the image we're loading is. this could be a little more
488 * descriptive but I don't care
491 static void tellAboutImage(char *name)
493 printf("\n%s:\n %dx%d %s%s image with %d colors\n",
494 name, gifin_img_width, gifin_img_height,
495 (gifin_interlace_flag ? "interlaced " : ""),
496 gif_version_name[gifin_version],
497 (gifin_l_cmap_flag ? gifin_l_ncolors : gifin_g_ncolors));
500 Image *gifLoad(char *fullname)
504 int x, y, pixel, pass, scanlen;
505 byte *pixptr, *pixline;
508 if (!(zf = fopen(fullname,"r")))
514 if ((gifin_open_file(zf) != GIFIN_SUCCESS) || /* read GIF header */
515 (gifin_open_image() != GIFIN_SUCCESS)) /* read image header */
517 printf("gifin_open_file or gifin_open_image failed!\n");
524 tellAboutImage(fullname);
526 image= newRGBImage(gifin_img_width, gifin_img_height, (gifin_l_cmap_flag ?
528 gifin_g_pixel_bits));
529 image->title= dupString(fullname);
531 /* if image has a local colormap, override global colormap
534 if (gifin_l_cmap_flag)
536 for (x= 0; x < gifin_l_ncolors; x++)
538 image->rgb.red[x]= gifin_l_cmap[GIF_RED][x] << 8;
539 image->rgb.green[x]= gifin_l_cmap[GIF_GRN][x] << 8;
540 image->rgb.blue[x]= gifin_l_cmap[GIF_BLU][x] << 8;
542 image->rgb.used= gifin_l_ncolors;
546 for (x= 0; x < gifin_g_ncolors; x++)
548 image->rgb.red[x]= gifin_g_cmap[GIF_RED][x] << 8;
549 image->rgb.green[x]= gifin_g_cmap[GIF_GRN][x] << 8;
550 image->rgb.blue[x]= gifin_g_cmap[GIF_BLU][x] << 8;
552 image->rgb.used= gifin_g_ncolors;
555 /* interlaced image -- futz with the vertical trace. i wish i knew what
556 * kind of drugs the GIF people were on when they decided that they
557 * needed to support interlacing.
560 if (gifin_interlace_flag)
562 scanlen= image->height * image->pixlen;
564 /* interlacing takes four passes to read, each starting at a different
568 for (pass= 0; pass < 4; pass++)
570 y= interlace_start[pass];
571 scanlen= image->width * image->pixlen * interlace_rate[pass];
572 pixline= image->data + (y * image->width * image->pixlen);
573 while (y < gifin_img_height)
576 for (x= 0; x < gifin_img_width; x++)
578 if ((errno = gifin_get_pixel(&pixel)) != GIFIN_SUCCESS)
580 fprintf(stderr, "gifLoad: %s - Short read within image data, '%s'\n", fullname, get_err_string(errno));
581 y = gifin_img_height; x = gifin_img_width;
583 valToMem(pixel, pixptr, image->pixlen);
584 pixptr += image->pixlen;
586 y += interlace_rate[pass];
593 /* not an interlaced image, just read in sequentially
596 if(image->pixlen == 1) /* the usual case */
599 for (y= 0; y < gifin_img_height; y++)
600 for (x= 0; x < gifin_img_width; x++)
602 if ((errno = gifin_get_pixel(&pixel)) != GIFIN_SUCCESS)
604 fprintf(stderr, "gifLoad: %s - Short read within image data, '%s'\n", fullname, get_err_string(errno));
605 y = gifin_img_height; x = gifin_img_width;
607 valToMem(pixel, pixptr, 1);
611 else /* less ususal case */
614 for (y= 0; y < gifin_img_height; y++)
615 for (x= 0; x < gifin_img_width; x++)
617 if ((errno = gifin_get_pixel(&pixel)) != GIFIN_SUCCESS)
619 fprintf(stderr, "gifLoad: %s - Short read within image data, '%s'\n", fullname, get_err_string(errno));
620 y = gifin_img_height; x = gifin_img_width;
622 valToMem(pixel, pixptr, image->pixlen);
623 pixptr += image->pixlen;