package uk.co.mmscomputing.imageio.jpeg;
import java.io.*;
// [1] Joerg Anders, TU Chemnitz, Fakultaet fuer Informatik, GERMANY
// ja@informatik.tu-chemnitz.de
// http://rnvs.informatik.tu-chemnitz.de/~jan/MPEG/HTML/IDCT.html [last accessed 2005-11-23]
public class JPEGFastDCTInputStream extends JPEGDCTInputStream{
public JPEGFastDCTInputStream(JPEGHuffmanInputStream dc,JPEGHuffmanInputStream ac,int[] qt,int bps){
super(dc,ac,qt,bps);
}
static private final int CONST_BITS = 11;
static private int compute(double val){return (int)(val*(1<<CONST_BITS));}
static private final int VAL_BITS = 11;
static private final int ALLBITS = CONST_BITS + VAL_BITS;
static private final int TWO = CONST_BITS + 1;
static private final int C6 = compute(2.0*Math.sin(Math.PI/8.0));
static private final int C4C6 = compute(2.0*Math.sqrt(2.0)*Math.sin(Math.PI/8.0));
static private final int C4 = compute(Math.sqrt(2.0));
static private final int Q = compute(2.0*(Math.cos(Math.PI/8.0)-Math.sin(Math.PI/8.0)));
static private final int C4Q = compute(2.0*Math.sqrt(2.0)*(Math.cos(Math.PI/8.0)-Math.sin(Math.PI/8.0)));
static private final int R = compute(2.0*(Math.cos(Math.PI/8.0)+Math.sin(Math.PI/8.0)));
static private final int C4R = compute(2.0*Math.sqrt(2.0)*(Math.cos(Math.PI/8.0)+Math.sin(Math.PI/8.0)));
// protected int matr1[]=new int[DCTBlockSize]; // declared in JPEGDCTInputStream
protected int matr2[]=new int[DCTBlockSize];
public void inverseDCT(int[] buffer){
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
int plus8, plus16, plus24, plus32, plus40, plus48, plus56;
int co1, co2, co3, co5, co6, co7, co35, co17;
int n0, n1, n2, n3;
int m1, m2, m3, m4, m5, m6, m7, tmp;
int l0 = 0, l1 = 0, l2 = 0, l3 = 0;
int g0, g1, g2, g3;
int i, j, p;
for (p = j = 0; j < 64; j+=8) {
matr1[p++] = buffer[j+0];
matr1[p++] = buffer[j+4];
matr1[p++] = (co2 = buffer[j+2])-(co6 = buffer[j+6]);
matr1[p++] = co2+co6;
matr1[p++] =-(co3=buffer[j+3])+(co5=buffer[j+5]);
matr1[p++] = (co17=(co1=buffer[j+1]+(co7=buffer[j+7])))-(co35=co3+co5);
matr1[p++] = co1-co7;
matr1[p++] = co17+co35;
}
for (p = i = 0; i < 8; i++) {
switch(i) {
case 0:
case 1:
case 3:
case 7:
tmp4 = (co3=matr1[24+i])-(co5=matr1[40+i]);
tmp6 = (co1=matr1[ 8+i])-(co7=matr1[56+i]);
tmp = C6 * (tmp6-tmp4);
matr2[p++] = matr1[i ] << CONST_BITS;
matr2[p++] = matr1[32+i] << CONST_BITS;
matr2[p++] = ((co2=matr1[16+i])-(co6=matr1[48+i]))*C4;
matr2[p++] = (co2+co6) << CONST_BITS;
matr2[p++] = Q*tmp4-tmp;
matr2[p++] = ((co17=co1 + co7)-(co35=co3+co5))*C4;
matr2[p++] = R*tmp6-tmp;
matr2[p++] = (co17+co35) << CONST_BITS;
break;
case 2:
case 5:
tmp4 = (co3=matr1[24+i])-(co5=matr1[40+i]);
tmp6 = (co1=matr1[ 8+i])-(co7=matr1[56+i]);
tmp = C4C6 * (tmp6-tmp4);
matr2[p++] = C4*matr1[i ];
matr2[p++] = C4*matr1[i+32];
matr2[p++] = ((co2=matr1[16+i])-(co6=matr1[48+i])) << TWO;
matr2[p++] = C4*(co2+co6);
matr2[p++] = C4Q*tmp4-tmp;
matr2[p++] = ((co17 =co1+co7)-(co35=co3+co5)) << TWO;
matr2[p++] = C4R*tmp6-tmp;
matr2[p++] = C4* (co17+co35);
break;
case 4:
matr2[p++] = matr1[ i];
matr2[p++] = matr1[32+i];
matr2[p++] = (co2=matr1[16+i])-(co6=matr1[48+i]);
matr2[p] = co2+co6;
l0 = l2 = -(co3=matr1[24+i])+(co5=matr1[40+i]);
p += 2;
matr2[p] = (co17 =(co1=matr1[ 8+i]) + (co7=matr1[56+i]))-(co35=co3+co5);
l3 = -( l1 = co1-co7);
p += 2;
matr2[p++] = co17+co35;
break;
case 6:
matr2[p++] = matr1[ i];
matr2[p++] = matr1[32+i];
matr2[p++] = (co2=matr1[16+i])-(co6=matr1[48+i]);
matr2[p] = co2+co6;
l1 += (tmp4 = -(co3=matr1[24+i])+(co5=matr1[40+i]));
l3 += tmp4;
p += 2;
matr2[p] = (co17 =(co1=matr1[ 8+i]) + (co7=matr1[56+i]))-(co35=co3+co5);
l2 += (tmp6 = co1-co7);
l0 -= tmp6;
p += 2;
matr2[p++] = co17+co35;
break;
}
}
g0 = C4*(l0+l1);
g1 = C4*(l0-l1);
g2 = l2 << TWO;
g3 = l3 << TWO;
matr2[36] = g0+g2;
matr2[38] = g1+g3;
matr2[52] = g1-g3;
matr2[54] = g2-g0;
tmp = C6*(matr2[32]+matr2[48]);
matr2[32] = -Q*matr2[32]-tmp;
matr2[48] = R*matr2[48]-tmp;
tmp = C6*(matr2[33] + matr2[49]);
matr2[33] = -Q*matr2[33]-tmp;
matr2[49] = R*matr2[49]-tmp;
tmp = C4C6 * (matr2[34] + matr2[50]);
matr2[34] = -C4Q*matr2[34]-tmp;
matr2[50] = C4R*matr2[50]-tmp;
tmp = C6*(matr2[35] + matr2[51]);
matr2[35] = -Q*matr2[35]-tmp;
matr2[51] = R*matr2[51]-tmp;
tmp = C4C6 * (matr2[37] + matr2[53]);
matr2[37] = -C4Q*matr2[37]-tmp;
matr2[53] = C4R*matr2[53]-tmp;
tmp = C6*(matr2[39] + matr2[55]);
matr2[39] = -Q*matr2[39]-tmp;
matr2[55] = R*matr2[55]-tmp;
for (p=i = 0; i < 8; i++,p+=8) {
matr1[p] = (tmp4 = (n3 = matr2[p]+matr2[p+1]) + matr2[p+3]) + matr2[p+7];
matr1[p+3] = (tmp6=n3-matr2[p+3])-(tmp7=matr2[p+4]-(tmp1=(tmp2=matr2[p+6]-matr2[p+7])-matr2[p+5]));
matr1[p+4] = tmp6+tmp7;
matr1[p+1] = (tmp3=(n1=matr2[p]-matr2[p+1])+(n2=matr2[p+2]-matr2[p+3]))+tmp2;
matr1[p+2] = (tmp5=n1-n2)-tmp1;
matr1[p+5] = tmp5+tmp1;
matr1[p+6] = tmp3-tmp2;
matr1[p+7] = tmp4-matr2[p+7];
}
plus8 = 8; plus16 = 16; plus24 = 24; plus32 = 32; plus40 = 40; plus48 = 48; plus56 = 56;
for (p = i = 0; p < 64; p+=8) {
buffer[p] = ((tmp4 = (n3 = matr1[i]+matr1[plus8]) +matr1[plus24]) + matr1[plus56]) >> ALLBITS;
buffer[p+3] = ((tmp6=n3-matr1[plus24])-(tmp7=matr1[plus32++]-(tmp1=(tmp2=matr1[plus48++]-matr1[plus56])-matr1[plus40++])))>>ALLBITS;
buffer[p+4] = (tmp6+tmp7) >> ALLBITS;
buffer[p+1] = ((tmp3 = (n1 = matr1[i++]-matr1[plus8++])+ (n2 = matr1[plus16++]-matr1[plus24++]))+tmp2) >> ALLBITS;
buffer[p+2] = ((tmp5 = n1-n2) -tmp1) >> ALLBITS;
buffer[p+5] = (tmp5+tmp1) >> ALLBITS;
buffer[p+6] = (tmp3-tmp2) >> ALLBITS;
buffer[p+7] = (tmp4-matr1[plus56++]) >> ALLBITS;
}
}
static void normalize(int qt[]){ // need to normalize quantization tables; called in JPEGInputStream
double d;
for(int j=0;j<DCTSize;j++){
for(int i=0;i<DCTSize;i++){
d=(double)qt[ZigZagTable[j*DCTSize+i]];
if((i==0)&&(j==0)){
d/=8.0;
}else if((i==0)||(j==0)){
d/=8.0/Math.sqrt(2.0);
}else{
d/=4.0;
}
qt[ZigZagTable[j*DCTSize+i]]=(int)(d*(1<<VAL_BITS)*Math.cos(Math.PI*i/16.0)* Math.cos(Math.PI*j/16.0)+0.5);
}
}
}
}