J2ME版JPEG解码器

 

Java版使用原生代码编写的JPEG解码器,适用于J2ME平台。要求手机满足CLDC1.0、MIDP1.0即可。

虽然部分MIDP2.0手机已经原生支持JPEG了,但是仍有大多数手机不支持JPEG,此解码器解决了燃眉之急。


 

/* JPEGDecoder -- pure Java decoder for JPEG images
   Copyright (C) 2004 - Helmut Dersch  der@fh-furtwangen.de
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
*/



/////////////////////////////////////////////////////////////////////////

/* This decoder is based on C++-code for a Viewer ("JViewer") written and
   published by Bee-Chung Chen (
http://www.cs.wisc.edu/~beechung/home/coding/index.html).
   It is intended to be used with limited Java Runtimes not inluding
   JPEG decompression like the Java Microedition (J2ME) or gcj etc.

   Usage:
   ======
   
   (1) Implement the Interface "JPEGDecoder.PixelArray" with methods
       setSize(int width, int height) and setPixel(int x, int y, int argb).
       On a standard PC this could be just an Integer array (see example
       below), on a mobile device something more fancyful using RecordStores
       may be needed for large images (e.g. see my Panorama viewer 
       "PTViewerME" for PDAs).

   (2) Instantiate JPECDecoder: JPEGDecoder j = new JPEGDecoder();

   (3) Supply an InputStream in connecting to the image file
       and a PixelArray p, and start decoding:  j.decode(in,p);

   (4) Progress can be monitored by observing
       0 <= j.progress() <= 100

   (5) If space is scarce, destroy the decoder: j=null; System.gc();

   This is an example using standard JAVA (J2SE)     

   Example:
   ========

   // Simple JPEG-viewer using the pure JAVA JPEGDecoder
   // To run the viewer type "java Bild Filename"

   import java.awt.*;

   class Bild extends Frame implements Runnable, JPEGDecoder.PixelArray{
        Image im=null;
        Thread load;
        String file;
        JPEGDecoder j=null;

        // Implementation of PixelArray 

        int[] pix;
        int width,height;

        public void setSize(int width, int height){
            this.width = width;
            this.height = height;
            pix = new int[width*height];
        }

        public void setPixel(int x, int y, int argb){
            pix[x+y*width]=argb;
        }
        
        // Image viewer

    public static void main(String args[]){
            new Bild(args[0]);
    }

    public Bild(String s){
            file = s;
            j = new JPEGDecoder();
            load = new Thread(this);
            load.start();
         this.setTitle("Bild:" + s);
            this.resize(300,200);
        this.show();
            while(im == null){
               try{
                  Thread.sleep(1000);
               }catch(Exception e){}
               repaint();
            }
       }

       public void run(){
            try{
                FileInputStream in = new FileInputStream(file);                
                j.decode(in,this);
                in.close();
                MemoryImageSource mi = new MemoryImageSource(width,
                          height,
                          pix,
                          0,
                          width);
                im = createImage(mi);
                repaint();
            }catch(Exception e){
                System.out.println("Etwas ging schief: "+e);
            }    
    }

    public void paint(Graphics g){
                if(im != null){
                     g.drawImage(im,0,0,this);
                }else{
             g.drawString("Decodierung",40,50);
                     if(j!=null)
                          g.drawString("Progress:"+j.progress()+"%",40,70);
                }
    }
   }
     
   

--------------------------------------------------------------
*/


////////////////////////////////////////////////////////////////


package PTViewer;

import java.io.*;

