( for gifsave89 version 1.00 )
Click for:   download gifsave89
This page discusses gifsave89, a small C library that renders gif images and animations.

Copyright © 2012-2012, John Forkosh Associates, Inc.
email: john@forkosh.com



(Last revised: September 29, 2012)

This page contains more information than you'll probably need to read. If you follow the QuickStart instructions below, try using gifsave89 immediately. If you need more information, continue reading until you feel comfortable trying to use gifsave89. Return to this page as needed. Prerequisites are: some knowledge of C, and of gif images.
        "Computers are like Old Testament gods: lots of rules and no mercy."
        Joseph Campbell, The Power of Myth   (Doubleday 1988, page 18)


    C o n t e n t s           Q u i c k S t a r t    
Function Prototypes
(1) Introduction&Usage
(2) Extensions
      application
      control
      plaintext
(3) Compiling&Testing
(4) gifgraph
(5) GPL License

  Related   Pages  

gifsave89 changeLog
gifsave89 Listing
   
Compiling:   Download gifsave89.zip and type
    unzip gifsave89.zip
    cc   yourprogram.c   gifsave89.c \
      –o yourprogram

    (see Compiling for more information)
 
Usage:   Your program should contain something like,
 void *gsdata=NULL, *newgif();
 int  nbytes=0, putgif(), endgif();
 int  ncols=255, nrows=255,
      *colortable = {255,255,255, 0,0,0, -1}, bgindex=0;
 unsigned char pixels[99999] = {0,1,0,1/*,...,ncols*nrows*/};
 unsigned char *gifimage = NULL;
 generate_your_own(pixels,ncols,nrows);
 gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
 if ( gsdata != NULL ) {
   putgif(gsdata,pixels);
   nbytes = endgif(gsdata); }
 if ( nbytes > 0 ) {
   do_what_you_want_with(gifimage,nbytes);
   free(gifimage); }
    (see Prototypes and Usage for more information)

Synopsis of gifsave89 Function Prototypes  

A complete, ready to compile and run, Sample Program is illustrated in the Introduction, and "coding templates" for single gif's and gif animations are illustrated in the subsequent discussion. After you've read that, the function prototypes immediately below are for quick reference...

/* ------- call newgif() once, then putgif() one or more times, finally endgif() once ------- */
void   // *gsdata =    
  *newgif   ( void **gifimage, int width, int height, int colortable[], int bgindex );
int   // nbytes =    
  putgif   ( void *gsdata, unsigned char pixels[] ),
  endgif   ( void *gsdata ),
/* --------------- optional gif extension functions --------------- */
  animategif   ( void *gsdata, int nrepetitions, int delay, int tcolor, int disposal ),
  controlgif   ( void *gsdata, int tcolor, int delay, int userinput, int disposal ),
  plaintxtgif   ( void *gsdata, int left, int top, int width, int height, int fg, int bg, char *text );

(1) Introduction and Usage  

 gifsave89, licensed under the gpl, is a small C library that renders an in–memory gif from a sequence of bytes representing the pixels comprising your image.

Sample program

