/*------------------------------------------------------------------------ * * 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; }