/*------------------------------------------------------------------------
*
* 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
*
* Sugata sugata@cs.cornell.edu
*
* Usage : ppmtojpg inputPPm outputJPG
*
* Reads a PPM file and encode it into a JPG file.
*
*------------------------------------------------------------------------
*/
#include "dvmbasic.h"
#include "dvmjpeg.h"
#include "dvmcolor.h"
#include "dvmpnm.h"
#ifdef WIN32
#include "windows.h"
#endif
void ReadPPM(char *, PnmHdr **, ByteImage **, ByteImage **, ByteImage **);
int main(int argc, char *argv[])
{
#ifdef DO_TIMING
LARGE_INTEGER curr;
__int64 start, stop, f;
#endif
FILE *out;
int i;
PnmHdr *hdr;
ByteImage *r, *g, *b, *y, *u, *v, *cr, *cg, *cb;
ScImage *scy, *scu, *scv;
int w, h, bw, bh;
BitStream *outBs;
BitParser *outBp;
JpegHdr *jpegHdr;
JpegScanHdr *scanHdr;
JpegHuffTable *huffTable;
/*
* Check arguments and read in the input PPM.
*/
if (argc != 3) {
fprintf(stderr, "usage : ppmtojpg <inputppm> <outputjpg>\n");
exit(1);
}
out = fopen(argv[2], "wb");
ReadPPM(argv[1], &hdr, &r, &g, &b);
#ifdef DO_TIMING
QueryPerformanceFrequency(&curr);
f = curr.QuadPart;
QueryPerformanceCounter(&curr);
start = curr.QuadPart;
#endif
/*
* Find the dimension of the input image.
*/
w = PnmHdrGetWidth(hdr);
h = PnmHdrGetHeight(hdr);
/*
* Initialize the JPEG header. We uses the standard quantization
* table and the standard Huffman table. We are encoding the image
* using 4:2:0 sampling, so the block width and height are 2x2 for y
* 1x1 for u, and 1x1 for v. We also make u and v plane share the same
* quantization table.
*/
jpegHdr = JpegHdrNew();
JpegHdrSetWidth(jpegHdr, w);
JpegHdrSetHeight(jpegHdr, h);
JpegHdrSetNumOfComponents(jpegHdr, 3);
JpegHdrSetRestartInterval(jpegHdr, 0);
JpegHdrSetPrecision(jpegHdr, 8);
JpegHdrSetBlockWidth(jpegHdr, 0, 2);
JpegHdrSetBlockWidth(jpegHdr, 1, 1);
JpegHdrSetBlockWidth(jpegHdr, 2, 1);
JpegHdrSetMaxBlockWidth(jpegHdr, 2);
JpegHdrSetBlockHeight(jpegHdr, 0, 2);
JpegHdrSetBlockHeight(jpegHdr, 1, 1);
JpegHdrSetBlockHeight(jpegHdr, 2, 1);
JpegHdrSetMaxBlockHeight(jpegHdr, 2);
JpegHdrSetQtId(jpegHdr, 0, 0);
JpegHdrSetQtId(jpegHdr, 1, 1);
JpegHdrSetQtId(jpegHdr, 2, 1);
JpegHdrStdQtInit(jpegHdr);
JpegHdrStdHtInit(jpegHdr);
/*
* Initialize the scan header.
*/
scanHdr = JpegScanHdrNew();
JpegScanHdrSetNumOfComponents(scanHdr, 3);
JpegScanHdrSetScanId(scanHdr, 0, 0);
JpegScanHdrSetScanId(scanHdr, 1, 1);
JpegScanHdrSetScanId(scanHdr, 2, 2);
JpegScanHdrSetDcId(scanHdr, 0, 0);
JpegScanHdrSetDcId(scanHdr, 1, 1);
JpegScanHdrSetDcId(scanHdr, 2, 1);
JpegScanHdrSetAcId(scanHdr, 0, 0);
JpegScanHdrSetAcId(scanHdr, 1, 1);
JpegScanHdrSetAcId(scanHdr, 2, 1);
/*
* Creates and initialize a new huffman table for encoding.
*/
huffTable = JpegHuffTableNew(3);
JpegHuffTableInit(jpegHdr, scanHdr, huffTable);
/*
* Creates a new bitstream. Assumes the the JPEG image is smaller
* than the PPM, so a BitStream of size 3*w*h is enough for the output
* JPEG.
*/
outBs = BitStreamNew(3*w*h);
outBp = BitParserNew();
BitParserWrap(outBp, outBs);
/*
* Encodes the image start code, quantization table, huffman table,
* header and scan header.
*/
JpegStartCodeEncode(outBp);
i = JpegHdrQtEncode(jpegHdr, outBp);
i = JpegHdrHtEncode(jpegHdr, outBp);
i = JpegHdrEncode(jpegHdr, 1, outBp);
i = JpegScanHdrEncode(jpegHdr, scanHdr, outBp);
/*
* We clip the input r, g, b into strips of size w x 16, and encodes
* each strips.
*/
bw = w/8;
scy = ScNew(bw, 2);
scu = ScNew(bw/2, 1);
scv = ScNew(bw/2, 1);
y = ByteNew(w, 16);
u = ByteNew(w/2, 8);
v = ByteNew(w/2, 8);
cr = ByteClip(r, 0, 0, 0, 0);
cg = ByteClip(g, 0, 0, 0, 0);
cb = ByteClip(b, 0, 0, 0, 0);
JpegScanIncEncode420(jpegHdr, scanHdr, huffTable, NULL, scu, scv, outBp);
bh = h >> 4;
for (i = 0; i < bh; i++) {
ByteReclip(r, 0, i<<4, w, 16, cr);
ByteReclip(g, 0, i<<4, w, 16, cg);
ByteReclip(b, 0, i<<4, w, 16, cb);
RgbToYuv420(cr, cg, cb, y, u ,v);
ByteToSc(y, scy);
ByteToSc(u, scu);
ByteToSc(v, scv);
JpegScanIncEncode420(jpegHdr, scanHdr, huffTable, scy, scu, scv, outBp);
}
JpegScanIncEncode420(jpegHdr, scanHdr, huffTable, NULL, scu, scv, outBp);
JpegEndCodeEncode(outBp);
#ifdef DO_TIMING
QueryPerformanceCounter(&curr);
stop = curr.QuadPart;
printf("TOTAL TIME : %f ms\n", (stop - start)/(double)f*1000.0);
#endif
BitStreamFileWriteSegment(outBs, out, 0, BitParserTell(outBp));
/*
* Clean up.
*/
fclose(out);
ByteFree(y);
ByteFree(u);
ByteFree(v);
ByteFree(r);
ByteFree(g);
ByteFree(b);
ScFree(scy);
ScFree(scu);
ScFree(scv);
JpegHdrFree(jpegHdr);
JpegScanHdrFree(scanHdr);
JpegHuffTableFree(huffTable);
return 0;
}