public class JPEGDecoder{
    
private int height;     

    
// Private variables and constants
    private static final int  MSB = 0x80000000;
    
private static final int  MAX_HUFFMAN_SUBTREE = 50;   // max size = MAX_HUFFMAN_SUBTREE * 256
    private int nComp;                    //number of Components in a scan
    private int[] qTab[]  = new int[10][];//quantization table for the i-th Comp in a scan
    private int[] dcTab[] = new int[10][];//dc HuffTab for the i-th Comp in a scan
    private int[] acTab[] = new int[10][];//ac HuffTab for the i-th Comp in a scan
    private int nBlock[]  = new int[10];  //number of blocks in the i-th Comp in a scan
                                  
//                  i=0,  ,Ns-1
    private int YH,YV,Xsize,Ysize;
    
private int marker ;
    
private int marker_index=0;
    
private int Ri = 0// RestartInterval

    
private int DU[][][]= new int[10][4][64];   //at most 10 data units in a MCU
                       
//at most 4 data units in one component 

    
private int x=0, y=0, num=0, yp=0// the begin point of MCU

    
private int IDCT_Source[]=new int[64];
    
private final static int IDCT_P[] ={
       
0,   5,  40,  16,  45,   2,   7,  42,
      
21,  56,   8,  61,  18,  47,   1,   4,
      
41,  23,  58,  13,  32,  24,  37,  10,
      
63,  17,  44,   3,   6,  43,  20,  57,
      
15,  34,  29,  48,  53,  26,  39,   9,
      
60,  19,  46,  22,  59,  12,  33,  31,
      
50,  55,  25,  36,  11,  62,  14,  35,
      
28,  49,  52,  27,  38,  30,  51,  54    
    }
 ;
    
private final static int table[] = {
        
0,    15,    6,    14,    15,    27,    28
        
2,    4,    7,    13,    16,    26,    29,    42,
        
3,    8,    12,    17,    25,    30,    41,    43,
        
9,    11,    18,    24,    31,    40,    44,    53,
        
1019233239455254,
        
2022333846515560,
        
2134374750565961,
        
3536484957586263
    }
;



    
private FrameHeader       FH = new FrameHeader();
    
private ScanHeader        SH = new ScanHeader() ;
    
private QuantizationTable QT = new QuantizationTable();
    
private HuffmanTable      HT = new HuffmanTable();

    
private void error(String message) throws Exception{
         
throw new Exception(message);
    }


    
// Report progress in the range 0100
    public int progress(){
         
if(height==0)
             
return 0;
         
if(yp>height) return 100;
         
return yp*100/height;
    }


    
interface PixelArray{
        
public void setSize(int width, int height) throws Exception;
        
public void setPixel(int x, int y, int argb);
    }


    
class ComponentSpec{
       
int C,  //Component id
           H,  //Horizontal sampling factor
           V,  //Vertical  .
           Tq; //Quantization table destination selector
    }


    
class FrameHeader{
           
int SOF,  //Start of frame in different type
               Lf,   //Length
               P,    //Sample Precision (from the orignal image)
               Y,    //Number of lines
               X,    //Number of samples per line
               Nf;   //Number of component in the frame

           ComponentSpec Comp[];  
//Components  C H V Tq

           
public int get(InputStream in, int sof) throws Exception{
           
//get data from file stream in
           
//return 0 : correct       otherwise : error

               
int i, temp, count=0, c;
               SOF
=sof;
               Lf
=get16(in); count+=2;
               P
=get8(in);   count++;
               Y
=get16(in);  count+=2;
               height
=Y;
               X
=get16(in);  count+=2;
               
//width=X;
               Nf=get8(in);  count++;
               Comp 
= new ComponentSpec[Nf+1];
               
for(i=0; i<=Nf; i++){ Comp[i]= new ComponentSpec();}
               
for(i=1; i<=Nf; i++){                 
                   
if(count>Lf){
                       error(
"ERROR: frame format error");
                   }

                   c
=get8(in);          count++;
                   
if(c>=Lf){
                       error(
"ERROR: fram format error [c>=Lf]");
                   }

                   Comp[c].C
=c;
                   temp
=get8(in);       count++;
                   Comp[c].H
=temp>>4;
                   Comp[c].V
=temp&0x0F;
                   Comp[c].Tq
=get8(in); count++;
               }

               
if(count!=Lf){
                   error(
"ERROR: frame format error [Lf!=count]");
               }

               
return 1;
           }

    }


    
class ScanComponent{
           
int Cs,   //Scan component selector
               Td,   //DC table selector
               Ta;   //AC table selector
    }


    
class ScanHeader{
          
int Ls,  //length
               Ns,  //Number of components in the scan
               Ss,  //Start of spectral or predictor selection
               Se,  //End of spectral selection
               Ah,  
               Al;
    
