📄 jpegdec.c
字号:
tmp7 = z11 + z13;
tmp11= (z11 - z13) * 1.414213562f;
z5 = (z10 + z12) * 1.847759065f; // 2*c2
tmp10 = 1.082392200f * z12 - z5; // 2*(c2-c6)
tmp12 = -2.613125930f * z10 + z5; // -2*(c2+c6)
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
// Final output stage: scale down by a factor of 8
outptr[0] = range_limit[(DESCALE((int) (tmp0 + tmp7), 3)) & 1023L];
outptr[7] = range_limit[(DESCALE((int) (tmp0 - tmp7), 3)) & 1023L];
outptr[1] = range_limit[(DESCALE((int) (tmp1 + tmp6), 3)) & 1023L];
outptr[6] = range_limit[(DESCALE((int) (tmp1 - tmp6), 3)) & 1023L];
outptr[2] = range_limit[(DESCALE((int) (tmp2 + tmp5), 3)) & 1023L];
outptr[5] = range_limit[(DESCALE((int) (tmp2 - tmp5), 3)) & 1023L];
outptr[4] = range_limit[(DESCALE((int) (tmp3 + tmp4), 3)) & 1023L];
outptr[3] = range_limit[(DESCALE((int) (tmp3 - tmp4), 3)) & 1023L];
wsptr+=8;//advance pointer to the next row
outptr+=8;
}
}
void precalculate_Cr_Cb_tables()
{
WORD k;
WORD Cr_v,Cb_v;
for (k=0;k<=255;k++) Cr_tab[k]=(SWORD)((k-128.0)*1.402);
for (k=0;k<=255;k++) Cb_tab[k]=(SWORD)((k-128.0)*1.772);
for (Cr_v=0;Cr_v<=255;Cr_v++)
for (Cb_v=0;Cb_v<=255;Cb_v++)
Cr_Cb_green_tab[((WORD)(Cr_v)<<8)+Cb_v]=(int)(-0.34414*(Cb_v-128.0)-0.71414*(Cr_v-128.0));
}
void convert_8x8_YCbCr_to_RGB(BYTE *Y, BYTE *Cb, BYTE *Cr, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Y,Cb,Cr
// Stim ca va fi apelata doar in cazul 1x1
{
DWORD x,y;
BYTE im_nr;
BYTE *Y_val = Y, *Cb_val = Cb, *Cr_val = Cr;
BYTE *ibuffer = im_buffer + im_loc;
for (y=0;y<8;y++)
{
im_nr=0;
for (x=0;x<8;x++)
{
ibuffer[im_nr++] = rlimit_table[*Y_val + Cb_tab[*Cb_val]]; //B
ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_Cb_green_tab[WORD_hi_lo(*Cr_val,*Cb_val)]]; //G
ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_tab[*Cr_val]]; // R
/*
// Monochrome display
im_buffer[im_nr++] = *Y_val;
im_buffer[im_nr++] = *Y_val;
im_buffer[im_nr++] = *Y_val;
*/
Y_val++; Cb_val++; Cr_val++; im_nr++;
}
ibuffer+=X_image_bytes;
}
}
void convert_8x8_YCbCr_to_RGB_tab(BYTE *Y, BYTE *Cb, BYTE *Cr, BYTE *tab, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Cb,Cr
{
DWORD x,y;
BYTE nr, im_nr;
BYTE Y_val,Cb_val,Cr_val;
BYTE *ibuffer = im_buffer + im_loc;
nr=0;
for (y=0;y<8;y++)
{
im_nr=0;
for (x=0;x<8;x++)
{
Y_val=Y[nr];
Cb_val=Cb[tab[nr]]; Cr_val=Cr[tab[nr]]; // reindexare folosind tabelul
// de supraesantionare precalculat
ibuffer[im_nr++] = rlimit_table[Y_val + Cb_tab[Cb_val]]; //B
ibuffer[im_nr++] = rlimit_table[Y_val + Cr_Cb_green_tab[WORD_hi_lo(Cr_val,Cb_val)]]; //G
ibuffer[im_nr++] = rlimit_table[Y_val + Cr_tab[Cr_val]]; // R
nr++; im_nr++;
}
ibuffer+=X_image_bytes;
}
}
void calculate_tabs()
{
BYTE tab_temp[256];
BYTE x,y;
// Tabelul de supraesantionare 16x16
for (y=0;y<16;y++)
for (x=0;x<16;x++)
tab_temp[y*16+x] = (y/YV)* 8 + x/YH;
// Din el derivam tabelele corespunzatoare celor 4 blocuri de 8x8 pixeli
for (y=0;y<8;y++)
{
for (x=0;x<8;x++)
tab_1[y*8+x]=tab_temp[y*16+x];
for (x=8;x<16;x++)
tab_2[y*8+(x-8)]=tab_temp[y*16+x];
}
for (y=8;y<16;y++)
{
for (x=0;x<8;x++)
tab_3[(y-8)*8+x]=tab_temp[y*16+x];
for (x=8;x<16;x++)
tab_4[(y-8)*8+(x-8)]=tab_temp[y*16+x];
}
}
int init_JPG_decoding()
{
byte_pos=0;
init_QT();
calculate_mask();
prepare_range_limit_table();
precalculate_Cr_Cb_tables();
return 1; //for future error check
}
DWORD filesize(FILE *fp)
{
DWORD pos;
DWORD pos_cur;
pos_cur=ftell(fp);
fseek(fp,0,SEEK_END);
pos=ftell(fp);
fseek(fp,pos_cur,SEEK_SET);
return pos;
}
int load_JPEG_header(FILE *fp, DWORD *X_image, DWORD *Y_image)
{
DWORD length_of_file;
BYTE vers,units;
WORD Xdensity,Ydensity,Xthumbnail,Ythumbnail;
WORD length;
float *qtable;
DWORD old_byte_pos;
Huffman_table *htable;
DWORD j;
BYTE precision,comp_id,nr_components;
BYTE QT_info,HT_info;
BYTE SOS_found,SOF_found;
length_of_file=filesize(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);
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.");
init_JPG_decoding();
byte_pos=11;
BYTE_p(byte_pos);vers=bp;
if (vers!=1) exit_func("JFIF version not supported");
BYTE_p(byte_pos); // vers_lo=bp;
BYTE_p(byte_pos); units=bp;
if (units!=0) //exit_func("JPG format not supported");
;// printf("units = %d\n", units);
WORD_p(byte_pos); Xdensity=wp; WORD_p(byte_pos); Ydensity=wp;
if ((Xdensity!=1)||(Ydensity!=1)) //exit_func("JPG format not supported");
; //{printf("X density = %d\n",Xdensity); printf("Y density = %d\n",Ydensity);}
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");
// Start decoding process
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;
// A marker was found
BYTE_p(byte_pos);
switch(bp)
{
case DQT: WORD_p(byte_pos); length=wp; // length of the DQT marker
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];
load_quant_table(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];
load_Huffman_table(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; //should be = 4
WORD_p(byte_pos); MCU_restart=wp;
if (MCU_restart==0) Restart_markers=0;
break;
case SOF: WORD_p(byte_pos); length=wp; //should be = 8+3*3=17
BYTE_p(byte_pos); precision=bp;
if (precision!=8) exit_func("Only 8 bit precision supported");
WORD_p(byte_pos); *Y_image=wp; WORD_p(byte_pos); *X_image=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; //should be = 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 format 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); // Skip 3 bytes
SOS_found=1;
break;
case 0xFF:
break; // do nothing for 0xFFFF, sequence of consecutive 0xFF are for
// filling purposes and should be ignored
default: WORD_p(byte_pos); length=wp;
byte_pos+=wp-2; //skip unknown marker
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");
// Restricting sampling factors for Y,Cb,Cr should give us 4 possible cases for sampling factors
// YHxYV,CbHxCbV,CrHxCrV: 2x2,1x1,1x1; 1x2,1x1,1x1; 2x1,1x1,1x1;
// and 1x1,1x1,1x1 = no upsampling needed
Hmax=YH,Vmax=YV;
if ( *X_image%(Hmax*8)==0) X_round=*X_image; // X_round = Multiple of Hmax*8
else X_round=(*X_image/(Hmax*8)+1)*(Hmax*8);
if ( *Y_image%(Vmax*8)==0) Y_round=*Y_image; // Y_round = Multiple of Vmax*8
else Y_round=(*Y_image/(Vmax*8)+1)*(Vmax*8);
im_buffer=(BYTE *)malloc(X_round*Y_round*4);
if (im_buffer==NULL) exit_func("Not enough memory for storing the JPEG image");
return 1;
}
void resync()
// byte_pos = pozitionat pe restart marker
{
byte_pos+=2;
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w1=WORD_hi_lo(bp, 0);
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w1+=bp;
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w2=WORD_hi_lo(bp, 0);
BYTE_p(byte_pos);
if (bp==0xFF) byte_pos++; // skip 00
w2+=bp;
wordval=w1; d_k=0; // Reinit bitstream decoding
DCY=0; DCCb=0; DCCr=0; // Init DC coefficients
}
void decode_MCU_1x1(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB(Y,Cb,Cr,im_loc,X_image_bytes,im_buffer);
}
void decode_MCU_2x1(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
}
void decode_MCU_2x2(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_3,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_4,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_3,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_4,Cb,Cr,tab_4,im_loc+y_inc_value+32,X_image_bytes,im_buffer);
}
void decode_MCU_1x2(DWORD im_loc)
{
// Y
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_1,YQ_nr);
process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
IDCT_transform(DCT_coeff,Y_2,YQ_nr);
// Cb
process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
IDCT_transform(DCT_coeff,Cb,CbQ_nr);
// Cr
process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
IDCT_transform(DCT_coeff,Cr,CrQ_nr);
convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
}
void decode_JPEG_image()
{
decode_MCU_func decode_MCU;
WORD x_mcu_cnt,y_mcu_cnt;
DWORD nr_mcu;
WORD X_MCU_nr,Y_MCU_nr; // Nr de MCU-uri
DWORD MCU_dim_x; //dimensiunea in bufferul imagine a unui MCU pe axa x
DWORD im_loc_inc; // = 7 * X_round * 4 sau 15*X_round*4;
DWORD im_loc; //locatia in bufferul imagine
byte_pos-=2;
resync();
y_inc_value = 32*X_round;
calculate_tabs(); // Calcul tabele de supraesantionare, tinand cont de YH si YV
if ((YH==1)&&(YV==1)) decode_MCU=decode_MCU_1x1;
else {
if (YH==2)
{
if (YV==2) decode_MCU=decode_MCU_2x2;
else decode_MCU=decode_MCU_2x1;
}
else decode_MCU=decode_MCU_1x2;
}
MCU_dim_x=Hmax*8*4;
Y_MCU_nr=Y_round/(Vmax*8); // nr of MCUs on Y axis
X_MCU_nr=X_round/(Hmax*8); // nr of MCUs on X axis
X_image_bytes=X_round*4; im_loc_inc = (Vmax*8-1) * X_image_bytes;
nr_mcu=0; im_loc=0; // memory location of the current MCU
for (y_mcu_cnt=0;y_mcu_cnt<Y_MCU_nr;y_mcu_cnt++)
{
for (x_mcu_cnt=0;x_mcu_cnt<X_MCU_nr;x_mcu_cnt++)
{
decode_MCU(im_loc);
if ((Restart_markers)&&((nr_mcu+1)%MCU_restart==0)) resync();
nr_mcu++;
im_loc+=MCU_dim_x;
}
im_loc+=im_loc_inc;
}
}
int get_JPEG_buffer(WORD X_image,WORD Y_image, BYTE **address_dest_buffer)
{
WORD y;
DWORD dest_loc=0;
BYTE *src_buffer=im_buffer;
BYTE *dest_buffer_start, *dest_buffer;
DWORD src_bytes_per_line=X_round*4;
DWORD dest_bytes_per_line=X_image*4;
if ((X_round==X_image)&&(Y_round==Y_image))
*address_dest_buffer=im_buffer;
else
{
dest_buffer_start = (BYTE *)malloc(X_image*Y_image*4);
if (dest_buffer_start==NULL) exit_func("Not enough memory for storing the JPEG image");
dest_buffer = dest_buffer_start;
for (y=0;y<Y_image;y++) {
memcpy(dest_buffer,src_buffer,dest_bytes_per_line);
src_buffer+=src_bytes_per_line;
dest_buffer+=dest_bytes_per_line;
}
*address_dest_buffer=dest_buffer_start;
free(im_buffer);
}
// release the buffer which contains the JPG file
free(buf);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -