1 /* GIF reading routines based on those in pbmplus:ppm/giftoppm.c, bearing
2 * following copyright notice:
5 /* +-------------------------------------------------------------------+ */
6 /* | Copyright 1990, David Koblas. | */
7 /* | Permission to use, copy, modify, and distribute this software | */
8 /* | and its documentation for any purpose and without fee is hereby | */
9 /* | granted, provided that the above copyright notice appear in all | */
10 /* | copies and that both that copyright notice and this permission | */
11 /* | notice appear in supporting documentation. This software is | */
12 /* | provided "as is" without express or implied warranty. | */
13 /* +-------------------------------------------------------------------+ */
16 * $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $
23 extern long *FDECL(alloc, (unsigned int));
26 #define PPM_ASSIGN(p, red, grn, blu) \
33 #define MAX_LWZ_BITS 12
35 #define INTERLACE 0x40
36 #define LOCALCOLORMAP 0x80
37 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
39 #define ReadOK(file, buffer, len) \
40 (fread((genericptr_t) buffer, (int) len, 1, file) != 0)
42 #define LM_to_uint(a, b) (((b) << 8) | (a))
59 } Gif89 = { -1, -1, -1, 0 };
61 int ZeroDataBlock = FALSE;
63 static FILE *gif_file;
64 static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down;
66 static unsigned char input_code_size;
68 static int FDECL(GetDataBlock, (FILE * fd, unsigned char *buf));
69 static void FDECL(DoExtension, (FILE * fd, int label));
70 static boolean FDECL(ReadColorMap, (FILE * fd, int number));
71 static void FDECL(read_header, (FILE * fd));
72 static int FDECL(GetCode, (FILE * fd, int code_size, int flag));
73 static int FDECL(LWZReadByte, (FILE * fd, int flag, int input_code_size));
74 static void FDECL(ReadInterleavedImage, (FILE * fd, int len, int height));
75 static void FDECL(ReadTileStrip, (FILE * fd, int len));
77 /* These should be in gif.h, but there isn't one. */
78 boolean FDECL(fopen_gif_file, (const char *, const char *));
79 boolean FDECL(read_gif_tile, (pixel(*) [TILE_X]));
80 int NDECL(fclose_gif_file);
89 if (!ReadOK(fd, &count, 1)) {
90 Fprintf(stderr, "error in getting DataBlock size\n");
94 ZeroDataBlock = (count == 0);
96 if ((count != 0) && (!ReadOK(fd, buf, count))) {
97 Fprintf(stderr, "error in reading DataBlock\n");
105 DoExtension(fd, label)
109 static char buf[256];
113 case 0x01: /* Plain Text Extension */
114 str = "Plain Text Extension";
116 if (GetDataBlock(fd, (unsigned char *) buf) == 0)
119 lpos = LM_to_uint(buf[0], buf[1]);
120 tpos = LM_to_uint(buf[2], buf[3]);
121 width = LM_to_uint(buf[4], buf[5]);
122 height = LM_to_uint(buf[6], buf[7]);
125 foreground = buf[10];
126 background = buf[11];
128 while (GetDataBlock(fd, (unsigned char *) buf) != 0) {
129 PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v], cmap[CM_GREEN][v],
138 case 0xff: /* Application Extension */
139 str = "Application Extension";
141 case 0xfe: /* Comment Extension */
142 str = "Comment Extension";
143 while (GetDataBlock(fd, (unsigned char *) buf) != 0) {
144 Fprintf(stderr, "gif comment: %s\n", buf);
147 case 0xf9: /* Graphic Control Extension */
148 str = "Graphic Control Extension";
149 (void) GetDataBlock(fd, (unsigned char *) buf);
150 Gif89.disposal = (buf[0] >> 2) & 0x7;
151 Gif89.inputFlag = (buf[0] >> 1) & 0x1;
152 Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
153 if ((buf[0] & 0x1) != 0)
154 Gif89.transparent = buf[3];
156 while (GetDataBlock(fd, (unsigned char *) buf) != 0)
161 Sprintf(buf, "UNKNOWN (0x%02x)", label);
165 Fprintf(stderr, "got a '%s' extension\n", str);
167 while (GetDataBlock(fd, (unsigned char *) buf) != 0)
172 ReadColorMap(fd, number)
177 unsigned char rgb[3];
179 for (i = 0; i < number; ++i) {
180 if (!ReadOK(fd, rgb, sizeof(rgb))) {
184 ColorMap[CM_RED][i] = rgb[0];
185 ColorMap[CM_GREEN][i] = rgb[1];
186 ColorMap[CM_BLUE][i] = rgb[2];
188 colorsinmap = number;
193 * Read gif header, including colormaps. We expect only one image per
194 * file, so if that image has a local colormap, overwrite the global one.
200 unsigned char buf[16];
204 if (!ReadOK(fd, buf, 6)) {
205 Fprintf(stderr, "error reading magic number\n");
209 if (strncmp((genericptr_t) buf, "GIF", 3) != 0) {
210 Fprintf(stderr, "not a GIF file\n");
214 (void) strncpy(version, (char *) buf + 3, 3);
217 if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
218 Fprintf(stderr, "bad version number, not '87a' or '89a'\n");
222 if (!ReadOK(fd, buf, 7)) {
223 Fprintf(stderr, "failed to read screen descriptor\n");
227 GifScreen.Width = LM_to_uint(buf[0], buf[1]);
228 GifScreen.Height = LM_to_uint(buf[2], buf[3]);
229 GifScreen.Colors = 2 << (buf[4] & 0x07);
230 GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
231 GifScreen.Background = buf[5];
232 GifScreen.AspectRatio = buf[6];
234 if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
235 if (!ReadColorMap(fd, GifScreen.Colors)) {
236 Fprintf(stderr, "error reading global colormap\n");
241 if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
242 Fprintf(stderr, "warning - non-square pixels\n");
246 if (!ReadOK(fd, &c, 1)) {
247 Fprintf(stderr, "EOF / read error on image data\n");
251 if (c == ';') { /* GIF terminator */
255 if (c == '!') { /* Extension */
256 if (!ReadOK(fd, &c, 1)) {
258 "EOF / read error on extension function code\n");
261 DoExtension(fd, (int) c);
265 if (c != ',') { /* Not a valid start character */
266 Fprintf(stderr, "bogus character 0x%02x, ignoring\n", (int) c);
270 if (!ReadOK(fd, buf, 9)) {
271 Fprintf(stderr, "couldn't read left/top/width/height\n");
275 if (BitSet(buf[8], LOCALCOLORMAP)) {
276 /* replace global color map with local */
277 GifScreen.Colors = 1 << ((buf[8] & 0x07) + 1);
278 if (!ReadColorMap(fd, GifScreen.Colors)) {
279 Fprintf(stderr, "error reading local colormap\n");
283 if (GifScreen.Width != LM_to_uint(buf[4], buf[5])) {
284 Fprintf(stderr, "warning: widths don't match\n");
285 GifScreen.Width = LM_to_uint(buf[4], buf[5]);
287 if (GifScreen.Height != LM_to_uint(buf[6], buf[7])) {
288 Fprintf(stderr, "warning: heights don't match\n");
289 GifScreen.Height = LM_to_uint(buf[6], buf[7]);
291 GifScreen.Interlace = BitSet(buf[8], INTERLACE);
297 GetCode(fd, code_size, flag)
302 static unsigned char buf[280];
303 static int curbit, lastbit, done, last_byte;
314 if ((curbit + code_size) >= lastbit) {
316 if (curbit >= lastbit)
317 Fprintf(stderr, "ran off the end of my bits\n");
320 buf[0] = buf[last_byte - 2];
321 buf[1] = buf[last_byte - 1];
323 if ((count = GetDataBlock(fd, &buf[2])) == 0)
326 last_byte = 2 + count;
327 curbit = (curbit - lastbit) + 16;
328 lastbit = (2 + count) * 8;
332 for (i = curbit, j = 0; j < code_size; ++i, ++j)
333 ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
341 LWZReadByte(fd, flag, input_code_size)
346 static int fresh = FALSE;
348 static int code_size, set_code_size;
349 static int max_code, max_code_size;
350 static int firstcode, oldcode;
351 static int clear_code, end_code;
352 static int table[2][(1 << MAX_LWZ_BITS)];
353 static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
357 set_code_size = input_code_size;
358 code_size = set_code_size + 1;
359 clear_code = 1 << set_code_size;
360 end_code = clear_code + 1;
361 max_code_size = 2 * clear_code;
362 max_code = clear_code + 2;
364 (void) GetCode(fd, 0, TRUE);
368 for (i = 0; i < clear_code; ++i) {
372 for (; i < (1 << MAX_LWZ_BITS); ++i)
373 table[0][i] = table[1][0] = 0;
381 firstcode = oldcode = GetCode(fd, code_size, FALSE);
382 } while (firstcode == clear_code);
389 while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
390 if (code == clear_code) {
391 for (i = 0; i < clear_code; ++i) {
395 for (; i < (1 << MAX_LWZ_BITS); ++i)
396 table[0][i] = table[1][i] = 0;
397 code_size = set_code_size + 1;
398 max_code_size = 2 * clear_code;
399 max_code = clear_code + 2;
401 firstcode = oldcode = GetCode(fd, code_size, FALSE);
403 } else if (code == end_code) {
405 unsigned char buf[260];
410 while ((count = GetDataBlock(fd, buf)) > 0)
415 "missing EOD in data stream (common occurrence)\n");
421 if (code >= max_code) {
426 while (code >= clear_code) {
427 *sp++ = table[1][code];
428 if (code == table[0][code]) {
429 Fprintf(stderr, "circular table entry BIG ERROR\n");
432 code = table[0][code];
435 *sp++ = firstcode = table[1][code];
437 if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
438 table[0][code] = oldcode;
439 table[1][code] = firstcode;
441 if ((max_code >= max_code_size)
442 && (max_code_size < (1 << MAX_LWZ_BITS))) {
457 ReadInterleavedImage(fd, len, height)
462 int xpos = 0, ypos = 0, pass = 0;
464 while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) {
465 PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
466 ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
484 if (ypos >= height) {
506 if (LWZReadByte(fd, FALSE, (int) input_code_size) >= 0)
507 Fprintf(stderr, "too much input data, ignoring extra...\n");
511 ReadTileStrip(fd, len)
516 int xpos = 0, ypos = 0;
518 while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) {
519 PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
520 ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
533 fopen_gif_file(filename, type)
534 const char *filename;
539 if (strcmp(type, RDBMODE)) {
540 Fprintf(stderr, "using reading routine for non-reading?\n");
543 gif_file = fopen(filename, type);
544 if (gif_file == (FILE *) 0) {
545 Fprintf(stderr, "cannot open gif file %s\n", filename);
549 read_header(gif_file);
550 if (GifScreen.Width % TILE_X) {
551 Fprintf(stderr, "error: width %d not divisible by %d\n",
552 GifScreen.Width, TILE_X);
555 tiles_across = GifScreen.Width / TILE_X;
556 curr_tiles_across = 0;
557 if (GifScreen.Height % TILE_Y) {
558 Fprintf(stderr, "error: height %d not divisible by %d\n",
559 GifScreen.Height, TILE_Y);
560 /* exit(EXIT_FAILURE) */;
562 tiles_down = GifScreen.Height / TILE_Y;
565 if (GifScreen.Interlace) {
566 /* sigh -- hope this doesn't happen on micros */
567 image = (pixel **) alloc(GifScreen.Height * sizeof(pixel *));
568 for (i = 0; i < GifScreen.Height; i++) {
569 image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
572 image = (pixel **) alloc(TILE_Y * sizeof(pixel *));
573 for (i = 0; i < TILE_Y; i++) {
574 image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
579 ** Initialize the Compression routines
581 if (!ReadOK(gif_file, &input_code_size, 1)) {
582 Fprintf(stderr, "EOF / read error on image data\n");
586 if (LWZReadByte(gif_file, TRUE, (int) input_code_size) < 0) {
587 Fprintf(stderr, "error reading image\n");
591 /* read first section */
592 if (GifScreen.Interlace) {
593 ReadInterleavedImage(gif_file, GifScreen.Width, GifScreen.Height);
595 ReadTileStrip(gif_file, GifScreen.Width);
600 /* Read a tile. Returns FALSE when there are no more tiles */
602 read_gif_tile(pixels)
603 pixel (*pixels)[TILE_X];
607 if (curr_tiles_down >= tiles_down)
609 if (curr_tiles_across == tiles_across) {
610 curr_tiles_across = 0;
612 if (curr_tiles_down >= tiles_down)
614 if (!GifScreen.Interlace)
615 ReadTileStrip(gif_file, GifScreen.Width);
617 if (GifScreen.Interlace) {
618 for (j = 0; j < TILE_Y; j++) {
619 for (i = 0; i < TILE_X; i++) {
620 pixels[j][i] = image[curr_tiles_down * TILE_Y
621 + j][curr_tiles_across * TILE_X + i];
625 for (j = 0; j < TILE_Y; j++) {
626 for (i = 0; i < TILE_X; i++) {
627 pixels[j][i] = image[j][curr_tiles_across * TILE_X + i];
633 /* check for "filler" tile */
634 for (j = 0; j < TILE_Y; j++) {
635 for (i = 0; i < TILE_X && i < 4; i += 2) {
636 if (pixels[j][i].r != ColorMap[CM_RED][0]
637 || pixels[j][i].g != ColorMap[CM_GREEN][0]
638 || pixels[j][i].b != ColorMap[CM_BLUE][0]
639 || pixels[j][i + 1].r != ColorMap[CM_RED][1]
640 || pixels[j][i + 1].g != ColorMap[CM_GREEN][1]
641 || pixels[j][i + 1].b != ColorMap[CM_BLUE][1])
653 if (GifScreen.Interlace) {
654 for (i = 0; i < GifScreen.Height; i++) {
655 free((genericptr_t) image[i]);
657 free((genericptr_t) image);
659 for (i = 0; i < TILE_Y; i++) {
660 free((genericptr_t) image[i]);
662 free((genericptr_t) image);
664 return (fclose(gif_file));
668 static char *std_args[] = { "tilemap", /* dummy argv[0] */
669 "monsters.gif", "monsters.txt", "objects.gif",
670 "objects.txt", "other.gif", "other.txt" };
677 pixel pixels[TILE_Y][TILE_X];
680 argc = SIZE(std_args);
682 } else if (argc != 3) {
683 Fprintf(stderr, "usage: gif2txt giffile txtfile\n");
688 if (!fopen_gif_file(argv[1], RDBMODE))
693 if (!fopen_text_file(argv[2], WRTMODE)) {
694 (void) fclose_gif_file();
698 while (read_gif_tile(pixels))
699 (void) write_text_tile(pixels);
701 (void) fclose_gif_file();
702 (void) fclose_text_file();