/*------------------------------------------------------------------------
 *
 * 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.
 *
 * giftoppm.c 
 *
 * Steve Weiss sweiss@cs.cornell.edu
 *
 * Usage : giftoppm inputGIF outPrefix
 *
 * Takes a GIF (possibly animated GIF) and output a sequence of PPM files.
 * outPrefix specifies the prefix of the PPM file.  If outPrefix is foo,
 * and the GIF contains three image, then the GIF file will be decoded into
 * foo0.ppm foo1.ppm foo2.ppm.
 *
 *------------------------------------------------------------------------
 */
#include <dvmbasic.h>
#include <dvmimap.h>
#include <dvmpnm.h>
#include <dvmgif.h>

int  fsize(char *);
void WritePPM(PnmHdr *, ByteImage *, ByteImage *, ByteImage *, char *);

int main(int argc, char *argv[])
{
     GifSeqHdr *seqhdr;
     GifImgHdr *imgHdr;
     PnmHdr *pnmhdr;
     ByteImage *red, *green, *blue, *indices;
     BitParser *bp;
     BitStream *bs;
     FILE *inf;
     ImageMap *rmap, *gmap, *bmap, *lrmap, *lgmap, *lbmap;
     int i, ctsize;
     int status;
     char outname[256];


     /*
      * Check the arguments.
      */

     if (argc != 3) {
	 fprintf(stderr, "usage : %s inputGIF outPrefix\n", argv[0]);
	 exit(1);
     }

     /*
      * Open the input file and check for errors.
      */

#ifdef _WIN32_
     inf = fopen(argv[1], "rb");
#else
     inf = fopen(argv[1], "r");
#endif
     if (!inf) {
	 fprintf(stderr, "cannot open input GIF %s.\n", argv[1]);
	 exit(1);
     }

     /*
      * Initialize BitStream and BitParser 
      */
     bp  = BitParserNew();
     bs = BitStreamNew(fsize(argv[1]));
     BitStreamFileRead(bs, inf, 0);
     BitParserWrap(bp, bs);

     /*
      * Initialize Image Maps
      */
     rmap = ImageMapNew();
     gmap = ImageMapNew();
     bmap = ImageMapNew();

     /*
      * Create a new header and initilaize the header with data from 
      * BitStream.
      */
     seqhdr = GifSeqHdrNew();
     GifSeqHdrParse(bp, seqhdr);
     

     /*
      * Check if a color table exists.  If it does, parse it from the
      * BitStream.
      */
     if (GifSeqHdrGetCtFlag(seqhdr) == 1) {
	 ctsize = GifSeqHdrGetCtSize(seqhdr);
	 GifCtParse(bp, ctsize, rmap, gmap, bmap);
     }

     /*
      * Initialize data for the decoding loop below.  imgHdr and pnmHdr
      * holds the GIF image header and output PPM header respectively.
      * i is the number of image (index to the output PPM).
      */
     imgHdr = GifImgHdrNew();
     pnmhdr = PnmHdrNew();
     i = 0;

     /*
      * Now we find an image from the BitStream.  While there is an image,
      * we decode the image and write it to an output PPM.
      */
     status = GifImgFind(bp);
     while (status == DVM_GIF_OK) {

	 /*
	  * Here we parse an image, first the header then the body.
	  * Since each image can be of different width and height,
	  * we allocate the ByteImages separately for each image.
	  * (We can actually just allocate it according to the width
	  * and height from seqHdr, and clip it here. weitsang)
	  * We also allocate a ByteImage for indices to the color table.
	  */

	 int w, h;
	 GifImgHdrParse(bp, imgHdr);
	 w = GifImgHdrGetWidth(imgHdr);
	 h = GifImgHdrGetHeight(imgHdr);
	 red = ByteNew(w, h);
	 green = ByteNew(w, h);
	 blue = ByteNew(w, h);
	 indices = ByteNew(w, h);

	 if (GifImgHdrGetCtFlag(imgHdr) == 1) {
	     /*
	      * There is a local color table for this image.  We 
	      * create new image maps to hold this color table, and
	      * parse this color table.  
	      */
	     lrmap = ImageMapNew();
	     lgmap = ImageMapNew();
	     lbmap = ImageMapNew();
	     ctsize = GifImgHdrGetCtSize(imgHdr);
	     GifCtParse(bp, ctsize, lrmap, lgmap, lbmap);

	     /*
	      * Next we parse the body of the image.  Interlaced and
	      * non-interlaced table are parsed differently.
	      */
	     if (GifImgHdrGetInterlaced(imgHdr)) {
		 GifImgInterlacedParse(bp, seqhdr, imgHdr, indices);
	     } else {
		 GifImgNonInterlacedParse(bp, seqhdr, imgHdr, indices);
	     }

	     /*
	      * We map the color table to the indices to get the RGB plane 
	      * of the image.  Finally we free the image maps.
	      */
	     ImageMapApply(lrmap, indices, red);
	     ImageMapApply(lgmap, indices, green);
	     ImageMapApply(lbmap, indices, blue);
	     ImageMapFree(lrmap);
	     ImageMapFree(lgmap);
	     ImageMapFree(lbmap);

	 } else {

	     /*
	      * If there are no color table, we just parse the image and
	      * apply the color map.
	      */
	     if (GifImgHdrGetInterlaced(imgHdr)) {
		 GifImgInterlacedParse(bp, seqhdr, imgHdr, indices);
	     } else {
		 GifImgNonInterlacedParse(bp, seqhdr, imgHdr, indices);
	     }
	     ImageMapApply(rmap, indices, red);
	     ImageMapApply(gmap, indices, green);
	     ImageMapApply(bmap, indices, blue);
	 }

	 /*
	  * Output current RGB image to a PPM file.
	  */

	 sprintf(outname, "%s%d.ppm", argv[2], i);
	 WritePPM (pnmhdr, red, green, blue, outname);

	 /*
	  * Free the RGB ByteImages.
	  */
	 ByteFree(red);
	 ByteFree(green);
	 ByteFree(blue);
	 ByteFree(indices);

	 /*
	  * Try to find the next GIF image to decode.  
	  */
	 status = GifImgFind(bp);
	 i++;
     }

    return 0;
}