/*------------------------------------------------------------------------
 *
 * 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.
 *
 * ppmtogif
 *
 * Steve Weiss sweiss@cs.cornell.edu
 *
 * Usage : ppmtogif inputPPm outputGIF
 *
 * Reads a PPM file and encode it into a GIF file.
 *
 *------------------------------------------------------------------------
 */
#include <dvmbasic.h>
#include <dvmimap.h>
#include <dvmpnm.h>
#include <dvmgif.h>
#include <dvmcolor.h>

int fsize (char *);
void ReadPPM (char *name, PnmHdr **, ByteImage **, ByteImage **, ByteImage **);

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;
    GifSeqHdr *hdr;
    GifImgHdr *img;
    ColorHashTable *cht;
    VpTree tree;

    /* 
     * Check arguments, and read in the input PPM.  We create a BitStream
     * the same size as the PPM image, we assumes GIF is smaller than PPM
     * so this BitStream should be big enough to hold the output GIF.
     */
    if (argc < 3) {
	fprintf (stderr, "usage: %s input output\n", argv[0]);
	exit (1);
    }
    bp = BitParserNew ();
    bs = BitStreamNew (fsize (argv[1])); 
    f = fopen (argv[2], "wb");
    if (f == NULL) {
	fprintf (stderr, "unable to open file %s for writing.\n", argv[2]);
	exit (1);
    }
    BitParserWrap (bp, bs);
    ReadPPM (argv[1], &pnmhdr, &r, &g, &b);

    /*
     * Allocates all the stuffs that we need : rmap, gmap and bmap for 
     * the color table and indices for the color map indices.
     */
    rmap = ImageMapNew ();
    gmap = ImageMapNew ();
    bmap = ImageMapNew ();
    w = ByteGetWidth (r);
    h = ByteGetHeight (r);
    indices = ByteNew (w, h);

    /*
     * Find 256 colors that best represents all the color in the input
     * image.
     */
    cht = ColorHashTableNew (15);
    ColorHashTableClear (cht);
    RgbTo256 (r, g, b, cht, rmap, gmap, bmap);
    ColorHashTableFree (cht);

    /*
     * For each color in the input image, find the closest color 
     * among the 256 colors.
     */
    cht = ColorHashTableNew (16);
    ColorHashTableClear (cht);
    tree = VpTreeNew ();
    VpTreeInit (rmap, gmap, bmap, tree);
    RgbQuantWithVpTree (r, g, b, tree, cht, rmap, gmap, bmap, indices);
    ColorHashTableFree (cht);

    /*
     * Initialize a sequence header and encode it.
     */
    hdr = GifSeqHdrNew ();
    GifSeqHdrSetWidth (hdr, w);
    GifSeqHdrSetHeight (hdr, h);
    GifSeqHdrSetCtFlag (hdr, 1);
    GifSeqHdrSetVersion (hdr, "87a");
    GifSeqHdrSetCtSize (hdr, 256);
    GifSeqHdrSetCtSorted (hdr, 0);
    GifSeqHdrSetAspectRatio (hdr, 0);
    GifSeqHdrSetResolution (hdr, 3);
    GifSeqHdrEncode (hdr, bp);
    
    /*
     * Encode the color table.
     */
    GifCtEncode (256, rmap, gmap, bmap, bp);

    /*
     * Initialize the image header and encode it.
     */
    img = GifImgHdrNew ();
    GifImgHdrSetWidth (img, w);
    GifImgHdrSetHeight (img, h);
    GifImgHdrSetCtFlag (img, 0);
    GifImgHdrSetLeftPosition (img, 0);
    GifImgHdrSetTopPosition (img, 0);
    GifImgHdrSetInterlaced (img, 0);
    GifImgHdrSetGraphicControlFlag (img, 0);
    GifImgHdrEncode (img, bp);

    /*
     * Encode the image.
     */
    GifImgEncode (hdr, img, indices, bp);

    /*
     * Encode the sequence trailer to indicate end of bitstream.
     * Write the bitstream out to a file.
     */
    GifSeqTrailerEncode (bp);
    BitStreamFileWrite (bs, f, 0);

    /*
     * Clean up
     */
    fclose (f);
    ByteFree (r);
    ByteFree (g);
    ByteFree (b);
    ByteFree (indices);
    ImageMapFree (rmap);
    ImageMapFree (gmap);
    ImageMapFree (bmap);

    return 0;
}