A small sample program using gifsave89 is illustrated immediately below, and then further discussed below that. A more comprehensive sample program is gifsave.c's main() test driver in your gifsave89.zip distribution file, which also contains a complete and useful application, gifgraph.c, discussed later.


  #include <stdio.h>
  int main ( int argc, char *argv[] ) {
   /* --- gifsave89's three functions: newgif(),putgif(),endgif() --- */
   void *gsdata=NULL, *newgif();
   int  nbytes=0, putgif(), endgif();
   /* --- your two funcs: generate pixels, do something with gif  --- */
   int  generate_your_own(), do_what_you_want_with();
   /* --- additional variables --- */
   int  colortable[]={255,255,255, 0,0,255, -1}, bgindex=0;
   int  ncols=255, nrows=255;
   unsigned char pixels[99999] = {0,1,0,1/*,...,ncols*nrows*/};
   unsigned char *gifimage = NULL;
   /* --- easter egg ( to be explained later :) --- */
   char *text = "\\LARGE{\\frac1{sqrt{a^2+b^2}}\\atop\\rm hello, world}";
   int  left=40, top=100, fg=0, bg=1;
   /* --- generate your own pixels --- */
   generate_your_own(pixels,ncols,nrows);
   /* --- render gif from them --- */
   gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
   if ( gsdata != NULL ) {
     plaintxtgif(gsdata,left,top, 0,0, fg,bg, text); /*easter egg in action*/
     putgif(gsdata,pixels);
     nbytes = endgif(gsdata); }
   /* --- do what you want with the gif (e.g., write to a file) --- */
   if ( nbytes > 0 ) {
     do_what_you_want_with(gifimage,nbytes);
     free(gifimage); }
   return ( 0 );
   } /* --- end-of-function main() --- */

  /* --- example: draw a triangle --- */
  int generate_your_own ( unsigned char *pixels, int ncols, int nrows ) {
   int  icol=0, irow=0, npixels=0;
   for ( irow=0; irow<nrows; irow++ ) {
     int locol=(ncols-irow)/2, hicol=(ncols+irow)/2;
     for ( icol=0; icol<ncols; icol++ ) {
       int icolor = (icol>=locol&&icol<=hicol?1:0);
       pixels[npixels++] = ((unsigned char)icolor); } }
   return ( npixels );
   } /* --- end-of-function generate_your_own() --- */

  /* --- example: just write gifimage to a file --- */
  int do_what_you_want_with ( unsigned char *gifimage, int nbytes ) {
   FILE *fileptr = fopen("gifsave89test.gif","wb");
   int  nwritten = 0;
   if ( fileptr != NULL ) {
     nwritten = fwrite(gifimage,sizeof(unsigned char),nbytes,fileptr);
     fclose(fileptr); }
   return ( nwritten );
   } /* --- end-of-function do_what_you_want_with() --- */

Cut-and-paste the above program into file gifsave89test.c, download and unzip gifsave89.zip,
and then type
      cc gifsave89test.c gifsave89.c –o gifsave89test
      ./gifsave89test

Now display or point your browser to the program's output file, gifsave89test.gif,
and you should see,
     

Okay, there's a little extra "easter egg" in there, illustrating gifsave89's implementation of the intended but deprecated gIFt PLAINTEXT extension.
      If your computer has wget installed, and on your default path, then the above program should reproduce the triangle-plus-text as shown, and you can change the char *text string above to most valid LaTeX math expressions, adjust left and top accordingly, and watch what happens. Otherwise, just comment out the plaintxtgif( ) call, and you should see the triangle without text.

Meanwhile, "easter egg" aside, examine the above program to see how you might use gifsave89 in your own programs for your own purposes. Not illustrated above are gif animations and graphic controls, which are separately discussed under Extensions. Immediately below are discussed some details about the above code that might remain murky even after studying it...

gifsave89 functions and arguments used by sample program

void *gsdata, *newgif();


Initialize the gifsave89 library by a call to newgif() of the form

     void *gsdata=NULL, *newgif();
     ...
     gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);

 gsdata is returned by newgif() and then always passed as the first argument to every other gifsave89 function. It holds all local variables used by gifsave89, and is free()'ed for you by endgif(). Its internal structure is user-irrelevant, but may be examined in gifsave89.c if curious.
The other arguments to newgif() (and to putgif() and endgif()) are discussed below...

unsigned char *gifimage;   int nbytes;

 gifimage is a pointer to the buffer that will contain nbytes=endgif(gsdata) bytes comprising your gif image after gifsave89 finishes rendering it.

Note that you don't malloc() (or declare) any bytes for gifimage; just the pointer whose address you pass as the first argument to newgif(&gifimage,...).   newgif() receives this argument as unsigned char **gifimage, and then *gifimage=malloc() (and realloc()) as necessary. So that's all done for you by gifsave89, but you should free(gifimage) after you've finished using it.

int ncols, nrows;

As you already surmised: ncols is the width of your image, and nrows its height, both in #pixels.

int colortable[], bgindex;


