/* 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, 1, 5, 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,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
};
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 0...100
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=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;
}
//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==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;
}
/******************************************************************
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) == 0) break ;
}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==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);
}
}
|