home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11.lha / ccs-lib / lib / gif_r.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-03  |  10.1 KB  |  429 lines

  1. /*    GIF_R . C
  2. #
  3. %    Copyright (c)    Jin Guojun
  4. %
  5. % AUTHOR:    Jin, Guojun - LBL    10/01/91
  6. */
  7.  
  8. #include "header.def"
  9. #include "imagedef.h"
  10.  
  11. #define    MAX_LWZ_BITS    12
  12. #define INTERLACE    0x40
  13. #define COLORMAP_FLAG    0x80
  14.  
  15. #define    ReadOk(file, buffer, len)    ((*img->read)(buffer, len, 1, file)==1)
  16. #define LM_to_uint(a,b)            ( ((b)<<8) | (a) )
  17.  
  18. struct    {
  19.     int    transparent, delayTime, inputFlag, disposal;
  20.     } Gif89 = { -1, -1, -1, 0 };
  21.  
  22. static    int    ZeroDataBlock, ICount;
  23. GS    GifScreen;
  24.  
  25.  
  26. static
  27. GetDataBlock(fp, buf)
  28. FILE    *fp;
  29. byte    *buf;
  30. {
  31. byte    count;
  32.  
  33.     if (fread(&count, 1, 1, fp) != 1)
  34.         return    prgmerr(0, "error in getting junk size");
  35.  
  36.     ZeroDataBlock = !count;
  37.     if ((count) && (fread(buf, count, 1, fp) != 1))
  38.         return    prgmerr(0, "error in reading junk");
  39. return count;
  40. }
  41.  
  42. static
  43. DoExtension(fp, label)
  44. FILE    *fp;
  45. int    label;
  46. {
  47. static char    buf[256];
  48. char        *str;
  49.  
  50.     switch (label)    {
  51.     case 0x01:        /* Plain Text Extension */
  52.         str = "Plain Text Extension";
  53. #ifdef notdef
  54.         if (!GetDataBlock(fp, buf));
  55.  
  56.         lpos   = LM_to_uint(buf[0], buf[1]);
  57.         tpos   = LM_to_uint(buf[2], buf[3]);
  58.         width  = LM_to_uint(buf[4], buf[5]);
  59.         height = LM_to_uint(buf[6], buf[7]);
  60.         cellw  = buf[8];
  61.         cellh  = buf[9];
  62.         foreground = buf[10];
  63.         background = buf[11];
  64.  
  65.         while (GetDataBlock(fp, buf)) {
  66.             PPM_ASSIGN(image[ypos][xpos],
  67.                 cmap[v].r, cmap[v].g, cmap[v].b);
  68.             ++index;
  69.         }
  70.         return FALSE;
  71. #else
  72.         break;
  73. #endif
  74.     case 0xFF:        /* Application Extension */
  75.         str = "Application Extension";
  76.         break;
  77.     case 0xFE:        /* Comment Extension */
  78.         str = "Comment Extension";
  79.         while (GetDataBlock(fp, buf))
  80.             DEBUGMESSAGE("gif comment: %s", buf);
  81.         return    0;
  82.     case 0xF9:        /* Graphic Control Extension */
  83.         str = "Graphic Control Extension";
  84.         (void) GetDataBlock(fp, buf);
  85.         Gif89.disposal    = (buf[0] >> 2) & 0x7;
  86.         Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  87.         Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  88.         if ((buf[0] & 0x1))
  89.             Gif89.transparent = buf[3];
  90.  
  91.         while (GetDataBlock(fp, buf));
  92.         return    0;
  93.     default:
  94.         str = buf;
  95.         sprintf(buf, "UNKNOWN (0x%02x)", label);
  96.         break;
  97.     }
  98.  
  99.     message("got a '%s' extension - please report it to koblas@mips.com",
  100.         str);
  101.  
  102.     while (GetDataBlock(fp, buf));
  103. return    0;
  104. }
  105.  
  106. static
  107. GetCode(fp, code_size, flag)
  108. FILE    *fp;
  109. int    code_size, flag;
  110. {
  111. static byte    buf[280];
  112. static int    curbit, lastbit, done, last_byte;
  113. int    i, j, ret;
  114. byte    count;
  115.  
  116.     if (flag) {
  117.         done = FALSE;
  118.         return    lastbit = curbit =0;
  119.     }
  120.  
  121.     if ((curbit+code_size) >= lastbit) {
  122.         if (done)
  123.             if (curbit >= lastbit)
  124.             return    prgmerr(0, "ran off the end of my bits");
  125.  
  126.         buf[0] = buf[last_byte-2];
  127.         buf[1] = buf[last_byte-1];
  128.  
  129.         if ((count = GetDataBlock(fp, &buf[2])) == 0)
  130.             done = TRUE;
  131.  
  132.         last_byte = 2 + count;
  133.         curbit = (curbit - lastbit) + 16;
  134.         lastbit = (2+count) << 3;
  135.     }
  136.     for (i=curbit, j=ret=0; j < code_size; ++i, ++j)
  137.         ret |= ((buf[i >> 3] & (1 << (i & 7))) != 0) << j;
  138.     curbit += code_size;
  139.  
  140. return ret;
  141. }
  142.  
  143. static
  144. LWZReadByte(fp, flag, input_code_size)
  145. FILE    *fp;
  146. int    flag, input_code_size;
  147. {
  148. static int    fresh = FALSE;
  149. static int    code_size, set_code_size,
  150.         max_code, max_code_size,
  151.     firstcode, oldcode,
  152.     clear_code, end_code,
  153.     table[2][(1 << MAX_LWZ_BITS)],
  154.     stack[(1 << (MAX_LWZ_BITS)) << 1], *sp;
  155. int    incode;
  156. register int    i, code;
  157.  
  158.     if (flag) {
  159.         set_code_size = input_code_size;
  160.         code_size = set_code_size+1;
  161.         clear_code = 1 << set_code_size ;
  162.         end_code = clear_code + 1;
  163.         max_code_size = clear_code << 1;
  164.         max_code = clear_code + 2;
  165.  
  166.         GetCode(fp, 0, fresh=TRUE);
  167.  
  168.         for (i=code=0; i < clear_code; ++i) {
  169.             table[0][i] = code;
  170.             table[1][i] = i;
  171.         }
  172.         for (; i < (1<<MAX_LWZ_BITS); ++i)
  173.             table[0][i] = table[1][i] = code;
  174.  
  175.         sp = stack;
  176.  
  177.         return    code;
  178.     } else if (fresh) {
  179.         fresh = FALSE;
  180.         do {
  181.             firstcode = oldcode = GetCode(fp, code_size, FALSE);
  182.         } while (firstcode == clear_code);
  183.         return    firstcode;
  184.     }
  185.  
  186.     if (sp > stack)
  187.         return *--sp;
  188.  
  189.     while ((code = GetCode(fp, code_size, FALSE)) >= 0) {
  190.         if (code == clear_code) {
  191.             for (i=code=0; i < clear_code; ++i) {
  192.                 table[0][i] = code;
  193.                 table[1][i] = i;
  194.             }
  195.             for (; i < (1<<MAX_LWZ_BITS); ++i)
  196.                 table[0][i] = table[1][i] = code;
  197.             code_size = set_code_size+1;
  198.             max_code_size = clear_code << 1;
  199.             max_code = clear_code+2;
  200.             sp = stack;
  201.             firstcode = oldcode = GetCode(fp, code_size, FALSE);
  202.             return    firstcode;
  203.         } else if (code == end_code) {
  204.             int    count;
  205.             byte    buf[260];
  206.  
  207.             if (ZeroDataBlock)
  208.                 return -2;
  209.  
  210.             while ((count = GetDataBlock(fp, buf)) > 0);/* fetch junk */
  211.  
  212.             if (count)
  213.                 message("missing EOD in data stream (common occurance)");
  214.             return -2;
  215.         }
  216.  
  217.         incode = code;
  218.         if (code >= max_code) {
  219.             *sp++ = firstcode;
  220.             code = oldcode;
  221.         }
  222.  
  223.         while (code >= clear_code) {
  224.             *sp++ = table[1][code];
  225.             if (code == table[0][code])
  226.              return    prgmerr(0, "circular table entry BIG ERROR");
  227.             code = table[0][code];
  228.         }
  229.  
  230.         *sp++ = firstcode = table[1][code];
  231.  
  232.         if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  233.             table[0][code] = oldcode;
  234.             table[1][code] = firstcode;
  235.             ++max_code;
  236.             if ((max_code >= max_code_size) &&
  237.                 (max_code_size < (1<<MAX_LWZ_BITS))) {
  238.                 max_code_size <<= 1;
  239.                 ++code_size;
  240.             }
  241.         }
  242.  
  243.         oldcode = incode;
  244.         if (sp > stack)
  245.             return *--sp;
  246.     }
  247. return code;
  248. }
  249.  
  250. static
  251. ReadImage(img, cmap, interlace, ignore)
  252. U_IMAGE    *img;
  253. color_cell    *cmap;
  254. {
  255. bool    OsameI = img->color_form==img->in_color;
  256. byte    c, *obp, *scan[3];
  257. int    ypos=0, pass=0, len=img->width;
  258. register unsigned int    r=RED_to_GRAY, g=GREEN_to_GRAY, b=BLUE_to_GRAY;
  259. register int    v, xpos=0;
  260.  
  261.     obp = scan[0] = (byte*)img->src;
  262.     for (v=1; v<img->dpy_channels; v++)
  263.         scan[v] = scan[v-1] + len;
  264.     /*    Initialize the Compression routines    */
  265.     if (!ReadOk(img->IN_FP, &c, 1))
  266.         return    prgmerr(DEBUGANY, "EOF / read on image data");
  267.  
  268.     if (LWZReadByte(img->IN_FP, TRUE, c) < 0)
  269.         return    prgmerr(DEBUGANY, "error reading image");
  270.  
  271.     /*    If this is an "uninteresting picture" ignore it    */
  272.     if (ignore) {
  273.         message("skipping image...");
  274.         while (LWZReadByte(img->IN_FP, FALSE, c) >= 0);
  275.         return    0;
  276.     }
  277.  
  278.     DEBUGMESSAGE("reading %d x %d %s GIF image",
  279.             len, img->height, interlace ? "interlaced" : "");
  280.  
  281.     while ((v = LWZReadByte(img->IN_FP, FALSE, c)) >= 0) {
  282.  
  283.         if (OsameI || img->mid_type == COLOR_PS)
  284.             obp[xpos] = v;
  285.         else if (img->color_form != CFM_SGF)
  286.             scan[0][xpos] = cmap[v].r,
  287.             scan[1][xpos] = cmap[v].g,
  288.             scan[2][xpos] = cmap[v].b;
  289.         else    /* grayscale */
  290.         obp[xpos] = (r*cmap[v].r + g*cmap[v].g + b*cmap[v].b) >> 8;
  291.  
  292.         if (++xpos==len) {
  293.             xpos = 0;
  294.             if (interlace) {
  295.             switch (pass) {
  296.             case 0:
  297.             case 1:    ypos += 8; break;
  298.             case 2:
  299.                 ypos += 4; break;
  300.             case 3:
  301.                 ypos += 2; break;
  302.             }
  303.             if (ypos >= img->height) {
  304.                 switch (++pass) {
  305.                 case 1:    ypos = 4; break;
  306.                 case 2:    ypos = 2; break;
  307.                 case 3:    ypos = 1; break;
  308.                 }
  309.             }
  310.             } else    ypos++;
  311.             obp = (byte*)img->src + ypos*len;
  312.             scan[0] = (byte *)img->src + ypos*len*img->dpy_channels;
  313.             for (v=1; v<img->dpy_channels; v++)
  314.             scan[v] = scan[v-1] + len;
  315.         }
  316.     }
  317.     if (img->mid_type == RLE)
  318.         img->channels = img->dpy_channels;
  319. return    (v == -2) ? ypos * len : v;    /* sometimes ypos = img->h + 1 */
  320. }
  321.  
  322.  
  323. gif_header_handle(job, img, ac, av, vva_p)
  324. U_IMAGE    *img;
  325. int    ac;    /* can be used as image numbers */
  326. char    **av;
  327. VType    *vva_p;    /* O_same_I */
  328. {
  329. bool    useGlobalColormap, status=0;
  330. int    img_num = (ac && ac < 64) ? ac : 1;    /* max 64 animators    */
  331. byte    buf[16], c, version[4];
  332.  
  333.     switch (job) {
  334.     case HEADER_READ:
  335.     case HEADER_FREAD:
  336.     if (!av || img->in_type != GIF) {
  337.         if (!av)
  338.             fseek(img->IN_FP, 0, 0);
  339.         if (!ReadOk(img->IN_FP, buf, 6))
  340.             prgmerr(DEBUGANY, "error reading magic number");
  341.         if (strncmp(buf, "GIF", 3))
  342.             return    EOF;
  343.  
  344.         strncpy(version, buf+3, 3);
  345.         version[3] = ICount = 0;
  346.         if ((strcmp(version, "87a")) && (strcmp(version, "89a"))) {
  347.             DEBUGMESSAGE("not '87a' or '89a' version");
  348.             status = EOF-1;
  349.         }
  350.         if (!ReadOk(img->IN_FP, buf, 7))
  351.             return    prgmerr(DEBUGANY, "read gif screen descriptor");
  352.  
  353.         GifScreen.Width    = LM_to_uint(buf[0], buf[1]);
  354.         GifScreen.Height = LM_to_uint(buf[2], buf[3]);
  355.         GifScreen.CmapLen = img->cmaplen = 2 << (buf[4] & 7);
  356.         GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
  357.         GifScreen.Background    = buf[5];
  358.         GifScreen.AspectRatio    = buf[6];
  359.  
  360.         img->in_type = GIF;
  361.         img->in_form = IFMT_SCF;
  362.         img->in_color = img->color_form = CFM_SCF;
  363.         img->channels = img->dpy_channels = img->pxl_in = 1;
  364.  
  365.         if (buf[4] & COLORMAP_FLAG)    /* Global Colormap */
  366.             if (!ReadRGBMap(img,
  367.             GifScreen.ColorMap, GifScreen.CmapLen, vva_p))
  368.             return    prgmerr(DEBUGANY, "reading global colormap");
  369.  
  370.         if (GifScreen.AspectRatio) {
  371.         register float    r = ( GifScreen.AspectRatio + 15.0 ) / 64.0;
  372.         message("warning - non-square pixels; to fix do a '%cscale %g'",
  373.             r < 1.0 ? 'x' : 'y', r < 1.0 ? 1.0 / r : r);
  374.         }
  375.     }
  376.     Loop {
  377.         if (!ReadOk(img->IN_FP, &c, 1))
  378.         return    prgmerr(DEBUGANY, "EOF / read error on image data");
  379.  
  380.         if (c == ';')    /* GIF terminator */
  381.         if (ICount < img_num)
  382.             return    prgmerr(0, "only %d image%s found in file",
  383.                  ICount, ICount>1 ? "s" : "");
  384.  
  385.         if (c == '!') {     /* Extension */
  386.         if (! ReadOk(img->IN_FP, &c, 1))
  387.             return    prgmerr(DEBUGANY, "EOF on reading extention function code");
  388.         DoExtension(img->IN_FP, c);
  389.         continue;
  390.         }
  391.  
  392.         if (c != ',') {    /* Not a valid start character */
  393.         DEBUGMESSAGE("bogus character 0x%02x, ignoring", (int) c);
  394.         continue;
  395.         }
  396.         ++ICount;    break;
  397.     }    /* end Loop */
  398.  
  399.     if (!ReadOk(img->IN_FP, buf, 9))
  400.         return    prgmerr(DEBUGANY, "reading left/top/width/height");
  401.  
  402.     useGlobalColormap = !(buf[8] & COLORMAP_FLAG);
  403.  
  404.     /*    img->binary_img = !(buf[8] & 0x7);    */
  405.     if (!useGlobalColormap)
  406.         if (!ReadRGBMap(img, GifScreen.ColorMap,
  407.             img->cmaplen = 1 << ((buf[8] & 0x7) + 1), vva_p))
  408.             return    prgmerr(DEBUGANY, "reading local colormap");
  409.     img->width = LM_to_uint(buf[4], buf[5]);
  410.     img->height = LM_to_uint(buf[6], buf[7]);
  411.     GifScreen.interlace = buf[8] & INTERLACE;
  412.     GifScreen.jumpover = ICount != img_num;
  413.     break;
  414.     case HEADER_WRITE:
  415.     default:    status = prgmerr(0, "no sunch gif job %d", job);
  416.     }
  417. return    status;
  418. }
  419.  
  420. read_gif_image(img, gs, num_img)
  421. U_IMAGE    *img;
  422. GS    *gs;
  423. {
  424. /* Since out (dpy) image channels >= input image's, so use dpy_channels    */
  425. verify_buffer_size(&img->src, img->width*img->height, img->dpy_channels,
  426.         "gif-src");
  427. return    ReadImage(img, gs->ColorMap, gs->interlace, gs->jumpover);
  428. }
  429.