www.pudn.com > pixit.zip > GIFDCD.C
#include#include #include #include #include #define PSZ 768 /* Maximum palette size */ #define BSZ 16384 /* Size of write buffer for delzw() */ struct gifhead { char s[6]; unsigned int w, h; unsigned char c, b, z; }; struct image { unsigned int l, t, w, h; unsigned char m; }; int _readc(int f) /* Read a character from file f, return -1 on end of file */ { unsigned char c; if (_read(f, &c, 1) == 1) return c; else return -1; } long delzw(int g, int h, int n) /* Decompress a .GIF style LZW compressed data stream of n-bit symbols, getting codes from file g and writing symbols (one per byte) to file h. delzw() returns the number of bytes written to file h. n must be in the range 2..8. */ { int n2, /* 2^n */ m, /* Current code size in bits */ m2, /* 2^m */ k, /* Next available table entry */ c, /* Code being expanded */ f, /* Last symbol decoded */ i, /* Code just read */ d, /* Code read before this one */ j, /* Number of bits left in *p */ a; /* Bytes in next block */ unsigned char *p, /* Pointer to current byte in read buffer */ *q, /* Pointer past liast byte in read buffer */ b[255], /* Read buffer */ *u, /* Stack pointer into r */ r[4096], /* Stack for code expansion */ s[4096]; /* Symbol entries in table */ int t[4096]; /* Code entries in table */ unsigned char *w; /* Write buffer pointer */ unsigned char y[BSZ]; /* Write buffer */ long e; /* Count of bytes written */ static int z[] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff, 0x7ff,0xfff,0x1fff,0x3fff,0x7fff}; /* Initialize buffers */ w = y; e = 0; p = q = b; j = 8; /* Setup decompression parameters */ if (n < 2 || n > 8) return -5; /* Bad symbol size */ n2 = 1 << n; k = n2 + 2; m2 = 1 << (m = n + 1); f = d = -1; /* There is no old code yet */ /* Do until termination code (2^n + 1) is read */ while (1) { /* Get next code: reads next m bits from file g, which is made of blocks of 1..255 bytes, each preceded by a one byte count. */ if (j == 8) { if (++p >= q && (((a = _readc(g)) < 1) || (q = (p = b) + _read(g, b, a)) < b + a)) return -4; /* Premature end of file */ j = 0; } c = *p; if ((i = m + j) <= 8) { *p >>= m; j = i; } else { if (++p >= q && (((a = _readc(g)) < 1) || (q = (p = b) + _read(g, b, a)) < b + a)) return -4; /* Premature end of file */ c |= *p << (8 - j); if (i <= 16) *p >>= (j = i - 8); else { if (++p >= q && (((a = _readc(g)) < 1) || (q = (p = b) + _read(g, b, a)) < b + a)) return -4; /* Premature end of file */ c |= *p << (16 - j); *p >>= (j = i - 16); } } c &= z[m]; i = c; /* Check code */ if (c == n2 + 1) break; /* Terminator symbol */ if (c > k) return -3; /* Bad code */ /* See if clear code */ if (c == n2) { k = n2 + 2; m2 = 1 << (m = n + 1); f = d = -1; continue; } /* Empty stack */ u = r; /* Check for special case---if code is next code to be defined */ if (c == k) { if (d == -1) return -2; /* First code is not a symbol */ *u++ = f; c = d; } /* Build string backwards */ while (c >= n2) { *u++ = s[c]; c = t[c]; } /* Write string out forwards, update final character (f) */ f = c; do { *w++ = c; if (w == y + BSZ) { _write(h, y, BSZ); e += BSZ; w = y; } if (u <= r) break; c = *--u; } while (1); /* Put new entry in table, update code length, old code */ if (k < 4096 && d != -1) { t[k] = d; s[k] = f; if (++k >= m2 && m < 12) m2 = 1 << ++m; } d = i; } /* Check that termination code was in the last byte of data */ if (_readc(g) != 0) return -1; /* File didn't end after terminator */ /* Flush write buffer and return bytes written */ if (w - y) { _write(h, y, w - y); e += w - y; } return e; } void gif(int f, int w, int e) /* Decode .gif file f: if e is 1, do an extended decode, of e is 2, write a decompressed version of the .gif file to file w. */ { long n, t; int b, c; struct gifhead g; struct image d; unsigned char p[PSZ]; /* Check GIF header */ if (_read(f, &g, sizeof(g)) != sizeof(g) || strncmp(g.s, "GIF87a", 6)) printf(" is not a GIF87a file.\n"); else { /* Show header information */ printf(" is %dx%dx%d bits and %d bits/color with ", g.w, g.h, (g.c & 7) + 1, ((g.c >> 4) & 7) + 1); if (g.c & 0x80) printf("a "); else printf("no "); printf("global color map\n"); if ((g.c & 8) || g.z) printf(" !reserved bits were not all zero\n"); /* If extended decode, read entire file */ if (e) { /* Show one more detail from header */ printf(" background color is %d\n", g.b); /* If /w, write crucial header information */ if (e == 2) { _write(w, "PX", 2); _write(w, &(g.w), 6); } /* Global color table is next */ if (g.c & 0x80) { c = 3 * (1 << ((g.c & 7) + 1)); if (e != 2) { if (lseek(f, c, SEEK_CUR) == -1L) { printf(" !file stopped in global color table\n"); return; } } else /* Save global color table in p */ { if (_read(f, p, c) != c) { printf(" !file stopped in global color table\n"); return; } for (b = 0; b < c; b++) p[b] >>= 2; for (; b < PSZ; b++) p[b] = 0; } } else printf(" !no global color table---.pix file unusable\n"); /* Read images and extension blocks */ while ((c = _readc(f)) == ',' || c == '!') /* Process image */ if (c == ',') { /* Initialize bits per pixel */ b = (g.c & 7) + 1; /* Read image descriptor */ if (_read(f, &d, sizeof(d)) != sizeof(d)) { printf(" !file stopped in image descriptor\n"); return; } printf(" image: start %d/%d pixels from left/top,", d.l, d.t); printf(" is %dx%d %s\n", d.w, d.h, d.m & 0x40 ? "interlaced" : "sequential"); if (d.m & 0x38) printf(" !reserved bits were not all zero\n"); if (e == 2) { if (d.l || d.t || d.w != g.w || d.h != g.h || (d.m & 0x40)) printf(" !image not standard---.pix file unusable\n"); _write(w, &d, 8); _write(w, p, PSZ); } /* Local color map (if any) is next */ if (d.m & 0x80) { b = (d.m & 7) + 1; printf(" local color map with %d bits/pixel\n", b); if (lseek(f, 3 * (1L << b), SEEK_CUR) == -1L) { printf(" !file stopped in local color map\n"); return; } if (e == 2) printf(" !has local color map---.pix file unusable\n"); } /* Get bits per symbol for compressed image */ if ((c = _readc(f)) == -1) { printf(" !file stopped in raster data\n"); return; } printf(" code size = %d bits\n", c); /* Go over image blocks if just /e */ if (e != 2) { n = t = 0; while ((c = _readc(f)) != 0) { if (c == -1 || lseek(f, c, SEEK_CUR) == -1L) { printf(" !file stopped in raster data block\n"); return; } n++; t += c; } printf(" compressed image = %ld bytes in %ld blocks\n", t, n); } /* If /w, decompress image and write it out */ else if ((t = delzw(f, w, c)) < 0) printf(" !error %ld decompressing image\n", t); else printf(" decompressed image = %ld pixels\n", t); } /* Process extension block */ else { if ((c = _readc(f)) == -1) { printf(" !file stopped in extension block\n"); return; } printf(" gif extension block with function code %d\n", c); n = t = 0; while ((c = _readc(f)) != 0) { if (c == -1 || lseek(f, c, SEEK_CUR) == -1L) { printf(" !file stopped in extension data block\n"); return; } n++; t += c; } printf(" total extension data = %ld bytes in %ld blocks\n", t, n); } /* Make sure images and extensions terminated with a semicolon */ if (c == ';') printf(" file"); else printf(" !file not"); printf(" properly terminated"); /* See if hit end of file */ if (eof(f) != 1) printf(" (but extra data at end)"); /* Done reading file */ printf("\n\n"); } } /* Close files */ _close(f); if (e == 2) _close(w); } void main(int argc, char *argv[]) /* Process .gif files and options---only options allowed are /e for an extended decode, and /w for a full decompression, writing the results to the same filename, but with extension .pix. */ { int i, e, f, w; char a[128]; e = 0; /* Extended list off */ for (i = 1; i < argc; i++) if (argv[i][0] == '/') if ((argv[i][1] & 0x5f) == 'E') e = 1; /* Extended list on */ else if ((argv[i][1] & 0x5f) == 'W') e = 2; /* Write image data */ else printf("(invalid option)\n"); else { printf(argv[i]); strcat(strcpy(a, argv[i]), ".gif"); if ((f = _open(a, O_RDONLY)) == -1) printf(".gif not found.\n"); else { if (e == 2) { strcat(strcpy(a, argv[i]), ".pix"); if ((w = _creat(a, 0)) == -1) { printf(".pix could not be created---downgrading to /e\n"); e = 1; printf(argv[i]); } } gif(f, w, e); } } }