The array

     int colortable[] = { r0,g0,b0, r1,g1,b1, r2,g2,b2, ..., -1 };

 is a sequence of ints, each one 0 to 255, interpreted as r,g,b-values, 0="black", 255="white". Terminate the sequence with any negative number. The first three colortable[] numbers are the r,g,b values for any pixel=pixels[ipixel] whose value is 0, the second three for any pixel whose value is 1, etc. Obviously, pixel values must always be between 0 and #colors-1.

 bgindex, if you haven't guessed, is the colortable[] index for the background color, i.e., the pixel value for background pixels. Typically, bgindex=0, and the first three numbers in colortable[] are the r,g,b values for the background color (typically white=255,255,255).

The number of colors in colortable[] must be a power of 2, e.g., you must have 6 integers (for 2 colors), or 12 (for 4), or etc, numbers in colortable[] preceding the –1. A maximum of 256 r,g,b colors are permitted.

The simplest usage is

     int colortable[] = {255,255,255, 0,0,0, -1};

 for a monochrome black-on-white color table where corresponding pixel values may be 0=white and 1=black.
For monochrome blue-on-white, simply write instead,

     int colortable[] = {255,255,255, 0,0,255, -1};

unsigned char pixels[ncols*nrows];

 unsigned char pixels[ncols*nrows]; which you must declare/malloc()/whatever yourself, is a sequence of bytes describing the pixels comprising your image.
pixels[] is always in row order, i.e.,
    pixels[0] corresponds to the upper-left corner pixel,
    pixels[ncols] to the leftmost pixel of the second row,
    ...,
    pixels[ncols*nrows-1] to the lower-right corner pixel.
Each pixels[] byte contains the color table index for the color to be displayed for that pixel.
For example, if
    colortable[] = {255,255,255, 255,0,0, 0,255,0, 0,0,255, -1}
and
    pixels[0] = 2
then your upper-left corner pixel will be green.

additional sample program remarks

As you can see, the "template" for basic gifsave89 usage is pretty trivial...

     generate_your_own(pixels,ncols,nrows);
     gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
     if ( gsdata != NULL ) {
       putgif(gsdata,pixels);
       nbytes = endgif(gsdata); }
     if ( nbytes > 0 ) {
       do_what_you_want_with(gifimage,nbytes);
       free(gifimage); }

 along with the several required variable declarations illustrated in the quickstart and sample program sections above.

The hard part for any non-trivial image is typically generate_your_own(pixels,ncols,nrows). But that, of course, is entirely your problem. Once solved, gif rendering with gifsave89 is easy.

My motivation for writing gifsave89 was web pages with dynamic content, including on-the-fly images. With gifsave89, you can easily write a cgi program invoked by an <img> tag of the form
        <img src="http://yourdomain.com/cgi-bin/yourprogram.cgi?query_string">
to generate gifs from users' query_string arguments, and then emit them to stdout preceded by appropriate http headers. You'd usually think of the src attribute as a static filename, but web servers will actually execute your cgi and interpret its stdout output (with http headers) as the image to be displayed.

(2) GIF89a Extensions in gifsave89  

The GIF89a Specification provides four "extensions" not supported by the original GIF87a standard:

  1. Graphic Control Extension
  2. Application Extension
  3. Plain Text Extension
  4. Comment Extension

 gifsave89 implements the first two as prescribed by the Specification, primarily to permit simple rendering of multiple-frame gif animations.
      gifsave89a also contains a plaintxtgif() function for the third extension's functionality, but implemented in a non-standard fashion.
      Finally, the Comment extension is trivial, but serves no particular purpose for gifsave89 renderings, and isn't implemented.

gif animations (application extension)

First make sure you've read and understood the "template" for basic gifsave89 usage illustrated in the remarks above, and reproduced again below...

     gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
     if ( gsdata != NULL ) {
       generate_your_own(pixels,ncols,nrows);
       putgif(gsdata,pixels);
       nbytes = endgif(gsdata); }
     if ( nbytes > 0 ) {
       do_what_you_want_with(gifimage,nbytes);
       free(gifimage); }

