/*------------------------------------------------------------------------
*
* Copyright (c) 1997-1998 by Cornell University.
*
* See the file "license.txt" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* ppmstoanimgif
*
* Steve Weiss sweiss@cs.cornell.edu
*
* Usage : ppmstoanimgif prefix outputGIF numOfImage
*
* Encodes a series of PPM (prefix0.ppm, prefix1.ppm etc) as an animated
* GIF. The color map of the first image is shared with the rest of the
* images. The number of images is specified by numOfImage.
*
*------------------------------------------------------------------------
*/
#include <dvmbasic.h>
#include <dvmimap.h>
#include <dvmpnm.h>
#include <dvmgif.h>
#include <dvmcolor.h>
int fsize (char *);
/*
* This is similar to ReadPPM_, except it only allocates r, g, b only
* if they are NULL. This allow more efficient use of memory by reusing
* previously allocated r, g, and b.
*/
void
ReadPPM_ (filename, hdr, r, g, b)
char *filename;
PnmHdr **hdr;
ByteImage **r;
ByteImage **g;
ByteImage **b;
{
FILE *f;
BitStream *inbs;
BitParser *inbp;
int w, h;
f = fopen (filename, "rb");
if (f == NULL) {
fprintf (stderr, "unable to open file %s for reading\n", filename);
exit (1);
}
*hdr = PnmHdrNew ();
inbs = BitStreamNew (fsize (filename));
inbp = BitParserNew ();
BitParserWrap (inbp, inbs);
BitStreamFileRead (inbs, f, 0);
PnmHdrParse (inbp, *hdr);
w = PnmHdrGetWidth (*hdr);
h = PnmHdrGetHeight (*hdr);
if (*r == NULL)
*r = ByteNew (w, h);
if (*g == NULL)
*g = ByteNew (w, h);
if (*b == NULL)
*b = ByteNew (w, h);
PpmParse (inbp, *r, *g, *b);
fclose (f);
BitParserFree (inbp);
BitStreamFree (inbs);
}
int
main (int argc, char *argv[])
{
BitParser *bp;
BitStream *bs;
PnmHdr *pnmhdr;
ImageMap *rmap, *gmap, *bmap;
ByteImage *r, *g, *b, *indices;
FILE *f;
int w, h, i, numOfImages;
GifSeqHdr *hdr;
GifImgHdr *img;
char inname[256];
ColorHashTable *cht;
VpTree tree;
if (argc < 4) {
fprintf (stderr, "usage: %s inputPrefix output numOfImages\n", argv[0]);
exit (1);
}
/* make compiler happy */
rmap = gmap = bmap = NULL;
img = NULL;
hdr = NULL;
indices = NULL;
bs = NULL;
bp = NULL;
f = fopen (argv[2], "w");
if (f == NULL) {
fprintf (stderr, "unable to open file %s for writing.\n", argv[2]);
exit (1);
}
numOfImages = atoi (argv[3]);
/*
* Read the first image. We need the width and height information
*/
sprintf (inname, "%s%03d.ppm", argv[1], 0);
r = g = b = NULL;
ReadPPM_ (inname, &pnmhdr, &r, &g, &b);
/*
* Allocates the image maps, ByteImage for indices and BitStream.
*/
rmap = ImageMapNew ();
gmap = ImageMapNew ();
bmap = ImageMapNew ();
w = ByteGetWidth (r);
h = ByteGetHeight (r);
indices = ByteNew (w, h);
bs = BitStreamNew (3 * numOfImages * w * h); // output better be smaller than this
bp = BitParserNew ();
BitParserWrap (bp, bs);
/*
* Create and encodes the sequence header.
*/
hdr = GifSeqHdrNew ();
GifSeqHdrSetWidth (hdr, w);
GifSeqHdrSetHeight (hdr, h);
GifSeqHdrSetCtFlag (hdr, 1);
GifSeqHdrSetVersion (hdr, "87a");
GifSeqHdrSetCtSize (hdr, 256);
GifSeqHdrSetCtSorted (hdr, 0);
GifSeqHdrSetAspectRatio (hdr, 0);
GifSeqHdrSetBackgroundColor (hdr, 0);
GifSeqHdrSetResolution (hdr, 3);
GifSeqHdrEncode (hdr, bp);
/*
* Calculate the color map to use. and
* encode the color map.
*/
cht = ColorHashTableNew (15);
ColorHashTableClear (cht);
RgbTo256 (r, g, b, cht, rmap, gmap, bmap);
ColorHashTableFree (cht);
cht = ColorHashTableNew (16);
ColorHashTableClear (cht);
tree = VpTreeNew ();
VpTreeInit (rmap, gmap, bmap, tree);
RgbQuantWithVpTree (r, g, b, tree, cht, rmap, gmap, bmap, indices);
GifCtEncode (256, rmap, gmap, bmap, bp);
/*
* Encode Netscape extension for animated GIF.
*/
GifSeqLoopEncode (bp);
/*
* Create and encodes the image header.
*/
img = GifImgHdrNew ();
GifImgHdrSetWidth (img, w);
GifImgHdrSetHeight (img, h);
GifImgHdrSetCtFlag (img, 0);
GifImgHdrSetLeftPosition (img, 0);
GifImgHdrSetTopPosition (img, 0);
GifImgHdrSetInterlaced (img, 0);
GifImgHdrSetGraphicControlFlag (img, 1);
GifImgHdrSetDisposalMethod (img, 0);
GifImgHdrSetUserInputFlag (img, 0);
GifImgHdrSetTransparentColorFlag (img, 0);
GifImgHdrSetDelayTime (img, 1);
GifImgHdrEncode (img, bp);
GifImgEncode (hdr, img, indices, bp);
/*
* Encode the rest of the images, using the same color map and
* image header.
*/
for (i = 0; i < numOfImages; i++) {
sprintf (inname, "%s%03d.ppm", argv[1], i);
ReadPPM_ (inname, &pnmhdr, &r, &g, &b);
RgbQuantWithVpTree (r, g, b, tree, cht, rmap, gmap, bmap, indices);
GifImgHdrEncode (img, bp);
GifImgEncode (hdr, img, indices, bp);
}
/*
* Clean up the stuffs.
*/
ImageMapFree (rmap);
ImageMapFree (gmap);
ImageMapFree (bmap);
ColorHashTableFree (cht);
GifSeqTrailerEncode (bp);
BitStreamFileWrite (bs, f, 0);
BitStreamFree (bs);
ByteFree (r);
ByteFree (g);
ByteFree (b);
fclose (f);
return 0;
}