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); 
      } 
    } 
}