JPEGDecoderpublic class JPEGDecoder extends Object
Fields Summary |
---|
private int | height | private static final int | MSB | private static final int | MAX_HUFFMAN_SUBTREE | private int | nComp | private int[] | qTab | private int[] | dcTab | private int[] | acTab | private int[] | nBlock | private int | YH | private int | YV | private int | Xsize | private int | Ysize | private int | marker | private int | marker_index | private int | Ri | private int[] | DU | private int | x | private int | y | private int | num | private int | yp | private int[] | IDCT_Source | private static final int[] | IDCT_P | private static final int[] | table | private FrameHeader | FH | private ScanHeader | SH | private QuantizationTable | QT | private HuffmanTable | HT | private int[] | HuffTabHuffman table for fast search: (HuffTab) 8-bit Look up table
2-layer search architecture, 1st-layer represent 256 node (8 bits)
if codeword-length > 8 bits, then
the entry of 1st-layer = (# of 2nd-layer table) | MSB
and it is stored in the 2nd-layer
Size of tables in each layer are 256.
HuffTab[*][*][0-256] is always the only 1st-layer table.
An entry can be:
(1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer
(2) (Code length) << 8 | HuffVal |
Methods Summary |
---|
private void | Build_HuffTab(int[] tab, int[] L, int[][] V)
/* Build_HuffTab()
Parameter: t table ID
c table class ( 0 for DC, 1 for AC )
L[i] # of codewords which length is i
V[i][j] Huffman Value (length=i)
Effect:
build up HuffTab[t][c] using L and V.
*/
int current_table,i,j,n,table_used, temp;
int k;
temp=256;
k=0;
for(i=0; i<8; i++){ // i+1 is Code length
for(j=0; j<L[i]; j++){
for(n=0; n < (temp>>(i+1)); n++){
tab[k]=V[i][j] | ((i+1) << 8);
k++;
}
}
}
for(i=1; k<256; i++, k++) tab[k]= i | MSB;
if(i>50){
error("ERROR: Huffman table out of memory!");
}
table_used=i;
current_table=1;
k=0;
for(i=8; i<16; i++){ // i+1 is Code length
for(j=0; j<L[i]; j++){
for(n=0; n < (temp>>(i-7)); n++){
tab[current_table*256+k]=V[i][j] | ((i+1)<<8);
k++;
}
if(k>=256){
if(k>256){
error("ERROR: Huffman table error(1)!");
}
k=0; current_table++;
}
}
}
| private void | EnhanceQuantizationTable(int[] qtab)
int i ;
for( i = 0 ; i < 8 ; i ++ )
{
qtab[table[0*8+i]] *= 90 ;
qtab[table[4*8+i]] *= 90 ;
qtab[table[2*8+i]] *= 118 ;
qtab[table[6*8+i]] *= 49 ;
qtab[table[5*8+i]] *= 71 ;
qtab[table[1*8+i]] *= 126 ;
qtab[table[7*8+i]] *= 25 ;
qtab[table[3*8+i]] *= 106 ;
}
for( i = 0 ; i < 8 ; i ++ )
{
qtab[table[0+8*i]] *= 90 ;
qtab[table[4+8*i]] *= 90 ;
qtab[table[2+8*i]] *= 118 ;
qtab[table[6+8*i]] *= 49 ;
qtab[table[5+8*i]] *= 71 ;
qtab[table[1+8*i]] *= 126 ;
qtab[table[7+8*i]] *= 25 ;
qtab[table[3+8*i]] *= 106 ;
}
for( i = 0 ; i < 64 ; i++ ) {
qtab[i] >>= 6 ;
}
| private int | HuffmanValue(int[] table, int[] temp, int[] index, java.io.InputStream in)
int code, input ,mask=0xFFFF;
if(index[0]<8){
temp[0] <<= 8;
input = get8(in);
if(input==0xFF){
marker=get8(in);
if(marker!=0) marker_index=9;
}
temp[0] |= input;
} else index[0] -= 8;
code=table[temp[0] >> index[0]];
if((code&MSB)!=0){
if(marker_index!=0){ marker_index=0; return 0xFF00|marker;}
temp[0] &= (mask >> (16-index[0]));
temp[0] <<= 8;
input = get8(in);
if(input==0xFF){
marker=get8(in);
if(marker!=0) marker_index=9;
}
temp[0] |= input;
code=table[(code&0xFF)*256 + (temp[0] >> index[0])];
index[0]+=8;
}
index[0] += 8 - (code>>8);
if(index[0]<0) error("index="+index[0]+" temp="+temp[0]+" code="+code+" in HuffmanValue()");
if(index[0] < marker_index){ marker_index=0; return 0xFF00|marker;}
temp[0] &= ( mask >> (16-index[0]) );
return code&0xFF;
| private void | ScaleIDCT(int[] matrix)
int p[][] = new int[8][8] ;
int t0 , t1 , t2 , t3, i ;
int src0, src1, src2, src3, src4, src5, src6, src7;
int det0, det1, det2, det3, det4, det5, det6, det7;
int mindex=0;
for( i = 0 ; i < 8 ; i++ )
{
src0 = IDCT_Source[0*8+i] ;
src1 = IDCT_Source[1*8+i] ;
src2 = IDCT_Source[2*8+i] - IDCT_Source[3*8+i] ;
src3 = IDCT_Source[3*8+i] + IDCT_Source[2*8+i] ;
src4 = IDCT_Source[4*8+i] - IDCT_Source[7*8+i] ;
src6 = IDCT_Source[5*8+i] - IDCT_Source[6*8+i] ;
t0 = IDCT_Source[5*8+i] + IDCT_Source[6*8+i] ;
t1 = IDCT_Source[4*8+i] + IDCT_Source[7*8+i] ;
src5 = t0 - t1 ;
src7 = t0 + t1 ;
//
det4 =-src4 * 480 - src6 * 192 ;
det5 = src5 * 384 ;
det6 = src6 * 480 - src4 * 192 ;
det7 = src7 * 256 ;
t0 = src0 * 256 ;
t1 = src1 * 256 ;
t2 = src2 * 384 ;
t3 = src3 * 256 ;
det3 = t3 ;
det0 = t0 + t1 ;
det1 = t0 - t1 ;
det2 = t2 - t3 ;
//
src0 = det0 + det3 ;
src1 = det1 + det2 ;
src2 = det1 - det2 ;
src3 = det0 - det3 ;
src4 = det6 - det4 - det5 - det7 ;
src5 = det5 - det6 + det7 ;
src6 = det6 - det7 ;
src7 = det7 ;
//
p[0][i] = ( src0 + src7 +(1<<12))>>13 ;
p[1][i] = ( src1 + src6 +(1<<12))>>13 ;
p[2][i] = ( src2 + src5 +(1<<12))>>13 ;
p[3][i] = ( src3 + src4 +(1<<12))>>13 ;
p[4][i] = ( src3 - src4 +(1<<12))>>13 ;
p[5][i] = ( src2 - src5 +(1<<12))>>13 ;
p[6][i] = ( src1 - src6 +(1<<12))>>13 ;
p[7][i] = ( src0 - src7 +(1<<12))>>13 ;
}
//
for( i = 0 ; i < 8 ; i++ )
{
src0 = p[i][0] ;
src1 = p[i][1] ;
src2 = p[i][2] - p[i][3] ;
src3 = p[i][3] + p[i][2] ;
src4 = p[i][4] - p[i][7] ;
src6 = p[i][5] - p[i][6] ;
t0 = p[i][5] + p[i][6] ;
t1 = p[i][4] + p[i][7] ;
src5 = t0 - t1 ;
src7 = t0 + t1 ;
//
det4 =-src4 * 480 - src6 * 192 ;
det5 = src5 * 384 ;
det6 = src6 * 480 - src4 * 192 ;
det7 = src7 * 256 ;
t0 = src0 * 256 ;
t1 = src1 * 256 ;
t2 = src2 * 384 ;
t3 = src3 * 256 ;
det3 = t3 ;
det0 = t0 + t1 ;
det1 = t0 - t1 ;
det2 = t2 - t3 ;
//
src0 = det0 + det3 ;
src1 = det1 + det2 ;
src2 = det1 - det2 ;
src3 = det0 - det3 ;
src4 = det6 - det4 - det5 - det7 ;
src5 = det5 - det6 + det7 ;
src6 = det6 - det7 ;
src7 = det7 ;
//
matrix[mindex++] = ( src0 + src7 +(1<<12))>>13 ;
matrix[mindex++] = ( src1 + src6 +(1<<12))>>13 ;
matrix[mindex++] = ( src2 + src5 +(1<<12))>>13 ;
matrix[mindex++] = ( src3 + src4 +(1<<12))>>13 ;
matrix[mindex++] = ( src3 - src4 +(1<<12))>>13 ;
matrix[mindex++] = ( src2 - src5 +(1<<12))>>13 ;
matrix[mindex++] = ( src1 - src6 +(1<<12))>>13 ;
matrix[mindex++] = ( src0 - src7 +(1<<12))>>13 ;
}
| private int | YUV_to_BGR(int Y, int u, int v)Decode MCU
DU[i][j][8][8] the j-th data unit of component i.
if(Y<0) Y=0;
int tempB,tempG,tempR;
tempB=Y+((116130*u)>>16);
if(tempB<0) tempB=0;
else if(tempB>255) tempB=255;
tempG=Y-((22554*u+46802*v)>>16);
if(tempG<0) tempG=0;
else if(tempG>255) tempG=255;
tempR=Y+((91881*v)>>16);
if(tempR<0) tempR=0;
else if(tempR>255) tempR=255;
return 0xff000000 | ((tempR<<16) + (tempG<<8) + tempB);
| public void | decode(java.io.InputStream in, PTViewer.JPEGDecoder$PixelArray out)
int current,m,i,scan_num=0,RST_num;
int PRED[] = new int[10];
if(in==null) return;
x=0; y=0; yp=0; num=0;
current=get16(in);
if(current!=0xFFD8){ //SOI
error("Not a JPEG file");
return;
}
current=get16(in);
while(current>>4 != 0x0FFC){ //SOF 0~15
switch(current){
case 0xFFC4: //DHT
HT.get(in); break;
case 0xFFCC: //DAC
error("Program doesn't support arithmetic coding. (format error)");
return;
case 0xFFDB:
QT.get(in); break;
case 0xFFDD:
Ri = readNumber(in); break;
case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3:
case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7:
case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB:
case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF:
readApp(in); break;
case 0xFFFE:
readComment(in); break;
default:
if(current>>8 != 0xFF){
error("ERROR: format error! (decode)");
}
}
current=get16(in);
}
if(current<0xFFC0 || current >0xFFC7){
error("ERROR: could not handle arithmetic code!");
}
FH.get(in,current);
current=get16(in);
// pix = new int[FH.X * FH.Y];
out.setSize(FH.X, FH.Y);
do{
while(current != 0x0FFDA){ //SOS
switch(current){
case 0xFFC4: //DHT
HT.get(in); break;
case 0xFFCC: //DAC
error("Program doesn't support arithmetic coding. (format error)");
case 0xFFDB:
QT.get(in); break;
case 0xFFDD:
Ri = readNumber(in); break;
case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3:
case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7:
case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB:
case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF:
readApp(in); break;
case 0xFFFE:
readComment(in); break;
default:
if(current>>8 != 0xFF){
error("ERROR: format error! (Parser.decode)");
}
}
current=get16(in);
}
SH.get(in);
nComp=(int)SH.Ns;
for(i=0; i<nComp; i++){
int CompN=SH.Comp[i].Cs;
qTab[i]=QT.Q[FH.Comp[CompN].Tq];
nBlock[i]=FH.Comp[CompN].V * FH.Comp[CompN].H;
dcTab[i]=HuffTab[SH.Comp[i].Td][0];
acTab[i]=HuffTab[SH.Comp[i].Ta][1];
}
YH=FH.Comp[1].H; YV=FH.Comp[1].V;
Xsize=FH.X; Ysize=FH.Y;
scan_num++;
m=0;
for(RST_num=0;;RST_num++){ //Decode one scan
int MCU_num;
int temp[] = new int[1]; // to store remainded bits
int index[] = new int[1];
temp[0]=0;
index[0]=0;
for(i=0; i<10; i++) PRED[i]=0;
if(Ri==0){
current=decode_MCU(in,PRED,temp,index);
// 0: correctly decoded
// otherwise: MARKER
while(current==0){
m++;
output(out);
current=decode_MCU(in,PRED,temp,index);
}
break; //current=MARKER
}
for(MCU_num=0; MCU_num<Ri; MCU_num++){
current=decode_MCU(in,PRED,temp,index);
output(out);
//fprintf(show,"%i ",MCU_num);
if(current!=0) break;
}
if(current==0){
if(marker_index!=0){
current=(0xFF00|marker);
marker_index=0;
}else current=get16(in);
}
if(current>=0xFFD0 && current<=0xFFD7){
}else break; //current=MARKER
}
if(current==0xFFDC && scan_num==1){ //DNL
readNumber(in);
current=get16(in);
}
}while(current!=0xFFD9);
| private int | decode_MCU(java.io.InputStream in, int[] PrevDC, int[] temp, int[] index)
int value,actab[],dctab[];
int qtab[],Cs;
for(Cs=0; Cs<nComp; Cs++){
qtab=qTab[Cs]; actab=acTab[Cs]; dctab=dcTab[Cs];
for(int i=0 ; i<nBlock[Cs]; i++){
for(int k=0; k<IDCT_Source.length; k++)
IDCT_Source[k]=0;
value = HuffmanValue(dctab,temp,index,in);
if(value>=0xFF00)
return value;
PrevDC[Cs] = IDCT_Source[0] = PrevDC[Cs] + getn(in,value,temp,index);
IDCT_Source[0] *= qtab[0];
for(int j=1 ; j<64 ; j++){
value = HuffmanValue(actab,temp,index,in);
if(value>=0xFF00)
return value;
j += (value>>4) ;
if( (value&0x0F) == 0){
if( (value>>4) == 0) break ;
}else {
IDCT_Source[IDCT_P[j]] =
getn(in,value&0x0F,temp,index)*qtab[j];
}
}
ScaleIDCT(DU[Cs][i]) ;
}
}
return 0;
| private void | error(java.lang.String message)
throw new Exception(message);
| private final int | get16(java.io.InputStream in)
int temp;
try{
temp = in.read();
temp<<=8;
return temp | in.read();
}catch(IOException e){
error("get16() read error: "+e.toString());
return -1;
}
| private final int | get8(java.io.InputStream in)
try{
return in.read();
}catch(IOException e){
error("get8() read error: "+e.toString());
return -1;
}
| private int | getn(java.io.InputStream in, int n, int[] temp, int[] index)
int result, one=1, n_one=-1;
int mask=0xFFFF, input;
if(n==0) return 0;
index[0] -= n;
if(index[0]>=0){
if(index[0] < marker_index){
marker_index=0;
return (0xFF00|marker) << 8;
}
result = temp[0]>>index[0];
temp[0] &= ( mask >> (16-index[0]) );
}else{
temp[0] <<= 8;
input = get8(in);
if(input==0xFF){
marker=get8(in);
if(marker!=0) marker_index=9;
}
temp[0] |= input;
index[0] += 8;
if(index[0] < 0){
if(marker_index!=0){
marker_index=0;
return (0xFF00|marker) << 8;
}
temp[0] <<= 8;
input = get8(in);
if(input==0xFF){
marker=get8(in);
if(marker!=0) marker_index=9;
}
temp[0] |= input;
index[0] += 8;
}
if(index[0]<0) error("index="+index[0]+" in getn()");
if(index[0]<marker_index){
marker_index=0;
return (0xFF00|marker) << 8;
}
result = temp[0]>>index[0];
temp[0] &= ( mask >> (16-index[0]) );
}
if( result < (one<<(n-1)) )
result += (n_one << n) + 1;
return result;
| private void | level_shift(int[] du, int P)
int i;
if(P==8){
for(i=0; i<64; i++)
du[i] += 128;
}else if(P==12){
for(i=0; i<64; i++)
du[i] += 2048;
}else
error("ERROR: Precision="+P);
| private void | output(PTViewer.JPEGDecoder$PixelArray out)
int temp_x, temp_8y, temp;
int k=0;
int DU10[], DU20[];
DU10=DU[1][0]; DU20=DU[2][0];
num++;
for(int i=0; i<YV; i++){
for(int j=0; j<YH; j++){
temp_8y=i*32;
temp_x=temp=j*4;
for(int l=0; l<64; l++){
if(x<Xsize && y<Ysize){
out.setPixel(x,y,
YUV_to_BGR(DU[0][k][l]+128,DU10[temp_8y+temp_x],DU20[temp_8y+temp_x]));
}
x++;
if( (x%YH)==0 ) temp_x++;
if( (x%8)==0 ){
y++; x-=8;
temp_x = temp;
if( (y%YV)==0 ) temp_8y+=8;
}
}
k++;
x+=8;
y-=8;
}
x -= YH*8;
y += 8;
}
x += YH*8;
y -= YV*8;
if(x>=Xsize){
y+=YV*8;
x=0;
}
yp = y;
| public int | progress()
if(height==0)
return 0;
if(yp>height) return 100;
return yp*100/height;
| private int | readApp(java.io.InputStream in)
int Lp;
int count=0;
Lp=get16(in); count+=2;
while(count<Lp){
get8(in); count++;
}
return Lp;
| private java.lang.String | readComment(java.io.InputStream in)
int Lc, count=0, i;
StringBuffer sb = new StringBuffer();
Lc=get16(in); count+=2;
for(i=0; count<Lc; i++){
sb.append((char)get8(in)); count++;
}
return sb.toString();
| private int | readNumber(java.io.InputStream in)
int Ld;
Ld=get16(in);
if(Ld!=4){
error("ERROR: Define number format error [Ld!=4]");
}
return get16(in);
|
|