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

email: john@forkosh.com

$\parstyle\usepackage{color} \large\color{blue}\begin{center}\today,\;\;\time\end{center}$
(Last revised: January 10, 2017)

"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       comment (3) Compiling&Testing (4) gifgraph (5) GPL License   Related   Pages   gifsave89 changeLog gifsave89 Listing

 Compiling: Download (No download yet) 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 ); commentgif ( void *gsdata, char *comment );

## (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() --- */

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.

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:

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, permitting arbitrary comment strings to be embedded in generated gifs, and is implemented as prescribed by the Specification.

### 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:

• 2nd arg nrepetitions: the number of repetitions before stopping, with 0 meaning loop the animation continuously.
• 3rd arg delay: the delay between frames in hundredths of a second, with 0 meaning no delay.
• 4th arg tcolor: the transparency color index (i.e., the colortable[] index for a color, usually the background color, to be treated as transparent), with -1 meaning no transparent color.
• 5th arg disposal: the disposal method, specifying the frame disposition after display, with 2 meaning "overwrite with background color".

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

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

• Each frame is complete in itself, and the preceding frame should be discarded before displaying the next frame.
• The sequence of frames builds up in composite fashion, and each new frame should be superimposed on the total result built up from all preceding frames.

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:

• 2nd arg tcolor: the transparency color index (i.e., the colortable[] index for a color, usually the background color, to be treated as transparent), with -1 meaning no transparent color.
• 3rd arg delay: the for multi-frame gifs, the delay between frames in hundredths of a second, with 0 meaning no delay.
• 4th arg userinput: for multi-frame gifs, 1 if user input (mouseclick or keystroke) is required before the next frame is displayed (i.e., frames are displayed in slide-show fashion), or 0 if not.
• 5th arg disposal: the disposal method, specifying the frame disposition after display. Allowed values are 0,1,2,3, with
0: meaning "disposal method not specified",
1: "do not dispose of graphic",
2: "overwrite with background color",
3: "restore preceding graphic".

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:

• 2nd arg left: the "column index" of your gif image where the leftmost character of your text should be placed, i.e., 0 for left-justified. Any negative number will horizontally center your text within the image. If your text is so wide that it goes beyond your image's right edge, then left is reduced so it fits. If wider then the entire image, the rightmost characters of your text are truncated.
• 3rd arg top: the "row index" of your gif image where the topmost pixel of the tallest character of your text should be placed, i.e., 0 to place your text at the top of the image. Any negative number will vertically center your text within the image. If your text is so tall that it goes beyond your image's bottom edge, then top is reduced so it fits. If taller then the entire image, the bottoms of all your characters are truncated.
• 4th arg width: ...
• 5th arg height: width and height aren't used by gifsave89 for their original purpose. Instead, if either or both is any negative number, then your text is "persistent", i.e., placed on every (animation) frame that follows, until endgif() is called, or until you issue another plaintxtgif() call.
• 6th arg fg: colortable[] index for text foreground
• 7th arg bg: colortable[] index for background
• 8th arg text: null-terminated string containing a valid LaTeX math expression. Note: passing text as a NULL pointer (or a zero-length string) signals plaintxtgif() to reset (turn off) plaintext, i.e., any "persistent" text in effect will disappear.

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.

### comment extension

The gif89a standard includes a comment extension that allows you to embed any comment you like in a gif, which is completely ignored during rendering. (Typically pretty useless, but I find it handy for gif-generating programs to embed the input command-string as a gif comment. Then I can always recall how that gif was generated.)

The function prototype arguments
int commentgif ( void *gsdata, char *comment )
following gsdata are:

• 2nd arg comment: any null-terminated character string you like, to be embedded in your generated gif.

## (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:

 README gifsave89 release notes COPYING GPL license, version 3, under which you may use gifsave89 gifsave89.c gifsave89 source program and all required functions gifsave89.html this file, the gifsave89 user page gifgraph.c sample application discussed below (click link at left)

### Test gifsave89...

• To compile a gifsave89 executable with its own embedded test driver main() program, just type
cc   –DGSTESTDRIVE gifsave89.c   –lm   –o   gifsave89test
• Immediately after compiling this gifsave89 executable image, test it by typing
./gifsave89   1
at the command prompt, whose screen output should look something like
    +-----------------------------------------------------------------------+
|gifsave89 ver1.02, Copyright(c) 2012-2017, John Forkosh Associates, Inc|
|               (  current revision:  09 Jan 2017  )                    |
+-----------------------------------------------------------------------+
|gifsave89 is free software, licensed to you under terms of the GNU/GPL,|
|           and comes with absolutely no warranty whatsoever.           |
|     See http://www.forkosh.com/gifsave89.html for further details.    |
+-----------------------------------------------------------------------+
GIF image written to file: gifsave89test.gif
Now bring up the output file gifsave89test.gif in any gif viewer, like ImageMagick's display, or in your browser. You should see a gif identical to the one displayed in the top-left corner of this page.
• Now repeat the test, this time typing
./gifsave89   2
and you should see a gif identical to the one displayed in the top-right corner of this page.

### Use gifsave89...

• To compile your own program using gifsave89, just type
cc   yourprogram.c   gifsave89.c   –o   yourprogram
along with any other switches, etc, that yourprogram requires.
• The sample application discussed below, gifgraph.c, in your gifsave89.zip distribution is a cgi program that can be compiled by typing
cc   gifgraph.c   gifsave89.c   –o   gifgraph.cgi
in exactly the preceding fashion.

## (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 • width width of the graphic in pixels • height height of the graphic in pixels • expression bc statement(s) defining the function to be graphed, in terms of variables defined in x-range (and optionally in t-range). Your expression may also contain an optional trailing expression$title, explained below.
• x-range bc statements of the form x=0;x<100;x++ which gifgraph places inside a for( ).
• t-range bc statements of the form t=0;t<100;t++ which gifgraph places inside a for( ) preceding your for(x-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.

"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-2017, John Forkosh Associates, Inc. email: john@forkosh.com $\hspace{50}$ $\blue{\small\rm You're the } \Large\counter[counters.log] {counters.txt:gifsave89.html}\\[0] {\small\rm visitor to this page.}$