          ScanComponent Comp[]; 
//Components Cs Td Ta
                                
// from [0] to [Ns-1]
          int get(InputStream in) throws Exception{
             
//get data from file stream in
             
//return 0 : correct       otherwise : error

             
int i,temp,count=0;
             Ls
=get16(in);   count+=2;
             Ns
=get8(in);    count++;
             Comp 
= new ScanComponent[Ns];
             
for(i=0; i<Ns; i++){
                 Comp[i] 
= new ScanComponent();
                 
if(count>Ls){
                     error(
"ERROR: scan header format error");
                 }

                 Comp[i].Cs
=get8(in); count++;
                 temp
=get8(in);       count++;
                 Comp[i].Td
=temp>>4;
                 Comp[i].Ta
=temp&0x0F;
             }

             Ss
=get8(in);    count++;
             Se
=get8(in);    count++;
             temp
=get8(in);  count++;
             Ah
=temp>>4;
             Al
=temp&0x0F;
             
if(count!=Ls){
                 error(
"ERROR: scan header format error [count!=Ns]");
             }

             
return 1;
          }

    }


    
class QuantizationTable{
          
int Lq,    //length
              Pq[]=new int[4], //Quantization precision 8 or 16
              Tq[]=new int[4]; //1: this table is presented
          int Q[][]=new int[4][64]; //Tables

          
public QuantizationTable(){
              Tq[
0]=0; Tq[1]=0; Tq[2]=0; Tq[3]=0;
          }


          
int get(InputStream in) throws Exception{
              
//get data from file stream in
              
//return 0 : correct       otherwise : error

              
int i,count=0, temp, t;
              Lq
=get16(in); count+=2;
              
while(count<Lq){
                 temp
=get8(in);  count++;
                 t
=temp&0x0F;
                 
if(t>3){
                     error(
"ERROR: Quantization table ID > 3");
                 }

                 Pq[t]
=temp>>4;
                 
if(Pq[t]==0) Pq[t]=8;
                 
else if(Pq[t]==1) Pq[t]=16;
                 
else{
                     error(
"ERROR: Quantization table precision error");
                 }

                 Tq[t]
=1;
                 
if(Pq[t]==8){
                     
for(i=0; i<64; i++){
                          
if(count>Lq){
                               error(
"ERROR: Quantization table format error");
                          }

                          Q[t][i]
=get8(in); count++;
                     }

                     EnhanceQuantizationTable(Q[t]);
                 }
else{
                     
for(i=0; i<64; i++){
                          
if(count>Lq){
                             error(
"ERROR: Quantization table format error");
                          }

                          Q[t][i]
=get16(in); count+=2;
                     }

                     EnhanceQuantizationTable(Q[t]);
                 }

             }

             
if(count!=Lq){
                  error(
"ERROR: Quantization table error [count!=Lq]");
             }

             
return 1;
          }

    }


    
class HuffmanTable{
          
int Lh,    //Length
              Tc[][]   = new int[4][2],   //1: this table is presented
              Th[]     = new int[4],      //1: this table is presented
              L[][][]  = new int[4][2][16],
              V[][][][]
= new int[4][2][16][200]; //tables

           
public HuffmanTable(){
              Tc[
0][0]=0; Tc[1][0]=0; Tc[2][0]=0; Tc[3][0]=0;
              Tc[
0][1]=0; Tc[1][1]=0; Tc[2][1]=0; Tc[3][1]=0;
              Th[
0]=0; Th[1]=0; Th[2]=0; Th[3]=0;
           }


           
int get(InputStream in) throws Exception{
              
//get data from file stream in
              
//return 0 : correct       otherwise : error

              
int i,j,temp,count=0,t,c;
              Lh
=get16(in);    count+=2;
              
while(count<Lh){
                 temp
=get8(in);  count++;
                 t
=temp&0x0F;
                 
if(t>3){
                     error(
"ERROR: Huffman table ID > 3");
                 }

                 c
=temp>>4;
                 
if(c>2){
                     error(
"ERROR: Huffman table [Table class > 2 ]");
                 }

                 Th[t]
=1; Tc[t][c]=1;
                 
for(i=0; i<16; i++){
                     L[t][c][i]
=get8(in);  count++;
                 }

                 
for(i=0; i<16; i++)
                     
for(j=0; j<L[t][c][i]; j++){
                         
if(count>Lh){
                             error(
"ERROR: Huffman table format error [count>Lh]");
                         }

                         V[t][c][i][j]
=get8(in); count++;
                     }

                 }

                 
if(count!=Lh){
                     error(
"ERROR: Huffman table format error [count!=Lf]");
                 }

                 
for(i=0; i<4; i++)
                     
for(j=0; j<2; j++)
                         
if(Tc[i][j]!=0){
                             Build_HuffTab(HuffTab[i][j],L[i][j],V[i][j]);
                         }

                 
return 1;
           }

    }


    
private int readNumber(InputStream in) throws Exception{
         
int Ld;
         Ld
=get16(in);
         
if(Ld!=4){
               error(
"ERROR: Define number format error [Ld!=4]");
         }

         
return get16(in);
    }



    
private String readComment(InputStream in) throws Exception{
          
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 readApp(InputStream in) throws Exception{
          
int Lp;
          
int count=0;
          Lp
=get16(in);   count+=2;
          
while(count<Lp){
               get8(in); count
++;
          }

          
return Lp;
    }
       


    
private final int get8(InputStream in) throws Exception{
       
try{
          
return in.read();
       }
catch(IOException e){
          error(
"get8() read error: "+e.toString());
          
return -1;
       }

    }


    
//get  16-bit data 
    private final int get16(InputStream in) throws Exception{
        
int temp;
        
try{
           temp 
= in.read();
           temp
<<=8;
           
return temp | in.read();
       }
catch(IOException e){
          error(
"get16() read error: "+e.toString());
          
return -1;
       }

    }





/********************************************************************
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
*******************************************************************
*/

   
private int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];

/* 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.
*/


    
private void Build_HuffTab(int tab[],int L[],int V[][]) throws Exception{
        
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++;
            }

         }

      }

   }


 

/* HuffmanValue(): 
    return: Huffman Value of table
            0xFF?? if it receives a MARKER
    Parameter:  table   HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],)
                temp    temp storage for remainded bits
                index   index to bit of temp
                in      FILE pointer
    Effect:
        temp  store new remainded bits
        index change to new index
        in    change to new position
    NOTE:
      Initial by   temp=0; index=0;
    NOTE: (explain temp and index)
      temp: is always in the form at calling time or returning time
       |  byte 4  |  byte 3  |  byte 2  |  byte 1  |
       |     0    |     0    | 00000000 | 00000??? |  if not a MARKER
                                               ^index=3 (from 0 to 15)
                                               321    
    NOTE (marker and marker_index):
      If get a MARKER from 'in', marker=the low-byte of the MARKER
        and marker_index=9
      If marker_index=9 then index is always > 8, or HuffmanValue()
        will not be called.
*/




   
private int HuffmanValue(int table[],int temp[], int index[], InputStream in) throws Exception{
    
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=0return 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=0return 0xFF00|marker;}
    temp[
0&= ( mask >> (16-index[0]) );
    
return code&0xFF;
}


//get n-bit signed data from file 'in'
// temp is defined as before
// return signed integer or 0x00FF??00 if it sees a MARKER

    
private int getn(InputStream in, int n, int temp[], int index[]) throws Exception{
    
int result, one=1, n_one=-1;
    
int mask=0xFFFF, input;
    
if(n==0return 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;
}


/******************************************************************

  Decode MCU

    DU[i][j][8][8]     the j-th data unit of component i.

*****************************************************************
*/



  
private int YUV_to_BGR(int Y,int u,int v){
    
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);
}



/* output()
    x, y should be the starting point of MCU when calling output(..)
      it means output() should set x,y for the next MCU at the end.
*/



  
private void output(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;
}


  
private void level_shift(int du[], int P) throws Exception{
    
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);
}


/* decode_MCU()
     return 0       if correctly decoded
            0xFF??  if it sees a MARKER
*/





 
private int decode_MCU(InputStream in, int PrevDC[],
                         
int temp[], int index[]) throws Exception
{
        
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== 0break ;
            }
else {
            IDCT_Source[IDCT_P[j]] 
= 
                                  getn(in,value
&0x0F,temp,index)*qtab[j];
                }

        }

        ScaleIDCT(DU[Cs][i]) ;
        }

       }

       
return 0;
   }




// in-place operation
   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 ;
    }

}


// out-of-place operation
// input: IDCT_Source
// output: matrix
   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 ;
    }

   }
    



    
public void decode(InputStream in, PixelArray out) throws Exception{
        
int current,m,i,scan_num=0,RST_num;
        
int PRED[] = new int[10];
    
if(in==nullreturn;

        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 0xFFE0case 0xFFE1case 0xFFE2case 0xFFE3:
            
case 0xFFE4case 0xFFE5case 0xFFE6case 0xFFE7:
            
case 0xFFE8case 0xFFE9case 0xFFEAcase 0xFFEB:
            
case 0xFFECcase 0xFFEDcase 0xFFEEcase 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 0xFFE0case 0xFFE1case 0xFFE2case 0xFFE3:
                   
case 0xFFE4case 0xFFE5case 0xFFE6case 0xFFE7:
                   
case 0xFFE8case 0xFFE9case 0xFFEAcase 0xFFEB:
                   
case 0xFFECcase 0xFFEDcase 0xFFEEcase 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!=0break;
               }

               
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);
   }


}

posted @ 2008-08-25 21:47  musée  阅读(1230)  评论(0)    收藏  举报