Did you notice one minor change? : I moved "generate_your_own() pixels" inside the if(gsdata!=NULL){ ... } block. Suppose you have nframes frames to be displayed as a looped animation. The simple "template" change is...

    gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
    if ( gsdata != NULL ) {
      animategif(gsdata,0,0,-1,2);
      for ( iframe=0; iframe<nframes; iframe++ ) {
        generate_your_own(iframe,pixels,ncols,nrows);
        putgif(gsdata,pixels); }
      nbytes = endgif(gsdata); }
    if ( nbytes > 0 ) {
      do_what_you_want_with(gifimage,nbytes);
      free(gifimage); }

 generate_your_own() and putgif() are now in a loop over nframes which generates the animation frame-by-grame.   generate_your_own() takes an extra iframe argument, from which it needs to generate pixels[] for that particular frame (you may or may not want to free(pixels) after calling putgif(), depending upon how generate_your_own() is coded). The putgif() call remains completely unchanged, simply adding each new frame to the gif.


Just before the loop, animategif(gsdata,0,0,-1,2) emits what's called a "NETSCAPE2.0" application extension, which introduces gif animation sequences. The full function prototype is
      int animategif ( void *gsdata, int nrepetitions, int delay, int tcolor, int disposal )
and the arguments following gsdata are:

 See immediately below for further discussion of 4th and 5th args.


There are two principal ways gif frames for animation are generated:

 The above gifsave89 "template" defaults to the first method. For the second, change the illustrated animategif() call to animategif(gsdata,0,0,0,1), where the background color (presumably colortable[] index 0) is now transparent, and where disposal method 1 means "do not dispose of graphic". See graphic control immediately below for further discussion of all these values.

graphic control extension

Besides the preceding animation modifications, our "template" for basic gifsave89 usage from the remarks above, and illustrated (yet again) below...

     gsdata = newgif(&gifimage,ncols,nrows,colortable,bgindex);
     if ( gsdata != NULL ) {
       generate_your_own(pixels,ncols,nrows);
       putgif(gsdata,pixels);
       nbytes = endgif(gsdata); }
     if ( nbytes > 0 ) {
       do_what_you_want_with(gifimage,nbytes);
       free(gifimage); }

 may optionally be changed to include a controlgif() call immediately preceding putgif(),

     ...
     if ( gsdata != NULL ) {
       generate_your_own(pixels,ncols,nrows);
       controlgif(gsdata,tcolor,delay,userinput,disposal);
       putgif(gsdata,pixels);
       nbytes = endgif(gsdata); }
     ...

  which emits what's called a gif "Graphic Control Extension" block that modifies display of the subsequent putgif() image. Only one (or none) gifcontrol() is permitted preceding putgif(). For multi-frame gifs, it's one (or none) preceding each putgif().


The function prototype arguments
      int controlgif ( void *gsdata, int tcolor, int delay, int userinput, int disposal )
following gsdata are:


For animations, gifsave89 saves you this trouble by automatically emitting a gifcontrol(), preceding each putgif(), all containing your animategif() values and the value userinput=0. To override these defaults, you can issue your own controlgif() preceding any (or every) putgif(), in which case gifsave89 doesn't emit its own.
      For example, to pause an animation midway, wait for user input, and then continue, do the obvious

    ...
    if ( gsdata != NULL ) {
      animategif(gsdata,0,0,-1,2);
      for ( iframe=0; iframe<nframes; iframe++ ) {
        generate_your_own(iframe,pixels,ncols,nrows);
        if ( iframe == ipause )
          controlgif(gsdata,-1,0,1,2);
        putgif(gsdata,pixels); }
      nbytes = endgif(gsdata); }
      ...

 Notice that the order of arguments ...,tcolor,delay,... is reversed between animategif() and controlgif(). Sorry about that (I have my reasons:).

For single-frame gifs, there's typically no need for controlgif(), unless you want to specify a transparent color index (most likely tcolor=bgindex, the background color index, as mentioned above).

plain text extension

 gifsave89 contains a non-standard implementation of the intended gIFt PLAINTEXT extension, which was deprecated almost immediately after being introduced, and which no other gif encoder/decoder (that I could find) now supports.

To use gifsave89's plaintext extension, your computer must have wget installed, and on your default path. If installed but not explicitly on your path, compile gifsave89 with the additional
      –DWGET=\"/path/to/etc/wget\"
–switch, ending with the filename (typically just wget) of the executable wget image. If wget isn't available on your computer, gifsave89 will still compile without complaint, but do not use the plaintxtgif() function described below.

The function prototype arguments
      int plaintxtgif ( void *gsdata, int left, int top, int width, int height, int fg, int bg, char *text )
following gsdata are:


After you call plaintxtgif(), gifsave89 simply "acquires" a pixelized (monochrome bytemap) rendering of your text, and overlays it (in the obvious way) on subsequent pixel image(s) that you supply to putgif(). The trick is pixelizing your text. That's beyond gifsave89's functionality, and it instead issues a request to the mimeTeX public web service (one of my other open source projects) via a popen("wget...","r") call.

(3) Compiling and Testing gifsave89  

Very quickly   --   download gifsave89.zip and type
        unzip gifsave89.zip
For testing,
        cc –DGSTESTDRIVE gifsave89.c –lm –o gifsave89
