Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

gifwrite.c

Go to the documentation of this file.
00001 /* gifwrite.c - Functions to write GIFs.
00002    Copyright (C) 1997-2001 Eddie Kohler, eddietwo@lcs.mit.edu
00003    This file is part of the GIF library.
00004 
00005    The GIF library is free software*. With the exception of this file, the GIF
00006    library is distributed under the GNU General Public License, version 2 or
00007    later; you can copy, distribute, or alter it at will, as long as this
00008    notice is kept intact and this source code is made available. There is no
00009    warranty, express or implied. This file is distributed in the public
00010    domain.
00011    
00012    *The LZW compression method used by GIFs is patented. Unisys, the patent
00013    holder, allows the compression algorithm to be used without a license in
00014    software distributed at no cost to the user. */
00015 
00016 #ifdef HAVE_CONFIG_H
00017 # include "config.h"
00018 #elif !defined(__cplusplus) && !defined(inline)
00019 /* Assume we don't have inline by default */
00020 # define inline
00021 #endif
00022 #include "gif.h"
00023 #include <stdarg.h>
00024 #include <string.h>
00025 #ifdef __cplusplus
00026 extern "C" {
00027 #endif
00028 
00029 #define WRITE_BUFFER_SIZE       255
00030 #define NODES_SIZE              GIF_MAX_CODE
00031 #define LINKS_SIZE              GIF_MAX_CODE
00032 
00033 /* 1.Aug.1999 - Removed code hashing in favor of an adaptive tree strategy
00034    based on Whirlgif-3.04, written by Hans Dinsen-Hansen <dino@danbbs.dk>. Mr.
00035    Dinsen-Hansen brought the adaptive tree strategy to my attention and argued
00036    at length that it was better than hashing. In fact, he was right: it runs a
00037    lot faster. However, it does NOT create "better" results in any way.
00038    
00039    Each code is represented by a Node. The Nodes form a tree with variable
00040    fan-out -- up to `clear_code' children per Node. There are two kinds of
00041    Node, TABLE and LINKS. In a TABLE node, the children are stored in a table
00042    indexed by suffix -- thus, it's very efficient to determine a given child.
00043    In a LINKS node, the existent children are stored in a linked list. This is
00044    slightly slower to access. When a LINKS node gets more than
00045    `MAX_LINKS_TYPE-1' children, it is converted to a TABLE node. (This is why
00046    it's an adaptive tree.)
00047    
00048    Problems with this implementation: MAX_LINKS_TYPE is fixed, so GIFs with
00049    very small numbers of colors (2, 4, 8) won't get the speed benefits of
00050    TABLE nodes. */
00051 
00052 #define TABLE_TYPE              0
00053 #define LINKS_TYPE              1
00054 #define MAX_LINKS_TYPE          5
00055 typedef struct Gif_Node {
00056   
00057   Gif_Code code;
00058   byte type;
00059   byte suffix;
00060   struct Gif_Node *sibling;
00061   union {
00062     struct Gif_Node *s;
00063     struct Gif_Node **m;
00064   } child;
00065   
00066 } Gif_Node;
00067 
00068 
00069 typedef struct Gif_Context {
00070   
00071   Gif_Node *nodes;
00072   int nodes_pos;
00073   Gif_Node **links;
00074   int links_pos;
00075   
00076 } Gif_Context;
00077 
00078 
00079 typedef struct Gif_Writer {
00080   
00081   FILE *f;
00082   byte *v;
00083   u_int32_t pos;
00084   u_int32_t cap;
00085   int flags;
00086   int global_size;
00087   int local_size;
00088   void (*byte_putter)(byte, struct Gif_Writer *);
00089   void (*block_putter)(byte *, u_int16_t, struct Gif_Writer *);
00090   
00091 } Gif_Writer;
00092 
00093 
00094 #define gifputbyte(b, grr)      ((*grr->byte_putter)(b, grr))
00095 #define gifputblock(b, l, grr)  ((*grr->block_putter)(b, l, grr))
00096 
00097 static inline void
00098 gifputunsigned(u_int16_t uns, Gif_Writer *grr)
00099 {
00100   gifputbyte(uns & 0xFF, grr);
00101   gifputbyte(uns >> 8, grr);
00102 }
00103 
00104 
00105 static void
00106 file_byte_putter(byte b, Gif_Writer *grr)
00107 {
00108   fputc(b, grr->f);
00109 }
00110 
00111 static void
00112 file_block_putter(byte *block, u_int16_t size, Gif_Writer *grr)
00113 {
00114   fwrite(block, size, 1, grr->f);
00115 }
00116 
00117 
00118 static void
00119 memory_byte_putter(byte b, Gif_Writer *grr)
00120 {
00121   if (grr->pos >= grr->cap) {
00122     grr->cap *= 2;
00123     Gif_ReArray(grr->v, byte, grr->cap);
00124   }
00125   if (grr->v) {
00126     grr->v[grr->pos] = b;
00127     grr->pos++;
00128   }
00129 }
00130 
00131 static void
00132 memory_block_putter(byte *data, u_int16_t len, Gif_Writer *grr)
00133 {
00134   if (grr->pos + len >= grr->cap) {
00135     grr->cap *= 2;
00136     Gif_ReArray(grr->v, byte, grr->cap);
00137   }
00138   if (grr->v) {
00139     memcpy(grr->v + grr->pos, data, len);
00140     grr->pos += len;
00141   }
00142 }
00143 
00144 
00145 static void
00146 change_node_to_table(Gif_Context *gfc, Gif_Node *work_node,
00147                      Gif_Node *next_node, Gif_Code clear_code)
00148 {
00149   /* change links node to table node */
00150   Gif_Code c;
00151   Gif_Node **table = &gfc->links[gfc->links_pos];
00152   Gif_Node *n;
00153   gfc->links_pos += clear_code;
00154   
00155   for (c = 0; c < clear_code; c++)
00156     table[c] = 0;
00157   table[next_node->suffix] = next_node;
00158   for (n = work_node->child.s; n; n = n->sibling)
00159     table[n->suffix] = n;
00160   
00161   work_node->type = TABLE_TYPE;
00162   work_node->child.m = table;
00163 }
00164 
00165 
00166 static void
00167 write_compressed_data(byte **img, u_int16_t width, u_int16_t height,
00168                       byte min_code_bits, Gif_Context *gfc, Gif_Writer *grr)
00169 {
00170   byte buffer[WRITE_BUFFER_SIZE];
00171   byte *buf;
00172   
00173   u_int16_t xleft;
00174   byte *imageline;
00175   
00176   u_int32_t leftover;
00177   byte bits_left_over;
00178   
00179   Gif_Node *work_node;
00180   Gif_Node *next_node;
00181   Gif_Code next_code;
00182   Gif_Code output_code;
00183   Gif_Code clear_code;
00184   Gif_Code eoi_code;
00185 #define CUR_BUMP_CODE (1 << cur_code_bits)
00186   byte suffix;
00187   
00188   byte cur_code_bits;
00189   
00190   /* Here we go! */
00191   gifputbyte(min_code_bits, grr);
00192   clear_code = 1 << min_code_bits;
00193   eoi_code = clear_code + 1;
00194   
00195   cur_code_bits = min_code_bits + 1;
00196   /* next_code set by first runthrough of output clear_code */
00197   GIF_DEBUG(("clear(%d) eoi(%d) bits(%d)",clear_code,eoi_code,cur_code_bits));
00198   
00199   work_node = 0;
00200   output_code = clear_code;
00201   /* Because output_code is clear_code, we'll initialize next_code, et al.
00202      below. */
00203   
00204   bits_left_over = 0;
00205   leftover = 0;
00206   buf = buffer;
00207   xleft = width;
00208   imageline = img[0];
00209   
00210   while (1) {
00211     
00212     /*****
00213      * Output `output_code' to the data stream. */
00214 
00215     leftover |= output_code << bits_left_over;
00216     bits_left_over += cur_code_bits;
00217     while (bits_left_over >= 8) {
00218       *buf++ = leftover & 0xFF;
00219       leftover = (leftover >> 8) & 0x00FFFFFF;
00220       bits_left_over -= 8;
00221       if (buf == buffer + WRITE_BUFFER_SIZE) {
00222         gifputbyte(WRITE_BUFFER_SIZE, grr);
00223         gifputblock(buffer, WRITE_BUFFER_SIZE, grr);
00224         buf = buffer;
00225       }
00226     }
00227     
00228     if (output_code == clear_code) {
00229       /* Clear data and prepare gfc */
00230       Gif_Code c;
00231       
00232       cur_code_bits = min_code_bits + 1;
00233       next_code = eoi_code + 1;
00234       
00235       /* The first clear_code nodes are reserved for single-pixel codes */
00236       gfc->nodes_pos = clear_code;
00237       gfc->links_pos = 0;
00238       for (c = 0; c < clear_code; c++) {
00239         gfc->nodes[c].code = c;
00240         gfc->nodes[c].type = LINKS_TYPE;
00241         gfc->nodes[c].suffix = c;
00242         gfc->nodes[c].child.s = 0;
00243       }
00244       
00245     } else if (next_code > CUR_BUMP_CODE) {
00246       /* bump up compression size */
00247       if (cur_code_bits == GIF_MAX_CODE_BITS) {
00248         output_code = clear_code;
00249         continue;
00250       } else
00251         cur_code_bits++;
00252       
00253     } else if (output_code == eoi_code)
00254       break;
00255     
00256     
00257     /*****
00258      * Find the next code to output. */
00259     
00260     /* If height is 0 -- no more pixels to write -- we output work_node next
00261        time around. */
00262     while (height != 0) {
00263       suffix = *imageline;
00264       if (suffix >= clear_code)
00265         /* should not happen unless GIF_WRITE_CAREFUL_MIN_CODE_BITS */
00266         suffix = 0;
00267       if (!work_node)
00268         next_node = &gfc->nodes[suffix];
00269       else if (work_node->type == TABLE_TYPE)
00270         next_node = work_node->child.m[suffix];
00271       else
00272         for (next_node = work_node->child.s; next_node;
00273              next_node = next_node->sibling)
00274           if (next_node->suffix == suffix)
00275             break;
00276       
00277       imageline++;
00278       xleft--;
00279       if (xleft == 0) {
00280         xleft = width;
00281         height--;
00282         img++;
00283         imageline = img[0];
00284       }
00285       
00286       if (!next_node) {
00287         /* We need to output the current code and add a new one to our
00288            dictionary. First reserve a node for the added code. It's
00289            LINKS_TYPE at first. */
00290         next_node = &gfc->nodes[gfc->nodes_pos];
00291         gfc->nodes_pos++;
00292         next_node->code = next_code;
00293         next_code++;
00294         next_node->type = LINKS_TYPE;
00295         next_node->suffix = suffix;
00296         next_node->child.s = 0;
00297         
00298         /* link next_node into work_node's set of children */
00299         if (work_node->type == TABLE_TYPE)
00300           work_node->child.m[suffix] = next_node;
00301         else if (work_node->type < MAX_LINKS_TYPE
00302                  || gfc->links_pos + clear_code > LINKS_SIZE) {
00303           next_node->sibling = work_node->child.s;
00304           work_node->child.s = next_node;
00305           work_node->type++;
00306         } else
00307           change_node_to_table(gfc, work_node, next_node, clear_code);
00308         
00309         /* Output the current code. */
00310         output_code = work_node->code;
00311         work_node = &gfc->nodes[suffix];
00312         goto found_output_code;
00313       }
00314       
00315       work_node = next_node;
00316     }
00317     
00318     /* Ran out of data if we get here. */
00319     output_code = (work_node ? work_node->code : eoi_code);
00320     work_node = 0;
00321     
00322    found_output_code: ;
00323   }
00324   
00325   if (bits_left_over > 0)
00326     *buf++ = leftover;
00327   
00328   if (buf != buffer) {
00329     GIF_DEBUG(("imageblock(%d)", buf - buffer));
00330     gifputbyte(buf - buffer, grr);
00331     gifputblock(buffer, buf - buffer, grr);
00332   }
00333   
00334   gifputbyte(0, grr);
00335 }
00336 
00337 
00338 static int
00339 calculate_min_code_bits(Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr)
00340 {
00341   int colors_used = -1, min_code_bits, i;
00342 
00343   if (grr->flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) {
00344     /* calculate m_c_b based on colormap */
00345     if (grr->local_size > 0)
00346       colors_used = grr->local_size;
00347     else if (grr->global_size > 0)
00348       colors_used = grr->global_size;
00349     
00350   } else if (gfi->compressed) {
00351     /* take m_c_b from compressed image */
00352     colors_used = 1 << gfi->compressed[0];
00353   
00354   } else if (gfi->img) {
00355     /* calculate m_c_b from uncompressed data */
00356     int x, y, width = gfi->width, height = gfi->height;
00357     colors_used = 0;
00358     for (y = 0; y < height && colors_used < 128; y++) {
00359       byte *data = gfi->img[y];
00360       for (x = width; x > 0; x--, data++)
00361         if (*data > colors_used)
00362           colors_used = *data;
00363     }
00364     colors_used++;
00365     
00366   } else {
00367     /* should never happen */
00368     colors_used = 256;
00369   }
00370   
00371   min_code_bits = 2;            /* min_code_bits of 1 isn't allowed */
00372   i = 4;
00373   while (i < colors_used) {
00374     min_code_bits++;
00375     i *= 2;
00376   }
00377 
00378   if ((grr->flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE)
00379       && gfi->compressed && gfi->compressed[0] != min_code_bits) {
00380     /* if compressed image disagrees with careful min_code_bits, recompress */
00381     if (Gif_UncompressImage(gfi))      
00382       Gif_FullCompressImage(gfs, gfi, grr->flags);
00383   }
00384   
00385   return min_code_bits;
00386 }
00387 
00388 static int
00389 write_image_data(Gif_Image *gfi, byte min_code_bits,
00390                  Gif_Context *gfc, Gif_Writer *grr)
00391 {
00392   byte **img = gfi->img;
00393   u_int16_t width = gfi->width, height = gfi->height;
00394     
00395   if (gfi->interlace) {
00396     u_int16_t y;
00397     byte **nimg = Gif_NewArray(byte *, height + 1);
00398     if (!nimg) return 0;
00399     
00400     for (y = 0; y < height; y++)
00401       nimg[y] = img[Gif_InterlaceLine(y, height)];
00402     nimg[height] = 0;
00403     
00404     write_compressed_data(nimg, width, height, min_code_bits, gfc, grr);
00405     
00406     Gif_DeleteArray(nimg);
00407   } else
00408     write_compressed_data(img, width, height, min_code_bits, gfc, grr);
00409   
00410   return 1;
00411 }
00412 
00413 
00414 static int get_color_table_size(Gif_Stream *, Gif_Image *, Gif_Writer *);
00415 
00416 int
00417 Gif_FullCompressImage(Gif_Stream *gfs, Gif_Image *gfi, int flags)
00418 {
00419   int ok = 0;
00420   byte min_code_bits;
00421   Gif_Writer grr;
00422   Gif_Context gfc;
00423   
00424   if (gfi->compressed && gfi->free_compressed) {
00425     (*gfi->free_compressed)((void *)gfi->compressed);
00426     gfi->compressed = 0;
00427   }
00428   
00429   gfc.nodes = Gif_NewArray(Gif_Node, NODES_SIZE);
00430   gfc.links = Gif_NewArray(Gif_Node *, LINKS_SIZE);
00431   
00432   grr.v = Gif_NewArray(byte, 1024);
00433   grr.pos = 0;
00434   grr.cap = 1024;
00435   grr.byte_putter = memory_byte_putter;
00436   grr.block_putter = memory_block_putter;
00437   grr.flags = flags;
00438   grr.global_size = get_color_table_size(gfs, 0, &grr);
00439   grr.local_size = get_color_table_size(gfs, gfi, &grr);
00440   
00441   if (!gfc.nodes || !gfc.links || !grr.v)
00442     goto done;
00443 
00444   min_code_bits = calculate_min_code_bits(gfs, gfi, &grr);
00445   ok = write_image_data(gfi, min_code_bits, &gfc, &grr);
00446   
00447  done:
00448   if (!ok) {
00449     Gif_DeleteArray(grr.v);
00450     grr.v = 0;
00451   }
00452   gfi->compressed = grr.v;
00453   gfi->compressed_len = grr.pos;
00454   gfi->free_compressed = Gif_DeleteArrayFunc;
00455   Gif_DeleteArray(gfc.nodes);
00456   Gif_DeleteArray(gfc.links);
00457   return grr.v != 0;
00458 }
00459 
00460 
00461 static int
00462 get_color_table_size(Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr)
00463 {
00464   Gif_Colormap *gfcm = (gfi ? gfi->local : gfs->global);
00465   int ncol, totalcol, i;
00466 
00467   if (!gfcm || gfcm->ncol <= 0)
00468     return 0;
00469 
00470   /* Make sure ncol is reasonable */
00471   ncol = gfcm->ncol;
00472 
00473   /* Possibly bump up 'ncol' based on 'transparent' values, if
00474      careful_min_code_bits */
00475   if (grr->flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) {
00476     if (gfi && gfi->transparent >= ncol)
00477       ncol = gfi->transparent + 1;
00478     else if (!gfi)
00479       for (i = 0; i < gfs->nimages; i++)
00480         if (gfs->images[i]->transparent >= ncol)
00481           ncol = gfs->images[i]->transparent + 1;
00482   }
00483 
00484   /* Make sure the colormap is a power of two entries! */
00485   /* GIF format doesn't allow a colormap with only 1 entry. */
00486   if (ncol > 256)
00487     ncol = 256;
00488   for (totalcol = 2; totalcol < ncol; totalcol *= 2)
00489     /* nada */;
00490   
00491   return totalcol;
00492 }
00493 
00494 static void
00495 write_color_table(Gif_Colormap *gfcm, int totalcol, Gif_Writer *grr)
00496 {
00497   Gif_Color *c = gfcm->col;
00498   int i, ncol = gfcm->ncol;
00499   
00500   for (i = 0; i < ncol && i < totalcol; i++, c++) {
00501     gifputbyte(c->red, grr);
00502     gifputbyte(c->green, grr);
00503     gifputbyte(c->blue, grr);
00504   }
00505   
00506   /* Pad out colormap with black. */
00507   for (; i < totalcol; i++) {
00508     gifputbyte(0, grr);
00509     gifputbyte(0, grr);
00510     gifputbyte(0, grr);
00511   }
00512 }
00513 
00514 
00515 static int
00516 write_image(Gif_Stream *gfs, Gif_Image *gfi, Gif_Context *gfc, Gif_Writer *grr)
00517 {
00518   byte min_code_bits, packed = 0;
00519   grr->local_size = get_color_table_size(gfs, gfi, grr);
00520   
00521   gifputbyte(',', grr);
00522   gifputunsigned(gfi->left, grr);
00523   gifputunsigned(gfi->top, grr);
00524   gifputunsigned(gfi->width, grr);
00525   gifputunsigned(gfi->height, grr);
00526   
00527   if (grr->local_size > 0) {
00528     int size = 2;
00529     packed |= 0x80;
00530     while (size < grr->local_size)
00531       size *= 2, packed++;
00532   }
00533   
00534   if (gfi->interlace) packed |= 0x40;
00535   gifputbyte(packed, grr);
00536   
00537   if (grr->local_size > 0)
00538     write_color_table(gfi->local, grr->local_size, grr);
00539 
00540   /* calculate min_code_bits here (because calculation may involve
00541      recompression, if GIF_WRITE_CAREFUL_MIN_CODE_BITS is true) */
00542   min_code_bits = calculate_min_code_bits(gfs, gfi, grr);
00543   
00544   /* use existing compressed data if it exists. This will tend to whip
00545      people's asses who uncompress an image, keep the compressed data around,
00546      but modify the uncompressed data anyway. That sucks. */
00547   if (gfi->compressed) {
00548     byte *compressed = gfi->compressed;
00549     u_int32_t compressed_len = gfi->compressed_len;
00550     while (compressed_len > 0) {
00551       u_int16_t amt = (compressed_len > 0x7000 ? 0x7000 : compressed_len);
00552       gifputblock(compressed, amt, grr);
00553       compressed += amt;
00554       compressed_len -= amt;
00555     }
00556     
00557   } else
00558     write_image_data(gfi, min_code_bits, gfc, grr);
00559   
00560   return 1;
00561 }
00562 
00563 
00564 static void
00565 write_logical_screen_descriptor(Gif_Stream *gfs, Gif_Writer *grr)
00566 {
00567   byte packed = 0x70;           /* high resolution colors */
00568   grr->global_size = get_color_table_size(gfs, 0, grr);
00569 
00570   Gif_CalculateScreenSize(gfs, 0);
00571   gifputunsigned(gfs->screen_width, grr);
00572   gifputunsigned(gfs->screen_height, grr);
00573   
00574   if (grr->global_size > 0) {
00575     u_int16_t size = 2;
00576     packed |= 0x80;
00577     while (size < grr->global_size && size < 256)
00578       size *= 2, packed++;
00579   }
00580   
00581   gifputbyte(packed, grr);
00582   gifputbyte(gfs->background, grr);
00583   gifputbyte(0, grr);           /* no aspect ratio information */
00584   
00585   if (grr->global_size > 0)
00586     write_color_table(gfs->global, grr->global_size, grr);
00587 }
00588 
00589 
00590 /* extension byte table:
00591    0x01 plain text extension
00592    0xCE name*
00593    0xF9 graphic control extension
00594    0xFE comment extension
00595    0xFF application extension
00596    */
00597 
00598 static void
00599 write_graphic_control_extension(Gif_Image *gfi, Gif_Writer *grr)
00600 {
00601   byte packed = 0;
00602   gifputbyte('!', grr);
00603   gifputbyte(0xF9, grr);
00604   gifputbyte(4, grr);
00605   if (gfi->transparent >= 0) packed |= 0x01;
00606   packed |= (gfi->disposal & 0x07) << 2;
00607   gifputbyte(packed, grr);
00608   gifputunsigned(gfi->delay, grr);
00609   gifputbyte((byte)gfi->transparent, grr);
00610   gifputbyte(0, grr);
00611 }
00612 
00613 
00614 static void
00615 blast_data(byte *data, int len, Gif_Writer *grr)
00616 {
00617   while (len > 0) {
00618     int s = len > 255 ? 255 : len;
00619     gifputbyte(s, grr);
00620     gifputblock(data, s, grr);
00621     data += s;
00622     len -= s;
00623   }
00624   gifputbyte(0, grr);
00625 }
00626 
00627 
00628 static void
00629 write_name_extension(char *id, Gif_Writer *grr)
00630 {
00631   gifputbyte('!', grr);
00632   gifputbyte(0xCE, grr);
00633   blast_data((byte *)id, strlen(id), grr);
00634 }
00635 
00636 
00637 static void
00638 write_comment_extensions(Gif_Comment *gfcom, Gif_Writer *grr)
00639 {
00640   int i;
00641   for (i = 0; i < gfcom->count; i++) {
00642     gifputbyte('!', grr);
00643     gifputbyte(0xFE, grr);
00644     blast_data((byte *)gfcom->str[i], gfcom->len[i], grr);
00645   }
00646 }
00647 
00648 
00649 static void
00650 write_netscape_loop_extension(u_int16_t value, Gif_Writer *grr)
00651 {
00652   gifputblock((byte *)"!\xFF\x0BNETSCAPE2.0\x03\x01", 16, grr);
00653   gifputunsigned(value, grr);
00654   gifputbyte(0, grr);
00655 }
00656 
00657 
00658 static void
00659 write_generic_extension(Gif_Extension *gfex, Gif_Writer *grr)
00660 {
00661   u_int32_t pos = 0;
00662   if (gfex->kind < 0) return;   /* ignore our private extensions */
00663   
00664   gifputbyte('!', grr);
00665   gifputbyte(gfex->kind, grr);
00666   if (gfex->kind == 255) {      /* an application extension */
00667     int len = gfex->application ? strlen(gfex->application) : 0;
00668     if (len) {
00669       gifputbyte(len, grr);
00670       gifputblock((byte *)gfex->application, len, grr);
00671     }
00672   }
00673   while (pos + 255 < gfex->length) {
00674     gifputbyte(255, grr);
00675     gifputblock(gfex->data + pos, 255, grr);
00676     pos += 255;
00677   }
00678   if (pos < gfex->length) {
00679     u_int32_t len = gfex->length - pos;
00680     gifputbyte(len, grr); 
00681     gifputblock(gfex->data + pos, len, grr);
00682   }
00683   gifputbyte(0, grr);
00684 }
00685 
00686 
00687 static int
00688 write_gif(Gif_Stream *gfs, Gif_Writer *grr)
00689 {
00690   int ok = 0;
00691   int i;
00692   Gif_Image *gfi;
00693   Gif_Extension *gfex = gfs->extensions;
00694   Gif_Context gfc;
00695   
00696   gfc.nodes = Gif_NewArray(Gif_Node, NODES_SIZE);
00697   gfc.links = Gif_NewArray(Gif_Node *, LINKS_SIZE);
00698   if (!gfc.nodes || !gfc.links)
00699     goto done;
00700   
00701   {
00702     byte isgif89a = 0;
00703     if (gfs->comment || gfs->loopcount > -1)
00704       isgif89a = 1;
00705     for (i = 0; i < gfs->nimages && !isgif89a; i++) {
00706       gfi = gfs->images[i];
00707       if (gfi->identifier || gfi->transparent != -1 || gfi->disposal ||
00708           gfi->delay || gfi->comment)
00709         isgif89a = 1;
00710     }
00711     if (isgif89a)
00712       gifputblock((byte *)"GIF89a", 6, grr);
00713     else
00714       gifputblock((byte *)"GIF87a", 6, grr);
00715   }
00716   
00717   write_logical_screen_descriptor(gfs, grr);
00718   
00719   if (gfs->loopcount > -1)
00720     write_netscape_loop_extension(gfs->loopcount, grr);
00721   
00722   for (i = 0; i < gfs->nimages; i++) {
00723     Gif_Image *gfi = gfs->images[i];
00724     while (gfex && gfex->position == i) {
00725       write_generic_extension(gfex, grr);
00726       gfex = gfex->next;
00727     }
00728     if (gfi->comment)
00729       write_comment_extensions(gfi->comment, grr);
00730     if (gfi->identifier)
00731       write_name_extension(gfi->identifier, grr);
00732     if (gfi->transparent != -1 || gfi->disposal || gfi->delay)
00733       write_graphic_control_extension(gfi, grr);
00734     if (!write_image(gfs, gfi, &gfc, grr))
00735       goto done;
00736   }
00737   
00738   while (gfex) {
00739     write_generic_extension(gfex, grr);
00740     gfex = gfex->next;
00741   }
00742   if (gfs->comment)
00743     write_comment_extensions(gfs->comment, grr);
00744   
00745   gifputbyte(';', grr);
00746   ok = 1;
00747   
00748  done:
00749   Gif_DeleteArray(gfc.nodes);
00750   Gif_DeleteArray(gfc.links);
00751   return ok;
00752 }
00753 
00754 
00755 int
00756 Gif_FullWriteFile(Gif_Stream *gfs, int flags, FILE *f)
00757 {
00758   Gif_Writer grr;
00759   grr.f = f;
00760   grr.byte_putter = file_byte_putter;
00761   grr.block_putter = file_block_putter;
00762   grr.flags = flags;
00763   return write_gif(gfs, &grr);
00764 }
00765 
00766 
00767 #undef Gif_CompressImage
00768 #undef Gif_WriteFile
00769 
00770 int
00771 Gif_CompressImage(Gif_Stream *gfs, Gif_Image *gfi)
00772 {
00773   return Gif_FullCompressImage(gfs, gfi, 0);
00774 }
00775 
00776 int
00777 Gif_WriteFile(Gif_Stream *gfs, FILE *f)
00778 {
00779   return Gif_FullWriteFile(gfs, 0, f);
00780 }
00781 
00782 
00783 #ifdef __cplusplus
00784 }
00785 #endif
 

Powered by Plone

This site conforms to the following standards: