"Fossies" - the Fresh Open Source Software Archive

Member "xearth-1.1/gifout.c" (7 Nov 1999, 12059 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * giflib/gifout.c
    3  * kirk johnson
    4  * may 1990
    5  *
    6  * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
    7  *
    8  * Parts of the source code (as marked) are:
    9  *   Copyright (C) 1989, 1990, 1991 by Jim Frost
   10  *   Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
   11  *
   12  * Permission to use, copy, modify and freely distribute xearth for
   13  * non-commercial and not-for-profit purposes is hereby granted
   14  * without fee, provided that both the above copyright notice and this
   15  * permission notice appear in all copies and in supporting
   16  * documentation.
   17  *
   18  * Unisys Corporation holds worldwide patent rights on the Lempel Zev
   19  * Welch (LZW) compression technique employed in the CompuServe GIF
   20  * image file format as well as in other formats. Unisys has made it
   21  * clear, however, that it does not require licensing or fees to be
   22  * paid for freely distributed, non-commercial applications (such as
   23  * xearth) that employ LZW/GIF technology. Those wishing further
   24  * information about licensing the LZW patent should contact Unisys
   25  * directly at (lzw_info@unisys.com) or by writing to
   26  *
   27  *   Unisys Corporation
   28  *   Welch Licensing Department
   29  *   M/S-C1SW19
   30  *   P.O. Box 500
   31  *   Blue Bell, PA 19424
   32  *
   33  * The author makes no representations about the suitability of this
   34  * software for any purpose. It is provided "as is" without express or
   35  * implied warranty.
   36  *
   37  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   38  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
   39  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
   40  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   41  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
   42  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   43  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   44  */
   45 
   46 #include <stdio.h>
   47 #include "port.h"
   48 #include "gifint.h"
   49 #include "kljcpyrt.h"
   50 
   51 
   52 /****
   53  **
   54  ** local #defines
   55  **
   56  ****/
   57 
   58 #define HASHSZ     (2048)
   59 #define HASH(p, e) (((p)&(HASHSZ-1))^(e))
   60 
   61 #define PUT_CODE(val)                       \
   62 {                                           \
   63   work_data |= ((long) (val) << work_bits); \
   64   work_bits += code_size;                   \
   65   while (work_bits >= 8)                    \
   66   {                                         \
   67     PUT_BYTE(work_data & 0xFF);             \
   68     work_data >>= 8;                        \
   69     work_bits  -= 8;                        \
   70   }                                         \
   71 }
   72 
   73 #define PUT_BYTE(val)                 \
   74 {                                     \
   75   buf[buf_idx++] = (val);             \
   76   if (buf_idx == 255)                 \
   77   {                                   \
   78     write_data_block(255, buf, outs); \
   79     buf_idx = 0;                      \
   80   }                                   \
   81 }
   82 
   83 
   84 /****
   85  **
   86  ** local variables
   87  **
   88  ****/
   89 
   90 static int  cmap_bits _P((int));
   91 static int  root_bits _P((int));
   92 static void put_clr_code _P((void));
   93 static void write_data_block _P((int, BYTE *, FILE *));
   94 static void reset_string_out _P((void));
   95 static void add_string_out _P((int, int));
   96 static int  find_string_out _P((int, int));
   97 static void gifout_fatal _P((const char *)) _noreturn;
   98 
   99 
  100 static BYTE file_open  = 0;     /* status flags */
  101 static BYTE image_open = 0;
  102 
  103 static int rast_width;          /* raster width */
  104 static int rast_height;         /* raster height */
  105 static int ncolors;             /* number of colors */
  106 static int img_width;           /* image width */
  107 static int img_height;          /* image height */
  108 
  109 static FILE *outs;              /* output file */
  110 
  111 static int root_size;           /* root code size */
  112 static int clr_code;            /* clear code */
  113 static int eoi_code;            /* end of info code */
  114 static int code_size;           /* current code size */
  115 static int code_mask;           /* current code mask */
  116 static int old_code;            /* previous code */
  117 
  118 static long work_data;          /* working bits */
  119 static int  work_bits;          /* working bit count */
  120 
  121 static BYTE buf[256];           /* byte buffer */
  122 static int  buf_idx;            /* buffer index */
  123 
  124 static int table_size;          /* string table size */
  125 static int htable[HASHSZ];
  126 static int pref_extn[STAB_SIZE]; /* (prefix << 16) | extension */
  127 static int next[STAB_SIZE];
  128 
  129 
  130 /****
  131  **
  132  ** exported procedures
  133  **
  134  ****/
  135 
  136 /*
  137  * open a GIF file for writing on stream s
  138  */
  139 int gifout_open_file(s, w, h, sz, cmap, bg)
  140      FILE *s;
  141      int   w;                   /* raster width (in pixels) */
  142      int   h;                   /* raster height (in pixels) */
  143      int   sz;                  /* number of colors */
  144      BYTE  cmap[3][256];        /* global colormap */
  145      int   bg;                  /* background color index */
  146 {
  147   int i;
  148   int pixel_bits;
  149 
  150   /* make sure there isn't already a file open */
  151   if (file_open)
  152     return GIFLIB_ERR_FAO;
  153 
  154   /* remember that we've got this file open */
  155   file_open   = 1;
  156   outs        = s;
  157   rast_width  = w;
  158   rast_height = h;
  159 
  160   /* write GIF signature */
  161   if (fwrite(GIF_SIG, sizeof(char), GIF_SIG_LEN, outs) != GIF_SIG_LEN)
  162     return GIFLIB_ERR_OUT;
  163 
  164   /* write screen descriptor */
  165   pixel_bits = cmap_bits(sz);
  166   ncolors    = 1 << pixel_bits;
  167 
  168   buf[0] = (w & 0x00FF);
  169   buf[1] = (w & 0xFF00) >> 8;
  170   buf[2] = (h & 0x00FF);
  171   buf[3] = (h & 0xFF00) >> 8;
  172   buf[4] = (pixel_bits - 1) | 0x80;
  173   buf[5] = bg;
  174   buf[6] = 0;
  175 
  176   if (fwrite(buf, sizeof(char), GIF_SD_SIZE, outs) != GIF_SD_SIZE)
  177     return GIFLIB_ERR_OUT;
  178 
  179   /* write (global) color map */
  180   for (i=0; i<sz; i++)
  181   {
  182     buf[GIFLIB_RED] = cmap[GIFLIB_RED][i];
  183     buf[GIFLIB_GRN] = cmap[GIFLIB_GRN][i];
  184     buf[GIFLIB_BLU] = cmap[GIFLIB_BLU][i];
  185 
  186     if (fwrite(buf, sizeof(BYTE), (unsigned) 3, outs) != 3)
  187       return GIFLIB_ERR_OUT;
  188   }
  189 
  190   for (i=sz; i<ncolors; i++)
  191   {
  192     buf[GIFLIB_RED] = 0;
  193     buf[GIFLIB_GRN] = 0;
  194     buf[GIFLIB_BLU] = 0;
  195 
  196     if (fwrite(buf, sizeof(BYTE), (unsigned) 3, outs) != 3)
  197       return GIFLIB_ERR_OUT;
  198   }
  199 
  200   /* done! */
  201   return GIFLIB_SUCCESS;
  202 }
  203 
  204 
  205 /*
  206  * open a new GIF image for writing in the current GIF file
  207  */
  208 int gifout_open_image(left, top, w, h)
  209      int left;                  /* column index for left edge */
  210      int top;                   /* row index for top edge */
  211      int w;                     /* image width (in pixels) */
  212      int h;                     /* image height (in pixels) */
  213 {
  214   /* make sure there's a file open */
  215   if (!file_open)
  216     return GIFLIB_ERR_NFO;
  217 
  218   /* make sure there isn't already an image open */
  219   if (image_open)
  220     return GIFLIB_ERR_IAO;
  221 
  222   /* remember that we've got this image open */
  223   image_open = 1;
  224   img_width  = w;
  225   img_height = h;
  226 
  227   /* write image separator */
  228   putc(GIF_SEPARATOR, outs);
  229 
  230   /* write image descriptor */
  231   buf[0] = (left & 0x00FF);
  232   buf[1] = (left & 0xFF00) >> 8;
  233   buf[2] = (top  & 0x00FF);
  234   buf[3] = (top  & 0xFF00) >> 8;
  235   buf[4] = (w & 0x00FF);
  236   buf[5] = (w & 0xFF00) >> 8;
  237   buf[6] = (h & 0x00FF);
  238   buf[7] = (h & 0xFF00) >> 8;
  239   buf[8] = 0;
  240 
  241   if (fwrite(buf, sizeof(BYTE), GIF_ID_SIZE, outs) != GIF_ID_SIZE)
  242     return GIFLIB_ERR_OUT;
  243 
  244   /* initialize raster data stream */
  245   root_size = root_bits(ncolors);
  246   putc(root_size, outs);
  247 
  248   clr_code  = 1 << root_size;
  249   eoi_code  = clr_code + 1;
  250   code_size = root_size + 1;
  251   code_mask = (1 << code_size) - 1;
  252   old_code  = NULL_CODE;
  253 
  254   work_bits = 0;
  255   work_data = 0;
  256 
  257   buf_idx = 0;
  258 
  259   /* initialize string table */
  260   reset_string_out();
  261 
  262   /* output initial clear code */
  263   put_clr_code();
  264 
  265   /* done! */
  266   return GIFLIB_SUCCESS;
  267 }
  268 
  269 
  270 /*
  271  * write a pixel into the current image
  272  */
  273 void gifout_put_pixel(val)
  274      int val;                   /* pixel color index */
  275 {
  276   int idx;
  277 
  278   /* see if string is in table already */
  279   idx = find_string_out(old_code, val);
  280 
  281   if (idx != NULL_CODE)
  282   {
  283     /* found a match */
  284     old_code = idx;
  285   }
  286   else
  287   {
  288     /* no match */
  289     PUT_CODE(old_code);
  290     add_string_out(old_code, val);
  291     old_code = val;
  292 
  293     /* check for full string table */
  294     if (table_size == STAB_SIZE)
  295     {
  296       /* output remaining code */
  297       PUT_CODE(old_code);
  298 
  299       /* reset encoder */
  300       put_clr_code();
  301     }
  302   }
  303 }
  304 
  305 
  306 /*
  307  * write a row of pixels into the current image
  308  */
  309 void gifout_put_row(row)
  310      int *row;                  /* array of size img_width */
  311 {
  312   int col;
  313   int idx;
  314 
  315   for (col=0; col<img_width; col++)
  316   {
  317     /* see if string is in table already */
  318     idx = find_string_out(old_code, row[col]);
  319 
  320     if (idx != NULL_CODE)
  321     {
  322       /* found a match */
  323       old_code = idx;
  324     }
  325     else
  326     {
  327       /* no match */
  328       PUT_CODE(old_code);
  329       add_string_out(old_code, row[col]);
  330       old_code = row[col];
  331 
  332       /* check for full string table */
  333       if (table_size == STAB_SIZE)
  334       {
  335         /* output remaining code */
  336         PUT_CODE(old_code);
  337 
  338         /* reset encoder */
  339         put_clr_code();
  340       }
  341     }
  342   }
  343 }
  344 
  345 
  346 /*
  347  * close an open GIF image
  348  */
  349 int gifout_close_image()
  350 {
  351   /* make sure there's an image open */
  352   if (!image_open)
  353     return GIFLIB_ERR_NIO;
  354 
  355   /* flush any remaining code */
  356   if (old_code != NULL_CODE)
  357     PUT_CODE(old_code);
  358 
  359   /* output end of info code */
  360   PUT_CODE(eoi_code);
  361 
  362   /* flush any extra bits */
  363   while (work_bits > 0)
  364   {
  365     PUT_BYTE(work_data & 0xFF);
  366     work_data >>= 8;
  367     work_bits  -= 8;
  368   }
  369 
  370   /* flush any extra bytes */
  371   if (buf_idx > 0)
  372     write_data_block(buf_idx, buf, outs);
  373 
  374   /* trailing zero byte */
  375   putc(0, outs);
  376 
  377   /* mark image as closed */
  378   image_open = 0;
  379 
  380   /* done! */
  381   return GIFLIB_SUCCESS;
  382 }
  383 
  384 
  385 /*
  386  * close an open GIF file
  387  */
  388 int gifout_close_file()
  389 {
  390   /* make sure there's a file open */
  391   if (!file_open)
  392     return GIFLIB_ERR_NFO;
  393 
  394   /* make sure there isn't an image open */
  395   if (image_open)
  396     return GIFLIB_ERR_ISO;
  397 
  398   /* write gif terminator */
  399   putc(GIF_TERMINATOR, outs);
  400 
  401   /* mark file as closed */
  402   file_open = 0;
  403 
  404   /* done! */
  405   return GIFLIB_SUCCESS;
  406 }
  407 
  408 
  409 /****
  410  **
  411  ** internal procedures
  412  **
  413  ****/
  414 
  415 static int cmap_bits(n)
  416      int n;
  417 {
  418   int nbits;
  419 
  420   if (n < 2)
  421     gifout_fatal("cmap_bits(): argument out of range");
  422 
  423   n    -= 1;
  424   nbits = 0;
  425 
  426   while (n != 0)
  427   {
  428     n    >>= 1;
  429     nbits += 1;
  430   }
  431 
  432   return nbits;
  433 }
  434 
  435 
  436 static int root_bits(n)
  437      int n;
  438 {
  439   int rslt;
  440 
  441   rslt = cmap_bits(n);
  442   if (rslt < 2)
  443     rslt = 2;
  444 
  445   return rslt;
  446 }
  447 
  448 
  449 static void put_clr_code()
  450 {
  451   /* output clear code */
  452   PUT_CODE(clr_code);
  453 
  454   /* reset raster data stream */
  455   code_size = root_size + 1;
  456   code_mask = (1 << code_size) - 1;
  457   old_code  = NULL_CODE;
  458 
  459   /* clear the string table */
  460   reset_string_out();
  461 }
  462 
  463 
  464 static void write_data_block(cnt, outbuf, s)
  465      int   cnt;
  466      BYTE *outbuf;
  467      FILE *s;
  468 {
  469   putc(cnt, s);
  470 
  471   if (fwrite(outbuf, sizeof(BYTE), (unsigned) cnt, s) != cnt)
  472     gifout_fatal("write_data_block(): problems writing data block");
  473 }
  474 
  475 
  476 static void reset_string_out()
  477 {
  478   int i;
  479 
  480   for (i=0; i<HASHSZ; i++)
  481     htable[i] = NULL_CODE;
  482 
  483   table_size = eoi_code + 1;
  484 }
  485 
  486 
  487 static void add_string_out(p, e)
  488      int p;
  489      int e;
  490 {
  491   int idx;
  492 
  493   idx = HASH(p, e);
  494 
  495   pref_extn[table_size] = (p << 16) | e;
  496   next[table_size]      = htable[idx];
  497   htable[idx]           = table_size;
  498 
  499   if ((table_size > code_mask) && (code_size < 12))
  500   {
  501     code_size += 1;
  502     code_mask  = (1 << code_size) - 1;
  503   }
  504 
  505   table_size += 1;
  506 }
  507 
  508 
  509 static int find_string_out(p, e)
  510      int p;
  511      int e;
  512 {
  513   int idx;
  514   int tmp;
  515   int rslt;
  516 
  517   if (p == NULL_CODE)
  518   {
  519     /* a lone symbol is always in table */
  520     rslt = e;
  521   }
  522   else
  523   {
  524     rslt = NULL_CODE;
  525 
  526     /* search the hash table */
  527     idx = htable[HASH(p, e)];
  528     tmp = (p << 16) | e;
  529     while (idx != NULL_CODE)
  530     {
  531       if (pref_extn[idx] == tmp)
  532       {
  533         rslt = idx;
  534         break;
  535       }
  536       else
  537       {
  538         idx = next[idx];
  539       }
  540     }
  541   }
  542 
  543   return rslt;
  544 }
  545 
  546 
  547 /*
  548  * semi-graceful fatal error mechanism
  549  */
  550 static void gifout_fatal(msg)
  551      const char *msg;
  552 {
  553   fprintf(stderr, "\n");
  554   fprintf(stderr, "gifout.c: fatal error\n");
  555   fprintf(stderr, "    %s\n", msg);
  556   exit(1);
  557 }