To see example 1 (using ImageMagick's display):
    ./gifsave89 1
    display gifsave89test.gif
To see example 2:
    ./gifsave89 2
    display gifsave89test.gif
For use with your own program,
        cc yourprogram.c gifsave89.c –o yourprogram
(along with any other –switches, etc, yourprogram requires)
Read the rest of this section only if you want more information.

gifsave89's source code is ansi standard C, which should compile and run without change on any platform. The steps needed to compile and test gifsave89 are:

Download gifsave89...

Test gifsave89...

Use gifsave89...

(4) gifgraph.c, an expression graphing cgi  

Your gifsave89.zip distribution contains a more complete, and much more useful, program than either the sample program above or gifsave89's main() test driver, that you can easily compile following the instructions above,
        cc   gifgraph.c   gifsave89.c   –o   gifgraph.cgi
It presently runs only on Unix-like systems where the bc "calculator" is installed (on your default path).

After compiling gifgraph.cgi, mv it to your cgi-bin/ directory, chmod permissions as necessary, and now try typing into your browser's locator window (if you see an "Internal Server Error 500", try typing more carefully -- that bc calculator can be finicky:),
        http://www.yourdomain.com/cgi-bin/gifgraph.cgi? 200&100&s(x+t)+.5*s(2.*x+3.*t)
        &x=0.0;x<6.283;x+=0.05&t=0.0;t<6.283;t+=0.05
and you should see,
       
A static image at, say, t=0 is displayed if you omit the last query string argument and adjust the expression accordingly, i.e.,
        http://www.yourdomain.com/cgi-bin/gifgraph.cgi? 200&100&s(x)+.5*s(2.*x)$
        &x=0.0;x<6.283;x+=0.05
displays,
       
The extra $ at the end of the "static" bc expression suppresses gifgraph's default title generation, displayed with the animation and explained below.

Before proceeding to explain what's happening, note that you can see the same images above on any html page by placing identical <img> tags wherever you want them displayed, i.e.,
        <img src="http://www.yourdomain.com/cgi-bin/gifgraph.cgi?
        200&100&s(x+t)+.5*s(2.*x+3.*t)&
        x=0.0;x<6.283;x+=0.05&t=0.0;t<6.283;t+=0.05">
for the animation, or,
        <img src="http://www.yourdomain.com/cgi-bin/gifgraph.cgi?
        200&100&s(x)+.5*s(2.*x)$&x=0.0;x<6.283;x+=0.05">
for the static t=0 image. So this small gifgraph utility lets your web pages easily display on-the-fly function graphs of any bc expression submitted, either by hard-coded <img> tags as illustrated above, or as generated by php scripts from parameters users enter on a <form>, or etc, etc.

To use gifgraph effectively, you first need sufficient knowledge of the unix/gnu bc calculator language to express functions you want graphed. Then the situation is pretty straightforward:   gifgraph's query string comprises five arguments (the fifth one, for animations, optional),
        width & height & expression & x-range & t-range

 That is, the entire bc "program" gifgraph constructs looks something like,
        for ( t-range ) { for ( x-range ) { expression } }
with the t-range loop omitted if you don't supply that argument. The variable names used in your expression must be defined in x-range and t-range, but are otherwise your choice. And expression must print exactly one number per line, presumably one number each time it's executed (but you can get tricky about that if you like).
      I illustrated variable names x and t for the (hopefully) obvious reason: Each pass through the x-range loop results in a sequence of numbers that comprise one frame of the gif animation gifgraph renders, or that comprise the entire static gif image if t-range is omitted. If not omitted, the next frame is rendered from the sequence of numbers printed for the next t-value, etc. That is, if expression defines a function f(x,t), then the sequence of values f(x_0,t_0),f(x_1,t_0),...,f(x_n,t_0) comprise the first frame, f(x_0,t_1),f(x_1,t_1),...,f(x_n,t_1) comprise the second frame, and so on. Thus, an expression like s(x+t) (recall that s( ) means sin( ) for bc) renders a simple moving sine wave (assuming that x-range is x=0;x<6.28;x+=.05;, or the like, and similarly for t-range).

 gifgraph uses gifsave89's plaintext extension to horizontally center a default title consisting of your expression at the bottom of your graph, unless instructed otherwise, as follows.
      A $ character anywhere in your expression terminates it, and only characters preceding $ are submitted to the bc calculator. Characters following $ comprise the displayed title. If no characters (or only whitespace) follow $, then no title is displayed at all. Otherwise, those characters are rendered by gifsave89's plaintext extension.
For example,
        <img src="http://www.yourdomain.com/cgi-bin/gifgraph.cgi?
        255&255 & x*s((x/4.+t)/6.2832) $ x*\left.\sin\left(\frac{x/4+t}{2\pi}\right)
        \right|_{x=0,t=0}^{x=200,t=100} & x=0.0;x<200.;x+=1. & t=0.0;t<100.;t+=1." >
renders,
       

The gifgraph.c main() program is relatively simple and straightforward, reflecting its illustrative purpose. While you could use it straight out-of-the-box for production purposes, it should probably be enhanced to cache rendered images for use in high-traffic situations.

(5) GPL License  

"My grandfather once told me there are two kinds of people:
    Those who do the work and those who take the credit.
    He told me to try to be in the first group; there was much less competition.
"
Indira Gandhi, the late Prime Minister of India

gifsave89's copyright is registered by me with the US Copyright Office, and I hereby license it to you under the terms and conditions of the GPL. There is no official support of any kind whatsoever, and you use gifsave89 entirely at your own risk, with no guarantee of any kind, in particular with no warranty of merchantability.

By using gifsave89, you warrant that you have read, understood and agreed to these terms and conditions, and that you possess the legal right and ability to enter into this agreement and to use gifsave89 in accordance with it.

Hopefully, the law and ethics regarding computer programs will evolve to make this kind of obnoxious banter unnecessary. In the meantime, please forgive me my paranoia.

To protect your own intellectual property, I recommend (all are pdf) Copyright Basics from The Library of Congress, in particular Circular 61, Copyright Registration for Computer Programs. Very briefly, download Form TX and follow the included instructions. In principle, you automatically own the copyright to anything you write the moment it's on paper. In practice, if the matter comes under dispute, the courts look _very_ favorably on you for demonstrating your intent by registering the copyright beforehand. (For example, courts will stop unauthorized use of unregistered material, but monetary damages are typically awarded _only_ if you register the copyright before infringement occurs.)

Concluding Remarks  

I hope you find gifsave89 useful. If so, a contribution to the GNU project, is suggested, especially if you're a company that's currently profitable.


Copyright © 2012-2012, John Forkosh Associates, Inc.
email: john@forkosh.com