FileDocCategorySizeDatePackage
JPEGDecoder.javaAPI DocExample33411Wed May 19 14:11:12 BST 2004PTViewer

JPEGDecoder

public 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[]
HuffTab
Huffman 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
Constructors Summary
Methods Summary
private voidBuild_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 voidEnhanceQuantizationTable(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 intHuffmanValue(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 voidScaleIDCT(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 intYUV_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 voiddecode(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 intdecode_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 voiderror(java.lang.String message)


         
         throw new Exception(message);
    
private final intget16(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 intget8(java.io.InputStream in)

       try{
          return in.read();
       }catch(IOException e){
          error("get8() read error: "+e.toString());
          return -1;
       }
    
private intgetn(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 voidlevel_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 voidoutput(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 intprogress()

         if(height==0)
             return 0;
         if(yp>height) return 100;
         return yp*100/height;
    
private intreadApp(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.StringreadComment(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 intreadNumber(java.io.InputStream in)

         int Ld;
         Ld=get16(in);
         if(Ld!=4){
               error("ERROR: Define number format error [Ld!=4]");
         }
         return get16(in);