home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 26 / CD_ASCQ_26_1295.iso / vrac / giftool2.zip / SOURCE.ZIP / READGIF.C < prev    next >
C/C++ Source or Header  |  1995-09-28  |  14KB  |  564 lines

  1. /*
  2. **  Copyright 1994, Home Pages, Inc.
  3. **
  4. **    Please read the file COPYRIGHT for specific information.
  5. **
  6. **    Home Pages, Inc.
  7. **    257 Castro St. Suite 219
  8. **    Mountain View, CA 94041
  9. **
  10. **    Phone: 1 415 903 5353
  11. **      Fax: 1 415 903 5345
  12. **
  13. **    EMail: support@homepages.com
  14. ** 
  15. */
  16.  
  17. /* +-------------------------------------------------------------------+ */
  18. /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com)          | */
  19. /* |   Permission to use, copy, modify, and distribute this software   | */
  20. /* |   and its documentation for any purpose and without fee is hereby | */
  21. /* |   granted, provided that the above copyright notice appear in all | */
  22. /* |   copies and that both that copyright notice and this permission  | */
  23. /* |   notice appear in supporting documentation.  This software is    | */
  24. /* |   provided "as is" without express or implied warranty.           | */
  25. /* +-------------------------------------------------------------------+ */
  26.  
  27. #include <stdio.h>
  28. #include <setjmp.h>
  29.  
  30. #include "gif.h"
  31.  
  32. #define        TRUE    1
  33. #define        FALSE   0
  34.  
  35. #define        MAX_LWZ_BITS            12
  36.  
  37. #define INTERLACE        0x40
  38. #define LOCALCOLORMAP        0x80
  39.  
  40. #define BitSet(byte, bit)    (((byte) & (bit)) == (bit))
  41. #define    ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
  42. #define MKINT(a,b)        (((b)<<8)|(a))
  43. #define NEW(x)            ((x *)malloc(sizeof(x)))
  44.  
  45. /***************************************************************************
  46. *
  47. *  ERROR()    --  should not return
  48. *  INFO_MSG() --  info message, can be ignored
  49. *
  50. ***************************************************************************/
  51.  
  52. #if 0
  53. #define INFO_MSG(fmt)    pm_message fmt 
  54. #define ERROR(str)    pm_error(str)
  55. #else
  56. #if 0 
  57. #define INFO_MSG(fmt)    
  58. #define ERROR(str)     do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
  59. #else
  60. #define INFO_MSG(fmt)    
  61. #define ERROR(str)     longjmp(setjmp_buffer, 1)
  62. #endif
  63. #endif
  64.  
  65. /***************************************************************************/
  66.  
  67. static int readColorMap(FILE *, int, unsigned char [GIF_MAXCOLORS][3]);
  68. static int GetDataBlock(FILE *, unsigned char *);
  69. static void readImage(FILE *, int, int, int, unsigned char *);
  70.  
  71. static jmp_buf                  setjmp_buffer;
  72.  
  73. static int    verbose = FALSE;
  74. static int    showComment = FALSE;
  75.  
  76. int     GIFTest(char *file)
  77. {
  78.         FILE    *fd = fopen(file, "rb");
  79.         char    buf[10];
  80.         int     ret = FALSE;
  81.  
  82.         if (fd != NULL && ReadOK(fd, buf, 6)) {
  83.                 if ((strncmp(buf, "GIF", 3) == 0) &&
  84.                      ((strncmp(buf + 3, "87a", 3) != 0) ||
  85.                       (strncmp(buf + 3, "89a", 3) != 0)))
  86.                         ret = TRUE;
  87.         }
  88.  
  89.         fclose(fd);
  90.  
  91.         return ret;
  92. }
  93.  
  94. GIFStream *GIFReadFP(FILE *fd)
  95. {
  96.     unsigned char   buf[256];
  97.     unsigned char   c;
  98.     GIFStream    *stream;
  99.     GIFData        *cur, **end;
  100.     GIF89info    info;
  101.     int        resetInfo = TRUE;
  102.     int        n;
  103.  
  104.     if (fd == NULL)
  105.         return NULL;
  106.  
  107.     if (setjmp(setjmp_buffer))
  108.         goto out;
  109.  
  110.     if (! ReadOK(fd,buf,6)) 
  111.            ERROR("error reading magic number" );
  112.  
  113.     if (strncmp((char*)buf,"GIF",3) != 0) 
  114.            ERROR("not a GIF file" );
  115.  
  116.     if ((strncmp(buf + 3, "87a", 3) != 0) && 
  117.         (strncmp(buf + 3, "89a", 3) != 0)) 
  118.         ERROR("bad version number, not '87a' or '89a'" );
  119.  
  120.     if (! ReadOK(fd,buf,7))
  121.         ERROR("failed to read screen descriptor");
  122.  
  123.     stream = NEW(GIFStream);
  124.  
  125.     stream->width           = MKINT(buf[0], buf[1]);
  126.     stream->height          = MKINT(buf[2], buf[3]);
  127.  
  128.     stream->cmapSize        = 2 << (buf[4] & 0x07);
  129.     stream->colorMapSize    = stream->cmapSize;
  130.     stream->colorResolution = ((int)(buf[4] & 0x70) >> 3) + 1;
  131.     stream->background      = buf[5];
  132.     stream->aspectRatio     = buf[6];
  133.  
  134.     stream->data            = NULL;
  135.  
  136.     end = &stream->data;
  137.  
  138.     /*
  139.     **  Global colormap is present.
  140.     */
  141.     if (BitSet(buf[4], LOCALCOLORMAP)) {
  142.         if (readColorMap(fd, stream->cmapSize, stream->cmapData))
  143.             ERROR("unable to get global colormap");
  144.     } else {
  145.         stream->cmapSize   = 0;
  146.         stream->background = -1;
  147.     }
  148.  
  149.     if (stream->aspectRatio != 0 && stream->aspectRatio != 49) {
  150.            float   r;
  151.  
  152.            r = ((float) stream->aspectRatio + 15.0) / 64.0;
  153.            INFO_MSG(("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  154.            r < 1.0 ? 'x' : 'y',
  155.            r < 1.0 ? 1.0 / r : r ));
  156.     }
  157.  
  158.     while (ReadOK(fd, &c, 1) && c != ';') {
  159.         if (resetInfo) {
  160.             info.disposal    = 0;
  161.             info.inputFlag   = 0;
  162.             info.delayTime   = 0;
  163.             info.transparent = -1;
  164.             resetInfo = FALSE;
  165.         }
  166.         cur = NULL;
  167.  
  168.         if (c == '!') {        /* Extension */
  169.             if (! ReadOK(fd,&c,1))
  170.                 ERROR("EOF / read error on extention function code");
  171.             if (c == 0xf9) {    /* graphic control */
  172.                 (void) GetDataBlock(fd, buf);
  173.                 info.disposal    = (buf[0] >> 2) & 0x7;
  174.                 info.inputFlag   = (buf[0] >> 1) & 0x1;
  175.                 info.delayTime   = MKINT(buf[1],buf[2]);
  176.                 if (BitSet(buf[0], 0x1))
  177.                     info.transparent = buf[3];
  178.  
  179.                 while (GetDataBlock(fd,  buf) != 0)
  180.                     ;
  181.             } else if (c == 0xfe || c == 0x01) {
  182.                 int        len = 0;
  183.                 int        size = 256;
  184.                 char        *text = NULL;
  185.  
  186.                 /* 
  187.                 **  Comment or Plain Text
  188.                 */
  189.  
  190.                 cur = NEW(GIFData);
  191.  
  192.                 if (c == 0x01) {
  193.                     (void)GetDataBlock(fd, buf);
  194.                         
  195.                     cur->type   = gif_text;
  196.                     cur->info   = info;
  197.                     cur->x      = MKINT(buf[0],buf[1]);
  198.                     cur->y      = MKINT(buf[2],buf[3]);
  199.                     cur->width  = MKINT(buf[4],buf[5]);
  200.                     cur->height = MKINT(buf[6],buf[7]);
  201.  
  202.                     cur->data.text.cellWidth  = buf[8];
  203.                     cur->data.text.cellHeight = buf[9];
  204.                     cur->data.text.fg         = buf[10];
  205.                     cur->data.text.bg         = buf[11];
  206.  
  207.                     resetInfo = TRUE;
  208.                 } else {
  209.                     cur->type    = gif_comment;
  210.                 }
  211.  
  212.                 text = (char*)malloc(size);
  213.  
  214.                 while ((n = GetDataBlock(fd, buf)) != 0) {
  215.                     if (n + len >= size) 
  216.                         text = (char*)realloc(text, size += 256);
  217.                     memcpy(text + len, buf, n);
  218.                     len += n;
  219.                 }
  220.  
  221.                 if (c == 0x01) {
  222.                     cur->data.text.len  = len;
  223.                     cur->data.text.text = text;
  224.                 } else {
  225.                     cur->data.comment.len  = len;
  226.                     cur->data.comment.text = text;
  227.                 }
  228.             } else {
  229.                 /*
  230.                 **  Unrecogonized extension, consume it.
  231.                 */
  232.                 while (GetDataBlock(fd, buf) > 0)
  233.                     ;
  234.             }
  235.         } else if (c == ',') {
  236.             if (! ReadOK(fd,buf,9))
  237.                    ERROR("couldn't read left/top/width/height");
  238.  
  239.             cur = NEW(GIFData);
  240.  
  241.             cur->type   = gif_image;
  242.             cur->info   = info;
  243.             cur->x      = MKINT(buf[0], buf[1]);
  244.             cur->y      = MKINT(buf[2], buf[3]);
  245.             cur->width  = MKINT(buf[4], buf[5]);
  246.             cur->height = MKINT(buf[6], buf[7]);
  247.             cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
  248.             if (BitSet(buf[8], LOCALCOLORMAP)) {
  249.                 if (readColorMap(fd, cur->data.image.cmapSize, 
  250.                                  cur->data.image.cmapData))
  251.                     ERROR("unable to get local colormap");
  252.             } else {
  253.                 cur->data.image.cmapSize = 0;
  254.  
  255.             }
  256.             cur->data.image.data = (unsigned char *)malloc(cur->width * cur->height);
  257.             cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
  258.             readImage(fd, BitSet(buf[8], INTERLACE), 
  259.                 cur->width, cur->height, cur->data.image.data);
  260.  
  261.             resetInfo = TRUE;
  262.         } else {
  263.             INFO_MSG(("bogus character 0x%02x, ignoring", (int)c));
  264.         }
  265.  
  266.         if (cur != NULL) {
  267.             *end = cur;
  268.             end = &cur->next;
  269.             cur->next = NULL;
  270.         }
  271.     }
  272.  
  273.     if (c != ';')
  274.         ERROR("EOF / data stream" );
  275.  
  276. out:
  277.  
  278.     return stream;
  279. }
  280.  
  281. GIFStream *GIFRead(char *file)
  282. {
  283.     FILE        *fp = fopen(file, "rb");
  284.     GIFStream    *stream = NULL;
  285.  
  286.     if (fp != NULL) {
  287.         stream = GIFReadFP(fp);
  288.         fclose(fp);
  289.     }
  290.     return stream;
  291. }
  292.  
  293. static int readColorMap(FILE *fd, int size, 
  294.             unsigned char data[GIF_MAXCOLORS][3])
  295. {
  296.     int             i;
  297.     unsigned char   rgb[3 * GIF_MAXCOLORS];
  298.     unsigned char    *cp = rgb;
  299.  
  300.     if (! ReadOK(fd, rgb, size * 3))
  301.         return TRUE;
  302.  
  303.     for (i = 0; i < size; i++) {
  304.         data[i][0] = *cp++;
  305.         data[i][1] = *cp++;
  306.         data[i][2] = *cp++;
  307.     }
  308.  
  309.     return FALSE;
  310. }
  311.  
  312. /*
  313. **
  314. */
  315.  
  316. static int    ZeroDataBlock = FALSE;
  317.  
  318. static int GetDataBlock(FILE *fd, unsigned char *buf)
  319. {
  320.        unsigned char   count;
  321.  
  322.        if (! ReadOK(fd,&count,1)) {
  323.                INFO_MSG(("error in getting DataBlock size"));
  324.                return -1;
  325.        }
  326.  
  327.        ZeroDataBlock = count == 0;
  328.  
  329.        if ((count != 0) && (! ReadOK(fd, buf, count))) {
  330.                INFO_MSG(("error in reading DataBlock"));
  331.                return -1;
  332.        }
  333.  
  334.        return count;
  335. }
  336.  
  337. /*
  338. **
  339. **
  340. */
  341.  
  342. /*
  343. **  Pulled out of nextCode
  344. */
  345. static    int        curbit, lastbit, get_done, last_byte;
  346. static    int        return_clear;
  347. /*
  348. **  Out of nextLWZ
  349. */
  350. static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  351. static int      code_size, set_code_size;
  352. static int      max_code, max_code_size;
  353. static int      clear_code, end_code;
  354.  
  355. static void initLWZ(int input_code_size)
  356. {
  357.     static int    inited = FALSE;
  358.  
  359.     set_code_size = input_code_size;
  360.     code_size     = set_code_size + 1;
  361.     clear_code    = 1 << set_code_size ;
  362.     end_code      = clear_code + 1;
  363.     max_code_size = 2 * clear_code;
  364.     max_code      = clear_code + 2;
  365.  
  366.     curbit = lastbit = 0;
  367.     last_byte = 2;
  368.     get_done = FALSE;
  369.  
  370.     return_clear = TRUE;
  371.  
  372.     sp = stack;
  373. }
  374.  
  375. static int nextCode(FILE *fd, int code_size)
  376. {
  377.     static unsigned char    buf[280];
  378.     static int maskTbl[16] = {
  379.         0x0000, 0x0001, 0x0003, 0x0007, 
  380.         0x000f, 0x001f, 0x003f, 0x007f,
  381.         0x00ff, 0x01ff, 0x03ff, 0x07ff,
  382.         0x0fff, 0x1fff, 0x3fff, 0x7fff,
  383.     };
  384.     int                     i, j, ret, end;
  385.  
  386.     if (return_clear) {
  387.         return_clear = FALSE;
  388.         return clear_code;
  389.     }
  390.  
  391.     end = curbit + code_size;
  392.  
  393.     if (end >= lastbit) {
  394.         int    count;
  395.  
  396.         if (get_done) {
  397.             if (curbit >= lastbit)
  398.                 ERROR("ran off the end of my bits" );
  399.             return -1;
  400.         }
  401.         buf[0] = buf[last_byte-2];
  402.         buf[1] = buf[last_byte-1];
  403.  
  404.         if ((count = GetDataBlock(fd, &buf[2])) == 0)
  405.             get_done = TRUE;
  406.  
  407.         last_byte = 2 + count;
  408.         curbit = (curbit - lastbit) + 16;
  409.         lastbit = (2+count)*8 ;
  410.  
  411.         end = curbit + code_size;
  412.     }
  413.  
  414.     j = end / 8;
  415.     i = curbit / 8;
  416.  
  417.         if (i == j) 
  418.                 ret = buf[i];
  419.         else if (i + 1 == j) 
  420.                 ret = buf[i] | (buf[i+1] << 8);
  421.         else 
  422.                 ret = buf[i] | (buf[i+1] << 8) | (buf[i+2] << 16);
  423.  
  424.         ret = (ret >> (curbit % 8)) & maskTbl[code_size];
  425.  
  426.     curbit += code_size;
  427.     
  428.     return ret;
  429. }
  430.  
  431. #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
  432.  
  433. static int nextLWZ(FILE *fd)
  434. {
  435.        static int    table[2][(1<< MAX_LWZ_BITS)];
  436.        static int    firstcode, oldcode;
  437.        int        code, incode;
  438.        register int    i;
  439.  
  440.        while ((code = nextCode(fd, code_size)) >= 0) {
  441.                if (code == clear_code) {
  442.                        for (i = 0; i < clear_code; ++i) {
  443.                                table[0][i] = 0;
  444.                                table[1][i] = i;
  445.                        }
  446.                        for (; i < (1<<MAX_LWZ_BITS); ++i)
  447.                                table[0][i] = table[1][i] = 0;
  448.                        code_size = set_code_size+1;
  449.                        max_code_size = 2*clear_code;
  450.                        max_code = clear_code+2;
  451.                        sp = stack;
  452.             do {
  453.                    firstcode = oldcode = nextCode(fd, code_size);
  454.             } while (firstcode == clear_code);
  455.  
  456.             return firstcode;
  457.                }
  458.            if (code == end_code) {
  459.                        int             count;
  460.                        unsigned char   buf[260];
  461.  
  462.                        if (ZeroDataBlock)
  463.                                return -2;
  464.  
  465.                        while ((count = GetDataBlock(fd, buf)) > 0)
  466.                                ;
  467.  
  468.                        if (count != 0)
  469.                                INFO_MSG(("missing EOD in data stream"));
  470.                        return -2;
  471.                }
  472.  
  473.                incode = code;
  474.  
  475.                if (code >= max_code) {
  476.                        *sp++ = firstcode;
  477.                        code = oldcode;
  478.                }
  479.  
  480.                while (code >= clear_code) {
  481.                        *sp++ = table[1][code];
  482.                        if (code == table[0][code])
  483.                                ERROR("circular table entry BIG ERROR");
  484.                        code = table[0][code];
  485.                }
  486.  
  487.                *sp++ = firstcode = table[1][code];
  488.  
  489.                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  490.                        table[0][code] = oldcode;
  491.                        table[1][code] = firstcode;
  492.                        ++max_code;
  493.                        if ((max_code >= max_code_size) &&
  494.                                (max_code_size < (1<<MAX_LWZ_BITS))) {
  495.                                max_code_size *= 2;
  496.                                ++code_size;
  497.                        }
  498.                }
  499.  
  500.                oldcode = incode;
  501.  
  502.                if (sp > stack)
  503.                        return *--sp;
  504.        }
  505.        return code;
  506. }
  507.  
  508. static void readImage(FILE *fd, int interlace, int width, int height, 
  509.             unsigned char *data)
  510. {
  511.        unsigned char    *dp, c;      
  512.        int        v, xpos = 0, ypos = 0, pass = 0;
  513.  
  514.     /*
  515.     **  Initialize the Compression routines
  516.     */
  517.     if (! ReadOK(fd,&c,1))
  518.         ERROR("EOF / read error on image data" );
  519.  
  520.     initLWZ(c);
  521.  
  522.     if (verbose)
  523.         INFO_MSG(("reading %d by %d%s GIF image",
  524.             width, height, interlace ? " interlaced" : ""));
  525.  
  526.     if (interlace) {
  527.         int    i;
  528.         int    pass = 0, step = 8;
  529.  
  530.         for (i = 0; i < height; i++) {
  531.             dp = &data[width * ypos];
  532.             for (xpos = 0; xpos < width; xpos++) {
  533.                 if ((v = readLWZ(fd)) < 0)
  534.                     goto fini;
  535.  
  536.                 *dp++ = v;
  537.             }
  538.             if ((ypos += step) >= height) {
  539.                 do {
  540.                     if (pass++ > 0)
  541.                         step /= 2;
  542.                     ypos = step / 2;
  543.                 } while (ypos > height);
  544.             }
  545.         }
  546.     } else {
  547.         dp = data;
  548.         for (ypos = 0; ypos < height; ypos++) {
  549.             for (xpos = 0; xpos < width; xpos++) {
  550.                 if ((v = readLWZ(fd)) < 0)
  551.                     goto fini;
  552.  
  553.                 *dp++ = v;
  554.             }
  555.         }
  556.     }
  557.  
  558. fini:
  559.        if (readLWZ(fd) >= 0)
  560.                INFO_MSG(("too much input data, ignoring extra..."));
  561.  
  562.        return;
  563. }
  564.