作者:hunhun1981
出自:http://blog.csdn.net/hunhun1981/
最近的项目提出一个直接读取手机中图片的需求。
但是一般手机上J2ME能使用的内存并不大,而拍出来的图却不小。我在多个真机上测试,结果都是OutOfMemory。只有一些高端机能够承受。
好在,我们的项目是一个对图像进行解码的算法。目的是从图片中获取像素颜色信息。于是我想到了使用流读取图片,直接对流中的数据进行解码并获取信息,无需构造图片对象。
于是,我从网上找到了这个JPEG解码器(PNG的以后再说吧),准备对它进行改造,然后从流中获取对我们算法的关键数据。
下面是JEPGDecoder的源代码,仅供大家学习和参考。并尊重原作者的劳动成果。
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)