/*------------------------------------------------------------------------
 *
 * 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.
 *
 * jpgtoppm
 *
 * Sugata sugata@cs.cornell.edu
 *
 * Usage : jpgtoppm inputJPG outputPPM
 *
 * Converts an input JPEG into a PPM file, quality = 50, using default
 * quantization table and huffman table.  Only common sampling format 
 * (420 and 422) and JPEG with single scan is supported.
 *
 *------------------------------------------------------------------------
 */
#include "dvmbasic.h"
#include "dvmjpeg.h"
#include "dvmpnm.h"
#include "dvmcolor.h"

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

int main(int argc, char *argv[])
{
    BitStream *bs;
    BitParser *bp;
    JpegHdr *hdr;
    JpegScanHdr *scanHdr;
    int nc, wi, hi, bw, bh, mbw, mbh, *xdec, *ydec, id, pw, ph;
    ByteImage *y, *u, *v, *r, *g, *b;
    int i;
    ScImage **sclist;
    PnmHdr* pnmHdr;

    /*
     * Check the arguments.
     */
    if (argc < 3) {
        fprintf(stderr, "usage : %s input output\n", argv[0]);
	exit(1);
    }
     
    /*
     * Initialize bitstream and bitparser.
     */
    bs = BitStreamMmapReadNew(argv[1]);
    bp = BitParserNew();
    BitParserWrap(bp, bs);

    /*
     * First, we read off the JPEG header and scan header.  
     */
    hdr = JpegHdrNew();
    JpegHdrParse(bp, hdr);
    scanHdr = JpegScanHdrNew();
    JpegScanHdrParse(bp, hdr, scanHdr);

    /*
     * Find out the number of components, width and height of the image.
     * bw and bh are the dimension of the image in blocks.
     */
    nc = JpegScanHdrGetNumOfComponents(scanHdr);
    wi = JpegHdrGetWidth(hdr);
    hi = JpegHdrGetHeight(hdr);
    bw = (wi+7)/8;
    bh = (hi+7)/8;
    mbw = JpegHdrGetMaxBlockWidth(hdr);
    mbh = JpegHdrGetMaxBlockHeight(hdr);
    xdec = (int *)malloc(sizeof(int)*nc);
    ydec = (int *)malloc(sizeof(int)*nc);
    sclist = (ScImage **)malloc(sizeof(ScImage *)*nc);
    for (i = 0; i < nc; i++) {
	id = JpegScanHdrGetScanId(scanHdr, i);
	xdec[i] = mbw/(JpegHdrGetBlockWidth(hdr, id));
	ydec[i] = mbh/(JpegHdrGetBlockHeight(hdr, id));
	sclist[i] = ScNew(bw/xdec[i], bh/ydec[i]);
    }

    /*
     * Finally, we parse the scan.
     */
    JpegScanParse(bp, hdr, scanHdr, sclist, i);

    /*
     * Prepare to decode the image.
     */
    pw = bw << 3;
    ph = bh << 3;
    y = ByteNew(pw/xdec[0], ph/ydec[0]);
    u = ByteNew(pw/xdec[1], ph/ydec[1]);
    v = ByteNew(pw/xdec[2], ph/ydec[2]);
    r = ByteNew(pw, ph);
    g = ByteNew(pw, ph);
    b = ByteNew(pw, ph);
    
    /*
     * Perform IDCT and dequantization on the image to get the raw image
     * in YUV color space.
     */
    ScIToByte(sclist[0], y);
    ScIToByte(sclist[1], u);
    ScIToByte(sclist[2], v);

    /*
     * Perform color conversion from YUV to RGB color space.
     */
    if (mbh == 1) {
	YuvToRgb422(y, u, v, r, g, b);
    } else {
	YuvToRgb420(y, u, v, r, g, b);
    }

    /*
     * Now output the PPM file.
     */
    pnmHdr = PnmHdrNew();
    PnmHdrSetWidth(pnmHdr, pw);
    PnmHdrSetHeight(pnmHdr, ph);
    PnmHdrSetMaxVal(pnmHdr, 255);
    PnmHdrSetType(pnmHdr, PPM_BIN);
    WritePPM (pnmHdr, r, g, b, argv[2]);

    /*
     * Clean up here.
     */
    PnmHdrFree(pnmHdr);
    JpegScanHdrFree(scanHdr);
    JpegHdrFree(hdr);
    ByteFree(y);
    ByteFree(u);
    ByteFree(v);
    ByteFree(r);
    ByteFree(g);
    ByteFree(b);
    BitStreamMmapReadFree(bs);
    free(xdec);
    free(ydec);

    return 0;
}