stk/Extensions/jpeg.c

1068 lines
28 KiB
C
Raw Normal View History

1998-04-10 06:59:06 -04:00
/*
* tkImgFmtJPEG.c --
*
* A photo image file handler for JPEG files.
*
* Author: Andrew Swan (aswan@cs.berkeley.edu)
* Department of Computer Science,
* University of California, Berkeley
*
1998-09-30 07:11:02 -04:00
* $Id: jpeg.c 1.1 Sat, 03 Jan 1998 13:46:25 +0100 eg $
1998-04-10 06:59:06 -04:00
*
* Parts of this file are based on code under the following
* copyrights. Include these copyrights if you do anything
* with this code
*/
/*
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
*/
/*
*
* Copyright (c) 1995 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#ifdef USE_TK
#ifdef STk_CODE
# include <stk.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <tk.h>
/*
* The format record for the JPEG file format:
*/
static int FileMatchJPEG _ANSI_ARGS_((FILE *f, char *fileName,
char *formatString, int *widthPtr,
int *heightPtr));
static int FileReadJPEG _ANSI_ARGS_((Tcl_Interp *interp,
FILE *f, char *fileName, char *formatString,
Tk_PhotoHandle imageHandle, int destX, int destY,
int width, int height, int srcX, int srcY));
Tk_PhotoImageFormat tkImgFmtJPEG = {
"JPEG", /* name */
FileMatchJPEG, /* fileMatchProc */
NULL, /* stringMatchProc */
FileReadJPEG, /* fileReadProc */
NULL, /* stringReadProc */
NULL, /* fileWriteProc */
NULL, /* stringWriteProc */
};
/*
* Prototypes for local procedures defined in this file:
*/
static int ReadJPEGFileHeader _ANSI_ARGS_((FILE *f, int *wPtr,
int *hPtr, int *decPtr,
unsigned char *lumqt,
unsigned char *chqt));
static unsigned short *CreateHufftab _ANSI_ARGS_((unsigned char *bits,
unsigned char *vals));
static void rdct _ANSI_ARGS_((short block[]));
#define DECIMATION_411 1
#define DECIMATION_422 2
/*
* ----------------------------------------
*
* Jpeg_Init
*
* Init function to be used with dynamic loading
* in Tcl 7.5
*
* ----------------------------------------
*/
int Jpeg_Init(Tcl_Interp* interp)
{
Tk_CreatePhotoImageFormat(&tkImgFmtJPEG);
return TCL_OK;
}
/*
* Standard Quantization Tables
*/
static unsigned char JPEG_StandardLumQT[] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99 };
static unsigned char JPEG_StandardChQT[] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99 };
/*
* Standard Huffman Tables
*/
static unsigned char JPEG_LDC_HuffBits[]
= { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char JPEG_LDC_HuffVals[]
= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static unsigned char JPEG_CDC_HuffBits[]
= { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
static unsigned char JPEG_CDC_HuffVals[]
= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static unsigned char JPEG_LAC_HuffBits[]
= { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
static unsigned char JPEG_LAC_HuffVals[] = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa };
static unsigned char JPEG_CAC_HuffBits[]
= { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
static unsigned char JPEG_CAC_HuffVals[] = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa };
/*
* The following macro decodes a number is the format
* that jpeg stores it.
*/
#define JPEG_EXTEND(v, t) \
((v) < (1 << (t-1) ) ? (v) + (((-1) << t) + 1) : (v))
static const char zz[] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49,
56, 57, 50, 43, 36, 29, 22, 15, 23, 30,
37, 44, 51, 58, 59, 52, 45, 38, 31, 39,
46, 53, 60, 61, 54, 47, 55, 62, 63 };
/*
* Bounds checking array for after DCT (biased by 128)
*/
static unsigned char JPEG_BoundsFix[] = {
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -128, -128, -128, -128, -128, -128, -128,
-128, -127, -126, -125, -124, -123, -122, -121,
-120, -119, -118, -117, -116, -115, -114, -113,
-112, -111, -110, -109, -108, -107, -106, -105,
-104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93,
-92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80,
-79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67,
-66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54,
-53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41,
-40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28,
-27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15,
-14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
123, 124, 125, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 };
static FILE* bitsFile;
static unsigned int currentBits;
static int bitCount;
#define getbyte(retval) if (fread(&retval, 1, 1, bitsFile) == 0) return;
/* num should be <= 16 */
/* XXX should check fread() return value */
#define fillbits(num) \
{ \
unsigned char fillval; \
while (bitCount < (num)) { \
fread(&fillval, 1, 1, bitsFile); \
currentBits <<= 8; \
currentBits |= fillval; \
bitCount += 8; \
if (fillval == 0xff) { \
fread(&fillval, 1, 1, bitsFile); \
if (fillval != 0) { \
currentBits <<= 8; \
currentBits |= fillval; \
bitCount += 8; \
} \
} \
} \
}
#define getbits(num, retval) \
{ \
fillbits(16); \
bitCount -= (num); \
(retval) = ((currentBits >> bitCount) & ((1<<(num)) - 1)); \
}
#define peekbits(num, retval) \
{ \
fillbits(16); \
(retval) = ((currentBits >> (bitCount-(num))) & ((1<<(num)) - 1)); \
}
#define flushbits(num) \
{ \
bitCount -= (num); \
}
/*
*----------------------------------------------------------------------
*
* FileMatchJPEG --
*
* This procedure is invoked by the photo image type to see if
* a file contains image data in JPEG format.
*
* Results:
* The return value is >0 if the first characters in file "f" look
* like JPEG data, and 0 otherwise.
*
* Side effects:
* The access position in f may change.
*
*----------------------------------------------------------------------
*/
static int
FileMatchJPEG(f, fileName, formatString, widthPtr, heightPtr)
FILE *f; /* The image file, open for reading. */
char *fileName; /* The name of the image file. */
char *formatString; /* User-specified format string, or NULL. */
int *widthPtr, *heightPtr; /* The dimensions of the image are
* returned here if the file is a valid
* JPEG file. */
{
unsigned char lumqt[64], chqt[64];
int decimation;
return ReadJPEGFileHeader(f, widthPtr, heightPtr, &decimation,
lumqt, chqt);
}
/*
*----------------------------------------------------------------------
*
* FileReadJPEG --
*
* This procedure is called by the photo image type to read
* JPEG format data from a file and write it into a given
* photo image.
*
* Results:
* A standard TCL completion code. If TCL_ERROR is returned
* then an error message is left in interp->result.
*
* Side effects:
* The access position in file f is changed, and new data is
* added to the image given by imageHandle.
*
*----------------------------------------------------------------------
*/
static int
FileReadJPEG(interp, f, fileName, formatString, imageHandle, destX, destY,
width, height, srcX, srcY)
Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
FILE *f; /* The image file, open for reading. */
char *fileName; /* The name of the image file. */
char *formatString; /* User-specified format string, or NULL. */
Tk_PhotoHandle imageHandle; /* The photo image to write into. */
int destX, destY; /* Coordinates of top-left pixel in
* photo image to be written to. */
int width, height; /* Dimensions of block of photo image to
* be written to. */
int srcX, srcY; /* Coordinates of top-left pixel to be used
* in image being read. */
{
int w, h, wFull, hFull, decimation; /* width, height, decimation */
unsigned char lumqt[64], chqt[64]; /* quantization tables */
unsigned short *ldht, *laht, *cdht, *caht; /* huffman tables */
short yPredict, crPredict, cbPredict;
Tk_PhotoImageBlock tkblock;
int mcu, maxmcu;
unsigned char *final;
w = h = -1;
memcpy(lumqt, JPEG_StandardLumQT, 64);
memcpy(chqt, JPEG_StandardChQT, 64);
ldht = CreateHufftab(JPEG_LDC_HuffBits, JPEG_LDC_HuffVals);
laht = CreateHufftab(JPEG_LAC_HuffBits, JPEG_LAC_HuffVals);
cdht = CreateHufftab(JPEG_CDC_HuffBits, JPEG_CDC_HuffVals);
caht = CreateHufftab(JPEG_CAC_HuffBits, JPEG_CAC_HuffVals);
if (ReadJPEGFileHeader(f, &w, &h, &decimation, lumqt, chqt) == 0) {
Tcl_AppendResult(interp, "couldn't read file \"", fileName,
"\" as a JPEG image.", NULL);
return TCL_ERROR;
}
if ((srcX + width) > w) {
width = w - srcX;
}
if ((srcY + height) > h) {
height = h - srcY;
}
if ((width <= 0) || (height <= 0)
|| (srcX >= w) || (srcY >= h)) {
return TCL_OK;
}
wFull = w;
if (w%16 != 0) {
wFull += (16 - (w%16));
}
hFull = h;
if (decimation == DECIMATION_422) {
if (h%8 != 0) {
hFull += (8 - (h%8));
}
maxmcu = (wFull/16) * (hFull/8);
} else if (decimation == DECIMATION_411) {
if (h%16 != 0) {
hFull += (16 - (h%16));
}
maxmcu = (wFull/16) * (hFull/16);
}
final = (unsigned char *) ckalloc(4 * wFull * hFull);
if (final == NULL) {
return TCL_ERROR;
}
Tk_PhotoBlank(imageHandle);
Tk_PhotoExpand(imageHandle, destX + width, destY + height);
tkblock.pixelPtr = final;
tkblock.width = w;
tkblock.height = h;
tkblock.pitch = 4 * wFull;
tkblock.pixelSize = 4;
tkblock.offset[0] = 0;
tkblock.offset[1] = 1;
tkblock.offset[2] = 2;
yPredict = 0;
crPredict = cbPredict = 0;
/*
* Main decode loop
*/
for (mcu = 0; mcu < maxmcu; mcu++) {
short block[64];
unsigned short *dcht;
unsigned short *acht;
unsigned char *qt;
short *predictor;
int stride;
int piece, pieces;
int code, value;
unsigned char difflen;
short diff;
int k;
unsigned char mixed, run, coefflen, coeff;
unsigned char *dest;
int mcux, mcuy;
signed char y[16*16], cr[8*8], cb[8*8];
int row, col, rows, cols;
signed char *outPtr;
short *inPtr;
unsigned char *BoundsFix = JPEG_BoundsFix + 128 + 128;
mcux = 16 * (mcu % (wFull / 16));
if (decimation == DECIMATION_422) {
mcuy = 8 * (mcu / (wFull / 16));
pieces = 4;
} else if (decimation == DECIMATION_411) {
mcuy = 16 * (mcu / (wFull / 16));
pieces = 6;
}
for (piece = 0; piece < pieces; piece++) {
/*
* Zero the piece we are about to decode
*/
memset(block, 0, sizeof(block));
/*
* Calculate everything specific to which plane we
* are decoding to avoid conditionals in the main loop
*/
if (decimation == DECIMATION_411) {
if (piece < 2) {
dcht = ldht;
acht = laht;
qt = lumqt;
predictor = &yPredict;
dest = y + (8 * piece);
stride = 16;
} else if (piece < 4) {
dcht = ldht;
acht = laht;
qt = lumqt;
predictor = &yPredict;
dest = y + (16*8) + (8 * (piece-2));
stride = 16;
} else if (piece == 4) {
dcht = cdht;
acht = caht;
qt = chqt;
predictor = &cbPredict;
dest = cb;
stride = 8;
} else {
dcht = cdht;
acht = caht;
qt = chqt;
predictor = &crPredict;
dest = cr;
stride = 8;
}
} else if (decimation == DECIMATION_422) {
if (piece < 2) {
dcht = ldht;
acht = laht;
qt = lumqt;
predictor = &yPredict;
dest = y + (8 * piece);
stride = 16;
} else if (piece == 2) {
dcht = cdht;
acht = caht;
qt = chqt;
predictor = &cbPredict;
dest = cb;
stride = 8;
} else {
dcht = cdht;
acht = caht;
qt = chqt;
predictor = &crPredict;
dest = cr;
stride = 8;
}
}
/*
* Get the DC value
*/
peekbits(16, code);
value = dcht[code];
flushbits(value >> 8);
difflen = value & 0xff;
if (difflen) {
getbits(difflen, diff);
diff = JPEG_EXTEND(diff, difflen);
*predictor += diff;
}
block[0] = (*predictor) * qt[0];
/*
* Get the AC values
*/
for (k=1; k<64; ) {
peekbits(16, code);
value = acht[code];
flushbits(value >> 8);
mixed = value & 0xff;
run = mixed >> 4;
coefflen = mixed & 0xf;
if (coefflen == 0) {
if (run == 15) {
k += 16;
} else {
k = 64;
}
} else {
k += run;
getbits(coefflen, coeff);
block[zz[k]] = (JPEG_EXTEND(coeff, coefflen)) * qt[zz[k]];
k++;
}
}
/*
* Do Reverse DCT and put the data where it belongs
*/
rdct(block);
inPtr = block;
outPtr = dest;
for (row=0; row<8; row++) {
outPtr[0] = BoundsFix[inPtr[0]];
outPtr[1] = BoundsFix[inPtr[1]];
outPtr[2] = BoundsFix[inPtr[2]];
outPtr[3] = BoundsFix[inPtr[3]];
outPtr[4] = BoundsFix[inPtr[4]];
outPtr[5] = BoundsFix[inPtr[5]];
outPtr[6] = BoundsFix[inPtr[6]];
outPtr[7] = BoundsFix[inPtr[7]];
outPtr += stride;
inPtr += 8;
}
}
if (decimation == DECIMATION_422) {
rows = 8;
cols = 16;
} else if (decimation == DECIMATION_411) {
rows = 16;
cols = 16;
}
/* XXX can this be made more efficient? */
for (row=0; row<rows; row++) {
for (col=0; col<cols; col++) {
int index = 4 * (wFull*(row+mcuy) + (col+mcux));
int yval, crval, cbval, val;
yval = ((int) y[16*row + col]) + (128-16);
crval = cr[8*(row/2) + col/2];
cbval = cb[8*(row/2) + col/2];
val = (1000*yval + 1596*crval)/1000;
final[index] = (val<0) ? 0 : (val>255) ? 255 : val;
val = (1000*yval - 813*crval - 391*cbval)/1000;
final[index + 1] = (val<0) ? 0 : (val>255) ? 255 : val;
val = (1000*yval + 2018*cbval)/1000;
final[index + 2] = (val<0) ? 0 : (val>255) ? 255 : val;
final[index + 3] = 0;
}
}
}
ckfree(ldht);
ckfree(laht);
ckfree(cdht);
ckfree(caht);
Tk_PhotoPutBlock(imageHandle, &tkblock, 0, 0, w, h);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ReadJPEGFileHeader --
*
* This procedure reads the JPEG header from the beginning of a
* JPEG file and returns the dimensions of the image.
*
* Results:
* The return value is 1 if a valid JFIF header is found in
* the file, 0 otherwise. If a valid JFIF header is found,
* then *widthPtr and *heightPtr are set to hold the dimensions
* of the image.
*
* Side effects:
* The access position in f advances.
*
*----------------------------------------------------------------------
*/
static int
ReadJPEGFileHeader(f, wPtr, hPtr, decPtr, lumqt, chqt)
FILE *f; /* Image file to read the header from */
int *wPtr; /* Pointer to int for storing width */
int *hPtr; /* Pointer to int for storing height */
int *decPtr; /* Pointer to int for storing decimation */
unsigned char *lumqt; /* Luminance Quantization table */
unsigned char *chqt; /* Chrominance Quantization table */
{
int marker, w, h, lumqtid, chqtid, decimation;
unsigned char* qtables[256];
int i;
memset(qtables, 0, sizeof(qtables) );
bitsFile = f;
currentBits = 0;
bitCount = 0;
fillbits(16);
w = h = decimation = -1;
lumqtid = chqtid = -1;
peekbits(8, marker);
while (marker == 0xff) {
flushbits(8);
getbits(8, marker);
switch (marker) {
case 0xc0:
{
/* SOF: Start of Frame */
int value, i;
/* Flush length */
flushbits(16);
/* Check sample precision */
getbits(8, value);
if (value != 8) {
return 0;
}
/* Get w and h */
getbits(16, h);
getbits(16, w);
/* Check the components */
getbits(8, value);
if (value != 3) {
return 0;
}
for (i=0; i<3; i++) {
/* Ignore ID number */
flushbits(8);
/* Check decimation */
getbits(8, value);
if (i == 0) {
if (value == 0x21) {
decimation = DECIMATION_422;
} else if (value == 0x22) {
decimation = DECIMATION_411;
} else {
return 0;
}
getbits(8, lumqtid);
} else {
if (value != 0x11) {
return 0;
}
getbits(8, chqtid);
}
}
}
break;
case 0xdb:
{
/* DQT: Define Quantization Table */
int length, id, tab, i;
unsigned char *qt;
/* Find the length */
getbits(16, length);
if ((length-2) % 65 != 0) {
return 0;
}
length = (length - 2) / 65;
for (tab = 0; tab < length; tab++) {
getbits(8, id);
if (qtables[id] == NULL) {
qtables[id] = ckalloc(64 * sizeof(unsigned char));
}
qt = qtables[id];
for (i = 0; i < 64; i++) {
getbits(8, qt[zz[i]]);
}
}
}
break;
case 0xc4: /* DHT: Define Huffman Table */
case 0xdd: /* DRI: Define Reset Interval */
case 0xda: /* SOS: Start of Scan */
/* Ignore these codes */
/* XXX add support for DHT */
peekbits(16, marker);
flushbits(8 * marker);
break;
case 0xd8: /* SOI: Start of Image */
case 0xd9: /* EOI: End of Image */
/* Ignore these codes */
break;
default:
/* Unhandled code -- ignore it */
peekbits(16, marker);
flushbits(8 * marker);
break;
}
peekbits(8, marker);
}
if ((w == -1) || (h == -1) || (decimation == -1)) {
return 0;
}
*wPtr = w;
*hPtr = h;
*decPtr = decimation;
if (lumqtid != -1 && qtables[lumqtid] != NULL)
memcpy(lumqt, qtables[lumqtid], 64 * sizeof(unsigned char));
if (chqtid != -1 && qtables[chqtid] != NULL)
memcpy(chqt, qtables[chqtid], 64 * sizeof(unsigned char));
for (i=0; i<256; i++)
if (qtables[i] != NULL)
ckfree(qtables[i]);
return 1;
}
/*
*--------------------------------------------------------------
*
* CreateHufftab
*
* Convert a list of bits and values for a Huffman
* table in to a table that can be used in decoding.
*
* Results:
* The table itself is returned. It should be freed
* with FreeHufftab
*
* Side effects:
* Memory is allocated for the table
*
*--------------------------------------------------------------
*/
static unsigned short *
CreateHufftab(unsigned char *bits, unsigned char *vals)
{
int symbols, sizes[256], codes[256], code, i, j;
unsigned short *table;
/*
* Allocate some memory
*/
table = (unsigned short *) ckalloc(65536 * sizeof(short));
if (table == NULL) {
return NULL;
}
memset(table, 0, 65536 * sizeof(short) );
/*
* Count the total number of symbols
* and generate the codes
*/
symbols = 0;
code = 0;
for (i=0; i<16; i++) {
for (j=0; j<(int)(bits[i]); j++) {
codes[symbols] = code++;
sizes[symbols] = i + 1;
symbols++;
}
code <<= 1;
}
/*
* Generate the values in the final table
*/
for (i=0; i<symbols; i++) {
int val, index, bits;
val = (sizes[i] << 8) | vals[i];
bits = 16 - sizes[i];
index = codes[i] << bits;
for (j=0; j< 1<<bits; j++) {
table[index | j] = val ;
}
}
return table;
}
/*
*--------------------------------------------------------------
*
* rdct --
*
* The inverse DCT function.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
rdct(short *data)
{
int tmp0, tmp1, tmp2, tmp3;
int tmp10, tmp11, tmp12, tmp13;
int z1, z2, z3, z4, z5;
int d0, d1, d2, d3, d4, d5, d6, d7;
register short *dataptr;
int row;
#define FIX(x) ((x) * (1<<13) + 0.5)
/* Pass 1: process rows. */
/* Note results are scaled up by sqrt(8) compared to a true IDCT; */
/* furthermore, we scale the results by 2**PASS1_BITS. */
dataptr = data;
for (row = 7; row >= 0; row--) {
d0 = dataptr[0];
d1 = dataptr[1];
d2 = dataptr[2];
d3 = dataptr[3];
d4 = dataptr[4];
d5 = dataptr[5];
d6 = dataptr[6];
d7 = dataptr[7];
/* Even part */
z1 = (d2 + d6) * FIX(0.541196100);
tmp2 = z1 - (d6 * FIX(1.847759065));
tmp3 = z1 + (d2 * FIX(0.765366865));
tmp0 = (d0 + d4) << 13;
tmp1 = (d0 - d4) << 13;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
/* Odd part */
z1 = d7 + d1;
z2 = d5 + d3;
z3 = d7 + d3;
z4 = d5 + d1;
z5 = (z3 + z4) * FIX(1.175875602);
tmp0 = d7 * FIX(0.298631336);
tmp1 = d5 * FIX(2.053119869);
tmp2 = d3 * FIX(3.072711026);
tmp3 = d1 * FIX(1.501321110);
z1 = -z1 * FIX(0.899976223);
z2 = -z2 * FIX(2.562915447);
z3 = -z3 * FIX(1.961570560);
z4 = -z4 * FIX(0.390180644);
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
/* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
dataptr[0] = (short) ((tmp10 + tmp3 + (1 << 10)) >> 11);
dataptr[7] = (short) ((tmp10 - tmp3 + (1 << 10)) >> 11);
dataptr[1] = (short) ((tmp11 + tmp2 + (1 << 10)) >> 11);
dataptr[6] = (short) ((tmp11 - tmp2 + (1 << 10)) >> 11);
dataptr[2] = (short) ((tmp12 + tmp1 + (1 << 10)) >> 11);
dataptr[5] = (short) ((tmp12 - tmp1 + (1 << 10)) >> 11);
dataptr[3] = (short) ((tmp13 + tmp0 + (1 << 10)) >> 11);
dataptr[4] = (short) ((tmp13 - tmp0 + (1 << 10)) >> 11);
dataptr += 8; /* advance pointer to next row */
}
/* Pass 2: process columns. */
/* Note that we must descale the results by a factor of 8 == 2**3, */
/* and also undo the PASS1_BITS scaling. */
dataptr = data;
for (row = 8-1; row >= 0; row--) {
d0 = dataptr[8*0];
d1 = dataptr[8*1];
d2 = dataptr[8*2];
d3 = dataptr[8*3];
d4 = dataptr[8*4];
d5 = dataptr[8*5];
d6 = dataptr[8*6];
d7 = dataptr[8*7];
/* Even part */
z1 = (d2 + d6) * FIX(0.541196100);
tmp2 = z1 - (d6 * FIX(1.847759065));
tmp3 = z1 + (d2 * FIX(0.765366865));
tmp0 = (d0 + d4) << 13;
tmp1 = (d0 - d4) << 13;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
/* Odd part */
z1 = d7 + d1;
z2 = d5 + d3;
z3 = d7 + d3;
z4 = d5 + d1;
z5 = (z3 + z4) * FIX(1.175875602);
tmp0 = d7 * FIX(0.298631336);
tmp1 = d5 * FIX(2.053119869);
tmp2 = d3 * FIX(3.072711026);
tmp3 = d1 * FIX(1.501321110);
z1 = -z1 * FIX(0.899976223);
z2 = -z2 * FIX(2.562915447);
z3 = -z3 * FIX(1.961570560);
z4 = -z4 * FIX(0.390180644);
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
dataptr[8*0] = (short) ((tmp10 + tmp3 + (1 << 17)) >> 18);
dataptr[8*7] = (short) ((tmp10 - tmp3 + (1 << 17)) >> 18);
dataptr[8*1] = (short) ((tmp11 + tmp2 + (1 << 17)) >> 18);
dataptr[8*6] = (short) ((tmp11 - tmp2 + (1 << 17)) >> 18);
dataptr[8*2] = (short) ((tmp12 + tmp1 + (1 << 17)) >> 18);
dataptr[8*5] = (short) ((tmp12 - tmp1 + (1 << 17)) >> 18);
dataptr[8*3] = (short) ((tmp13 + tmp0 + (1 << 17)) >> 18);
dataptr[8*4] = (short) ((tmp13 - tmp0 + (1 << 17)) >> 18);
dataptr++; /* advance pointer to next column */
}
}
#ifdef STk_CODE
PRIMITIVE STk_init_jpeg(void)
{
extern Tcl_Interp *STk_main_interp;
Jpeg_Init(STk_main_interp);
return UNDEFINED;
}
#endif
#else
/* Some compilers hate to produce an empty object file. */
static char dumb = '?';
#endif