📄 jpegdecoder.cpp
字号:
#include "stdafx.h"
#include "JpegDecoder.h"
#pragma warning ( disable : 4996)
// 标记符
#define SOI 0xD8
#define EOI 0xD9
#define APP0 0xE0
#define SOF 0xC0
#define DQT 0xDB
#define DHT 0xC4
#define SOS 0xDA
#define DRI 0xDD
#define COM 0xFE
#define BYTE_p(i) bp=buf[(i)++]
#define WORD_p(i) wp=(((WORD)(buf[(i)]))<<8) + buf[(i)+1]; (i)+=2
#define RIGHT_SHIFT(x,shft) \
((shift_temp = (x)) < 0 ? \
(shift_temp >> (shft)) | ((~(0L)) << (32-(shft))) : \
(shift_temp >> (shft)))
#define DESCALE(x,n) RIGHT_SHIFT((x) + (1L << ((n)-1)), n)
#define RANGE_MASK 1023L
typedef void (JpegDecoder::*decode_MCU_func)(DWORD);
// Z字形排列后的DCT系数序号矩阵
static BYTE zigzag[64]={ 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 };
// 数值幅度编码表数组
static SWORD neg_pow2[17] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
static DWORD start_neg_pow2 = (DWORD)neg_pow2;
// 霍夫曼解码时使用的实际值
static DWORD wordval;
#define exit_func(err) { strcpy(error_string, err); return 0;}//错误提示信息
#ifdef _MSC_VER
WORD lookKbits(BYTE k)
{
_asm {
mov dl, k
mov cl, 16
sub cl, dl
mov eax, [wordval]
shr eax, cl
}
}
WORD WORD_hi_lo(BYTE byte_high,BYTE byte_low)
{
_asm {
mov ah,byte_high
mov al,byte_low
}
}
SWORD get_svalue(BYTE k)
{
_asm {
xor ecx, ecx
mov cl,k
mov eax,[wordval]
shl eax,cl
shr eax, 16
dec cl
bt eax,ecx
jc end_macro
signed_value:inc cl
mov ebx,[start_neg_pow2]
add ax,word ptr [ebx+ecx*2]
end_macro:
}
}
#endif
#ifdef __WATCOMC__
WORD lookKbits(BYTE k);
#pragma aux lookKbits=\
"mov eax,[wordval]"\
"mov cl, 16"\
"sub cl, dl"\
"shr eax, cl"\
parm [dl] \
value [ax] \
modify [eax cl];
WORD WORD_hi_lo(BYTE byte_high,BYTE BYTE_low);
#pragma aux WORD_hi_lo=\
parm [ah] [al]\
value [ax] \
modify [ax];
SWORD get_svalue(BYTE k);
#pragma aux get_svalue=\
"xor ecx, ecx"\
"mov cl, al"\
"mov eax,[wordval]"\
"shl eax, cl"\
"shr eax, 16"\
"dec cl"\
"bt eax,ecx"\
"jc end_macro"\
"signed_value:inc cl"\
"mov ebx,[start_neg_pow2]"\
"add ax,word ptr [ebx+ecx*2]"\
"end_macro:"\
parm [al]\
modify [eax ebx ecx]\
value [ax];
#endif
/*************************************************************************** 构造函数
**************************************************************************/
JpegDecoder::JpegDecoder(FILE* f)
{
d_k = 0;
LoadJPEGHeader(f);
DecodeJPEGImage();
}
/*************************************************************************** 析构函数, 释放资源
**************************************************************************/
JpegDecoder::~JpegDecoder(void)
{
free(buf);
free(tempTable);
for (int i = 0; i <=3; i++)free(QT[i]);
}
/*************************************************************************** 载入JPEG文件头
**************************************************************************/
bool JpegDecoder::LoadJPEGHeader(FILE* fp)
{
DWORD length_of_file;
BYTE vers,units;
WORD Xdensity,Ydensity,Xthumbnail,Ythumbnail;
WORD length;
float *qtable;
DWORD old_byte_pos;
Huffman_table *htable;
long j;
BYTE precision,comp_id,nr_components;
BYTE QT_info,HT_info;
BYTE SOS_found,SOF_found;
//读取JPEG文件,并为其分配空间
length_of_file=GetFileSize(fp);
buf=(BYTE *)malloc(length_of_file+4);
if (buf==NULL) exit_func("Not enough memory for loading file");
fread(buf,length_of_file,1,fp);
//判断文件是否是一个合法的JPEG文件
if ((buf[0]!=0xFF)||(buf[1]!=SOI)) exit_func("Not a JPG file ?\n");
if ((buf[2]!=0xFF)||(buf[3]!=APP0)) exit_func("Invalid JPG file.");
if ( (buf[6]!='J')||(buf[7]!='F')||(buf[8]!='I')||(buf[9]!='F')||
(buf[10]!=0) ) exit_func("Invalid JPG file.");
//初始化
InitJPGDecoding();
byte_pos=11;
//获取JPEG文件的版本并判断是否支持该版本
BYTE_p(byte_pos);vers=bp;
if (vers!=1) exit_func("JFIF version not supported");
BYTE_p(byte_pos);
BYTE_p(byte_pos); units=bp;
WORD_p(byte_pos); Xdensity=wp; WORD_p(byte_pos); Ydensity=wp;
//是否能够处理缩略图
BYTE_p(byte_pos);Xthumbnail=bp;BYTE_p(byte_pos);Ythumbnail=bp;
if ((Xthumbnail!=0)||(Ythumbnail!=0))
exit_func(" Cannot process JFIF thumbnailed files\n");
//开始解码处理, 寻找扫描线开始的位置, 以确定压缩数据的位置
SOS_found=0; SOF_found=0; Restart_markers=0;
while ((byte_pos<length_of_file)&&!SOS_found)
{
BYTE_p(byte_pos);
if (bp!=0xFF) continue;
// 找到一个标记符
BYTE_p(byte_pos);
switch(bp)
{
case DQT: WORD_p(byte_pos); length=wp;
for (j=0;j<wp-2;)
{
old_byte_pos=byte_pos;
BYTE_p(byte_pos); QT_info=bp;
if ((QT_info>>4)!=0)
exit_func("16 bit quantization table not supported");
qtable=QT[QT_info&0xF];
LoadQuantTable(qtable);//载入量化表
j+=byte_pos-old_byte_pos;
}break;
case DHT: WORD_p(byte_pos); length=wp;
for (j=0;j<wp-2;)
{
old_byte_pos=byte_pos;
BYTE_p(byte_pos); HT_info=bp;
if ((HT_info&0x10)!=0) htable=&HTAC[HT_info&0xF];
else htable=&HTDC[HT_info&0xF];
LoadHuffmanTable(htable);//载入霍夫曼表
j+=byte_pos-old_byte_pos;
}break;
case COM: WORD_p(byte_pos); length=wp;
byte_pos+=wp-2;
break;
case DRI: Restart_markers=1;
WORD_p(byte_pos); length=wp;
WORD_p(byte_pos); MCU_restart=wp;
if (MCU_restart==0) Restart_markers=0;
break;
case SOF: WORD_p(byte_pos); length=wp; //该值应为 8+3*3=17
BYTE_p(byte_pos); precision=bp;
if (precision!=8) exit_func("Only 8 bit precision supported");
WORD_p(byte_pos); height=wp; WORD_p(byte_pos); width=wp;
BYTE_p(byte_pos); nr_components=bp;
if (nr_components!=3) exit_func("Only truecolor JPGS supported");
for (j=1;j<=3;j++)
{
BYTE_p(byte_pos); comp_id=bp;
if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr format supported");
switch (comp_id)
{
case 1: // Y
BYTE_p(byte_pos); YH=bp>>4;YV=bp&0xF;
BYTE_p(byte_pos); YQ_nr=bp;
break;
case 2: // Cb
BYTE_p(byte_pos); CbH=bp>>4;CbV=bp&0xF;
BYTE_p(byte_pos); CbQ_nr=bp;
break;
case 3: // Cr
BYTE_p(byte_pos); CrH=bp>>4;CrV=bp&0xF;
BYTE_p(byte_pos); CrQ_nr=bp;
break;
}
}
SOF_found=1;break;
case SOS: WORD_p(byte_pos); length=wp; //该值应为 = 6+3*2=12
BYTE_p(byte_pos); nr_components=bp;
if (nr_components!=3) exit_func("Invalid SOS marker");
for (j=1;j<=3;j++)
{
BYTE_p(byte_pos); comp_id=bp;
if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr supported");
switch (comp_id)
{
case 1: // Y
BYTE_p(byte_pos); YDC_nr=bp>>4;YAC_nr=bp&0xF;
break;
case 2: // Cb
BYTE_p(byte_pos); CbDC_nr=bp>>4;CbAC_nr=bp&0xF;
break;
case 3: // Cr
BYTE_p(byte_pos); CrDC_nr=bp>>4;CrAC_nr=bp&0xF;
break;
}
}
BYTE_p(byte_pos); BYTE_p(byte_pos); BYTE_p(byte_pos);
SOS_found=1;
break;
//连续出现0xFF时忽略不做处理
case 0xFF:
break;
//跳过无法识别的标记符
default: WORD_p(byte_pos); length=wp;
byte_pos+=wp-2;
break;
}
}
//若为非法或无效的文件, 则提示无法处理并返回
if (!SOS_found) exit_func("Invalid JPG file. No SOS marker found.");
if (!SOF_found) exit_func("Progressive JPEGs not supported");
if ((CbH>YH)||(CrH>YH)) exit_func("Vertical sampling factor for Y should be >= sampling factor for Cb,Cr");
if ((CbV>YV)||(CrV>YV)) exit_func("Horizontal sampling factor for Y should be >= sampling factor for Cb,Cr");
if ((CbH>=2)||(CbV>=2)) exit_func("Cb sampling factors should be = 1");
if ((CrV>=2)||(CrV>=2)) exit_func("Cr sampling factors should be = 1");
Hmax=YH,Vmax=YV;
if ( width%(Hmax*8)==0) X_round=width; // X_round = Multiple of Hmax*8
else X_round=(width/(Hmax*8)+1)*(Hmax*8);
if ( height%(Vmax*8)==0) Y_round=height; // Y_round = Multiple of Vmax*8
else Y_round=(height/(Vmax*8)+1)*(Vmax*8);
//确定文件合法后, 为像素数组分配空间
im_buffer=(BYTE *)malloc(X_round*Y_round*4);
return true;
}
/*************************************************************************** 为sample_range_limit表分配存储空间,并进行填充
**************************************************************************/
void JpegDecoder::PrepareRangeLimitTable()
{
int j;
rlimit_table = (BYTE *)malloc(5 * 256L + 128) ;
tempTable = rlimit_table;
memset((void *)rlimit_table,0,256);
rlimit_table += 256;
for (j = 0; j < 256; j++) rlimit_table[j] = j;
for (j = 256; j < 640; j++) rlimit_table[j] = 255;
memset((void *)(rlimit_table + 640),0,384);
for (j = 0; j < 128 ; j++) rlimit_table[j+1024] = j;
}
/*************************************************************************** 跳过k个比特
**************************************************************************/
void JpegDecoder::SkipKbits(BYTE k)
{
BYTE b_high,b_low;
d_k+=k;
if (d_k>=16)
{
d_k-=16;
w1=w2;
BYTE_p(byte_pos);
if (bp!=0xFF) b_high=bp;
else
{
if (buf[byte_pos]==0) byte_pos++;
else byte_pos--;
b_high=0xFF;
}
BYTE_p(byte_pos);
if (bp!=0xFF) b_low=bp;
else
{
if (buf[byte_pos]==0) byte_pos++;
else byte_pos--;
b_low=0xFF;
}
w2=WORD_hi_lo(b_high,b_low);
}
wordval = ((DWORD)(w1)<<16) + w2;
wordval <<= d_k;
wordval >>= 16;
}
/*************************************************************************** 返回k个比特
**************************************************************************/
SWORD JpegDecoder::GetKbits(BYTE k)
{
SWORD signed_wordvalue;
signed_wordvalue=get_svalue(k);
SkipKbits(k);
return signed_wordvalue;
}
/*************************************************************************** 计算mask[16]数组
**************************************************************************/
void JpegDecoder::CalculateMask()
{
BYTE k;
DWORD tmpdv;
for (k=0;k<=16;k++) { tmpdv=0x10000;mask[k]=(tmpdv>>k)-1;}
}
/*************************************************************************** 初始化量化表并为量化表分配存储空间
**************************************************************************/
void JpegDecoder::InitQT()
{
BYTE i;
for (i=0;i<=3;i++) QT[i]=(float *)malloc(sizeof(float)*64);
}
/*************************************************************************** 载入量化表
**************************************************************************/
void JpegDecoder::LoadQuantTable(float *quant_table)
{
float scalefactor[8]={1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
BYTE j,row,col;
//从JPEG文件中载入量化表系数, 并按Z字形排序
for (j=0;j<=63;j++) quant_table[j]=buf[byte_pos+zigzag[j]];
j=0;
for (row=0;row<=7;row++)
for (col=0;col<=7;col++) {
quant_table[j]*=scalefactor[row]*scalefactor[col];
j++;
}
byte_pos+=64;
}
/*************************************************************************** 载入霍夫曼表
**************************************************************************/
void JpegDecoder::LoadHuffmanTable(Huffman_table *HT)
{
BYTE k,j;
DWORD code;
for (j=1;j<=16;j++) {
BYTE_p(byte_pos);
HT->Length[j]=bp;
}
for (k=1;k<=16;k++)
for (j=0;j<HT->Length[k];j++) {
BYTE_p(byte_pos);
HT->V[WORD_hi_lo(k,j)]=bp;
}
code=0;
for (k=1;k<=16;k++) {
HT->minor_code[k] = (WORD)code;
for (j=1;j<=HT->Length[k];j++) code++;
HT->major_code[k]=(WORD)(code-1);
code*=2;
if (HT->Length[k]==0) {
HT->minor_code[k]=0xFFFF;
HT->major_code[k]=0;
}
}
}
/*************************************************************************** 处理8×8子块,每个8×8子块是一个独立的数据单元
* 数据通过霍夫曼解码过程而被解压缩,最后数组被从Z字形排列方式中还原
* 计算结果DCT_coeff是一个容量为64的 DCT 系数数组
**************************************************************************/
void JpegDecoder::ProcessHuffmanDataUnit(BYTE DC_nr, BYTE AC_nr,SWORD *previous_DC)
{
BYTE nr,k,j,EOB_found;
register WORD tmp_Hcode;
BYTE size_val,count_0;
// min_code[k]表示长度为k的最小编码, maj_code[k]表示长度为k的最大编码
WORD *min_code,*maj_code;
WORD *max_val, *min_val;
BYTE *huff_values;
SWORD DCT_tcoeff[64];
BYTE byte_temp;
// 开始霍夫曼解码,首先进行DC系数的解码
min_code=HTDC[DC_nr].minor_code;
maj_code=HTDC[DC_nr].major_code;
huff_values=HTDC[DC_nr].V;
for (nr = 0; nr < 64 ; nr++) DCT_tcoeff[nr] = 0; //初始化 DCT_tcoeff
nr=0;// DC 系数
min_val = &min_code[1]; max_val = &maj_code[1];
for (k=1;k<=16;k++)
{
tmp_Hcode=lookKbits(k);
if ( (tmp_Hcode<=*max_val)&&(tmp_Hcode>=*min_val) )
{
//查找一个有效的霍夫曼编码
SkipKbits(k);
size_val=huff_values[WORD_hi_lo(k,(BYTE)(tmp_Hcode-*min_val))];
if (size_val==0) DCT_tcoeff[0]=*previous_DC;
else
{
DCT_tcoeff[0]=*previous_DC+GetKbits(size_val);
*previous_DC=DCT_tcoeff[0];
}
break;
}
min_val++; max_val++;
}
// AC系数解码
min_code=HTAC[AC_nr].minor_code;
maj_code=HTAC[AC_nr].major_code;
huff_values=HTAC[AC_nr].V;
nr=1; // AC 系数
EOB_found=0;
while ( (nr<=63)&&(!EOB_found) )
{
max_val = &maj_code[1]; min_val =&min_code[1];
for (k=1;k<=16;k++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -