home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / glview.sit / glview.src / gif.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-15  |  10.4 KB  |  391 lines

  1. /*
  2.  * gif.c - routine to load GIF images (hacked from gif2ras).
  3.  *
  4.  * Copyright (c) 1991 by Patrick J. Naughton
  5.  */
  6.  
  7. #pragma segment Gif
  8.  
  9. #include "grasp.h"
  10.  
  11. #define NEXTBYTE (*ptr++)
  12. #define IMAGESEP 0x2c
  13. #define INTERLACEMASK 0x40
  14. #define COLORMAPMASK 0x80
  15.  
  16. static int  BitOffset,    /* Bit Offset of next code */
  17.             XC, YC,    /* Output X and Y coords of current pixel */
  18.             Pass,    /* Used by output routine if interlaced pic */
  19.             OutCount,    /* Decompressor output 'stack count' */
  20.             RWidth, RHeight,    /* screen dimensions */
  21.             Width, Height,    /* image dimensions */
  22.             LeftOfs, TopOfs,    /* image offset */
  23.             BitsPerPixel,    /* Bits per pixel, read from GIF header */
  24.             ColorMapSize,    /* number of colors */
  25.             CodeSize,    /* Code size, read from GIF header */
  26.             InitCodeSize,    /* Starting code size, used during Clear */
  27.             LZWCode,    /* Value returned by ReadCode */
  28.             MaxCode,    /* limiting value for current code size */
  29.             ClearCode,    /* GIF clear code */
  30.             EOFCode,    /* GIF end-of-information code */
  31.             CurCode, OldCode, InCode,    /* Decompressor variables */
  32.             FirstFree,    /* First free code, generated per GIF spec */
  33.             FreeCode,    /* Decompressor, next free slot in hash table */
  34.             FinChar,    /* Decompressor variable */
  35.             BitMask,    /* AND mask for data size */
  36.             ReadMask,    /* Code AND mask for current code size */
  37.             Interlace, HasColormap;
  38.  
  39. static u_char *Image;    /* The result array */
  40. static u_char *RawGIF;    /* The heap array to hold it, raw */
  41. static u_char *Raster;    /* The raster data stream, unblocked */
  42.  
  43.  /* The hash table used by the decompressor */
  44. static int  Prefix[4096];
  45. static int  Suffix[4096];
  46.  
  47.  /* An output array used by the decompressor */
  48. static int  OutCode[1025];
  49.  
  50. static char *id = "GIF87a";
  51.  
  52.  
  53. /* Fetch the next code from the raster data stream.  The codes can be
  54.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  55.  * maintain our location in the Raster array as a BIT Offset.  We compute
  56.  * the byte Offset into the raster array by dividing this by 8, pick up
  57.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  58.  * bring the desired code to the bottom, then mask it off and return it.
  59.  */
  60. static int
  61. ReadCode()
  62. {
  63.     int         RawCode, ByteOffset;
  64.  
  65.     ByteOffset = BitOffset / 8;
  66.     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  67.     if (CodeSize >= 8)
  68.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  69.     RawCode >>= (BitOffset % 8);
  70.     BitOffset += CodeSize;
  71.     return (RawCode & ReadMask);
  72. }
  73.  
  74. static void
  75. AddToPixel(Index)
  76.     u_char      Index;
  77. {
  78.     *(Image + YC * Width + XC) = Index;
  79.  
  80. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  81.  
  82.     if (++XC == Width) {
  83.  
  84. /* If a non-interlaced picture, just increment YC to the next scan line.
  85.  * If it's interlaced, deal with the interlace as described in the GIF
  86.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  87.  * past the bottom of it
  88.  */
  89.  
  90.     XC = 0;
  91.     if (!Interlace)
  92.         YC++;
  93.     else {
  94.         switch (Pass) {
  95.         case 0:
  96.         YC += 8;
  97.         if (YC >= Height) {
  98.             Pass++;
  99.             YC = 4;
  100.         }
  101.         break;
  102.         case 1:
  103.         YC += 8;
  104.         if (YC >= Height) {
  105.             Pass++;
  106.             YC = 2;
  107.         }
  108.         break;
  109.         case 2:
  110.         YC += 4;
  111.         if (YC >= Height) {
  112.             Pass++;
  113.             YC = 1;
  114.         }
  115.         break;
  116.         case 3:
  117.         YC += 2;
  118.         break;
  119.         default:
  120.         break;
  121.         }
  122.     }
  123.     }
  124. }
  125.  
  126.  
  127. ImageStruct *
  128. readgifimage(fp, dirent)
  129.     FILE       *fp;
  130.     FilenameStruct *dirent;
  131. {
  132.     ImageStruct *im;
  133.     XImage     *xim;
  134.     int         filesize;
  135.     u_char      ch, ch1;
  136.     u_char     *ptr, *ptr1;
  137.     int         i;
  138.  
  139.     BitOffset = 0;
  140.     XC = 0;
  141.     YC = 0;
  142.     Pass = 0;
  143.     OutCount = 0;
  144.  
  145.     im = (ImageStruct *) malloc(sizeof(ImageStruct));
  146.  
  147.     fseek(fp, dirent->offset, 0);
  148.  
  149.     filesize = GetLong(fp);    /* length of whole image file... */
  150.  
  151.     im->name = strtok(strdup(dirent->fname), ".");
  152.     im->type = EXT_GIF;
  153.     im->xoff = 0;
  154.     im->yoff = 0;
  155.  
  156.     if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
  157.     error("%s: not enough memory to read gif file.\n", NULL);
  158.  
  159.     if (!(Raster = (u_char *) malloc(filesize)))
  160.     error("%s: not enough memory to read gif file.\n", NULL);
  161.  
  162.     if (fread(ptr, filesize, 1, fp) != 1)
  163.     error("%s: GIF data read failed\n", NULL);
  164.  
  165.     if (strncmp(ptr, id, 6)) {
  166.     free(im->name);
  167.     free(im);
  168.     free(Raster);
  169.     free(ptr);
  170.     return (ImageStruct *) readimage(fp, dirent, EXT_PIC);
  171.     }
  172.     ptr += 6;
  173.  
  174. /* Get variables from the GIF screen descriptor */
  175.  
  176.     ch = NEXTBYTE;
  177.     RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  178.     ch = NEXTBYTE;
  179.     RHeight = ch + 0x100 * NEXTBYTE;
  180.  
  181.     ch = NEXTBYTE;
  182.     HasColormap = ((ch & COLORMAPMASK) ? True : False);
  183.  
  184.     BitsPerPixel = (ch & 7) + 1;
  185.     im->cmaplen = 1 << BitsPerPixel;
  186.     BitMask = im->cmaplen - 1;
  187.  
  188.     ch = NEXTBYTE;    /* background color... not used. */
  189.  
  190.     if (NEXTBYTE)    /* supposed to be NULL */
  191.     error("%s: %s is a corrupt GIF file (nonull).\n", im->name);
  192.  
  193. /* Read in global colormap. */
  194.  
  195.     if (HasColormap) {
  196.     unsigned long pmasks;
  197.     u_long      pixels[256];
  198.  
  199.  
  200.      im->cmap = XCreateColormap(dsp, win, vis, AllocNone);
  201.      XAllocColorCells(dsp, im->cmap, True, &pmasks, 0, pixels, im->cmaplen);
  202.     for (i = 0; i < im->cmaplen; i++) {
  203.         im->colors[i].pixel = pixels[i];
  204.         im->colors[i].red = NEXTBYTE << 8;
  205.         im->colors[i].green = NEXTBYTE << 8;
  206.         im->colors[i].blue = NEXTBYTE << 8;
  207.         im->colors[i].flags = DoRed | DoGreen | DoBlue;
  208.  
  209.         if (imverbose) {
  210.         printf("%02x%02x%02x ",
  211.                im->colors[i].red >> 8,
  212.                im->colors[i].green >> 8,
  213.                im->colors[i].blue >> 8);
  214.         if (!((i + 1) % 8))
  215.             printf("\n");
  216.         }
  217.     }
  218.     XStoreColors(dsp, im->cmap, im->colors, im->cmaplen);
  219.      
  220.     } else
  221.     im->cmap = (Colormap) 0;
  222.  
  223. /* Check for image seperator */
  224.  
  225.     if (NEXTBYTE != IMAGESEP)
  226.     error("%s: %s is a corrupt GIF file (nosep).\n", im->name);
  227. /* Now read in values from the image descriptor */
  228.  
  229.     ch = NEXTBYTE;
  230.     LeftOfs = ch + 0x100 * NEXTBYTE;
  231.     ch = NEXTBYTE;
  232.     TopOfs = ch + 0x100 * NEXTBYTE;
  233.     ch = NEXTBYTE;
  234.     Width = ch + 0x100 * NEXTBYTE;
  235.     ch = NEXTBYTE;
  236.     Height = ch + 0x100 * NEXTBYTE;
  237.     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  238.  
  239.     if (verbose)
  240.     fprintf(stderr, "%s: (GIF) %dx%dx%d %s\n",
  241.         im->name, Width, Height, 8,
  242.         (Interlace) ? "Interlaced" : "");
  243.  
  244. /* Note that I ignore the possible existence of a local color map.
  245.  * I'm told there aren't many files around that use them, and the spec
  246.  * says it's defined for future use.  This could lead to an error
  247.  * reading some files.
  248.  */
  249.  
  250. /* Start reading the raster data. First we get the intial code size
  251.  * and compute decompressor constant values, based on this code size.
  252.  */
  253.  
  254.     CodeSize = NEXTBYTE;
  255.     ClearCode = (1 << CodeSize);
  256.     EOFCode = ClearCode + 1;
  257.     FreeCode = FirstFree = ClearCode + 2;
  258.  
  259. /* The GIF spec has it that the code size is the code size used to
  260.  * compute the above values is the code size given in the file, but the
  261.  * code size used in compression/decompression is the code size given in
  262.  * the file plus one. (thus the ++).
  263.  */
  264.  
  265.     CodeSize++;
  266.     InitCodeSize = CodeSize;
  267.     MaxCode = (1 << CodeSize);
  268.     ReadMask = MaxCode - 1;
  269.  
  270. /* Read the raster data.  Here we just transpose it from the GIF array
  271.  * to the Raster array, turning it from a series of blocks into one long
  272.  * data stream, which makes life much easier for ReadCode().
  273.  */
  274.  
  275.     ptr1 = Raster;
  276.     do {
  277.     ch = ch1 = NEXTBYTE;
  278.     while (ch--)
  279.         *ptr1++ = NEXTBYTE;
  280.     if ((Raster - ptr1) > filesize)
  281.         error("%s: %s is a corrupt GIF file (unblock).\n", im->name);
  282.     } while (ch1);
  283.  
  284.     free(RawGIF);    /* We're done with the raw data now... */
  285.  
  286.     Image = (u_char *) malloc(Width * Height);
  287.     if (!Image)
  288.     error("%s: malloc failed on image data.\n");
  289.  
  290. /* Decompress the file, continuing until you see the GIF EOF code.
  291.  * One obvious enhancement is to add checking for corrupt files here.
  292.  */
  293.  
  294.     LZWCode = ReadCode();
  295.     while (LZWCode != EOFCode) {
  296.  
  297. /* Clear code sets everything back to its initial value, then reads the
  298.  * immediately subsequent code as uncompressed data.
  299.  */
  300.  
  301.     if (LZWCode == ClearCode) {
  302.         CodeSize = InitCodeSize;
  303.         MaxCode = (1 << CodeSize);
  304.         ReadMask = MaxCode - 1;
  305.         FreeCode = FirstFree;
  306.         CurCode = OldCode = LZWCode = ReadCode();
  307.         FinChar = CurCode & BitMask;
  308.         AddToPixel(FinChar);
  309.     } else {
  310.  
  311. /* If not a clear code, then must be data: save same as CurCode and InCode */
  312.  
  313.         CurCode = InCode = LZWCode;
  314.  
  315. /* If greater or equal to FreeCode, not in the hash table yet;
  316.  * repeat the last character decoded
  317.  */
  318.  
  319.         if (CurCode >= FreeCode) {
  320.         CurCode = OldCode;
  321.         OutCode[OutCount++] = FinChar;
  322.         }
  323. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  324.  * through the hash table to its end; each code in the chain puts its
  325.  * associated output code on the output queue.
  326.  */
  327.  
  328.         while (CurCode > BitMask) {
  329.         if (OutCount > 1024) {
  330.             fprintf(stderr, "%s is a corrupt GIF file (OutCount).\n",
  331.                 im->name);
  332.             goto error_exit;
  333.         }
  334.         OutCode[OutCount++] = Suffix[CurCode];
  335.         CurCode = Prefix[CurCode];
  336.         }
  337.  
  338. /* The last code in the chain is treated as raw data. */
  339.  
  340.         FinChar = CurCode & BitMask;
  341.         OutCode[OutCount++] = FinChar;
  342.  
  343. /* Now we put the data out to the Output routine.
  344.  * It's been stacked LIFO, so deal with it that way...
  345.  */
  346.  
  347.         for (i = OutCount - 1; i >= 0; i--)
  348.         AddToPixel(OutCode[i]);
  349.         OutCount = 0;
  350.  
  351. /* Build the hash table on-the-fly. No table is stored in the file. */
  352.  
  353.         Prefix[FreeCode] = OldCode;
  354.         Suffix[FreeCode] = FinChar;
  355.         OldCode = InCode;
  356.  
  357. /* Point to the next slot in the table.  If we exceed the current
  358.  * MaxCode value, increment the code size unless it's already 12.  If it
  359.  * is, do nothing: the next code decompressed better be CLEAR
  360.  */
  361.  
  362.         FreeCode++;
  363.         if (FreeCode >= MaxCode) {
  364.         if (CodeSize < 12) {
  365.             CodeSize++;
  366.             MaxCode *= 2;
  367.             ReadMask = (1 << CodeSize) - 1;
  368.         }
  369.         }
  370.     }
  371.     LZWCode = ReadCode();
  372.     }
  373. error_exit:
  374.  
  375.     free(Raster);
  376.  
  377.     im->w = Width;
  378.     im->h = Height;
  379.     im->d = 8;
  380.     xim = XCreateImage(dsp, vis, im->d, ZPixmap, 0, Image,
  381.                im->w, im->h, 8, im->w);
  382. //    im->pix = XCreatePixmap(dsp, win, im->w, im->h, 8);
  383. //    XPutImage(dsp, im->pix, gc, xim, 0, 0, 0, 0, im->w, im->h);
  384. //    XSync(dsp, False);
  385.     im->w= xim->width; // patch in case CreateImage needed to change size
  386.     im->h= xim->height;
  387.     im->pix = (Pixmap) xim;
  388.     free(Image);
  389.     return im;
  390. }
  391.