www.pudn.com > JpegTest.rar > ENC.C


// A BMP truecolor to JPEG encoder 
// Copyright 1999 Cristi Cuturicu 
#include  
#include  
#include  
#include "jtypes.h" 
#include "jglobals.h" 
#include "jtables.h" 
 
 
void write_APP0info() 
//Nothing to overwrite for APP0info 
{ 
 writeword(APP0info.marker); 
 writeword(APP0info.length); 
 writebyte('J');writebyte('F');writebyte('I');writebyte('F');writebyte(0); 
 writebyte(APP0info.versionhi);writebyte(APP0info.versionlo); 
 writebyte(APP0info.xyunits); 
 writeword(APP0info.xdensity);writeword(APP0info.ydensity); 
 writebyte(APP0info.thumbnwidth);writebyte(APP0info.thumbnheight); 
} 
 
void write_SOF0info() 
// We should overwrite width and height 
{ 
 writeword(SOF0info.marker); 
 writeword(SOF0info.length); 
 writebyte(SOF0info.precision); 
 writeword(SOF0info.height);writeword(SOF0info.width); 
 writebyte(SOF0info.nrofcomponents); 
 writebyte(SOF0info.IdY);writebyte(SOF0info.HVY);writebyte(SOF0info.QTY); 
 writebyte(SOF0info.IdCb);writebyte(SOF0info.HVCb);writebyte(SOF0info.QTCb); 
 writebyte(SOF0info.IdCr);writebyte(SOF0info.HVCr);writebyte(SOF0info.QTCr); 
} 
 
void write_DQTinfo() 
{ 
 BYTE i; 
 writeword(DQTinfo.marker); 
 writeword(DQTinfo.length); 
 writebyte(DQTinfo.QTYinfo);for (i=0;i<64;i++) writebyte(DQTinfo.Ytable[i]); 
 writebyte(DQTinfo.QTCbinfo);for (i=0;i<64;i++) writebyte(DQTinfo.Cbtable[i]); 
} 
 
void set_quant_table(BYTE *basic_table,BYTE scale_factor,BYTE *newtable) 
// Set quantization table and zigzag reorder it 
{ 
 BYTE i; 
 long temp; 
 for (i = 0; i < 64; i++) { 
      temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; 
	/* limit the values to the valid range */ 
    if (temp <= 0L) temp = 1L; 
    if (temp > 255L) temp = 255L; /* limit to baseline range if requested */ 
    newtable[zigzag[i]] = (WORD) temp; 
			  } 
} 
 
void set_DQTinfo() 
{ 
 BYTE scalefactor=50;// scalefactor controls the visual quality of the image 
			 // the smaller is, the better image we'll get, and the smaller 
			 // compression we'll achieve 
 DQTinfo.marker=0xFFDB; 
 DQTinfo.length=132; 
 DQTinfo.QTYinfo=0; 
 DQTinfo.QTCbinfo=1; 
 set_quant_table(std_luminance_qt,scalefactor,DQTinfo.Ytable); 
 set_quant_table(std_chrominance_qt,scalefactor,DQTinfo.Cbtable); 
} 
 
void write_DHTinfo() 
{ 
 BYTE i; 
 writeword(DHTinfo.marker); 
 writeword(DHTinfo.length); 
 writebyte(DHTinfo.HTYDCinfo); 
 for (i=0;i<16;i++)  writebyte(DHTinfo.YDC_nrcodes[i]); 
 for (i=0;i<=11;i++) writebyte(DHTinfo.YDC_values[i]); 
 writebyte(DHTinfo.HTYACinfo); 
 for (i=0;i<16;i++)  writebyte(DHTinfo.YAC_nrcodes[i]); 
 for (i=0;i<=161;i++) writebyte(DHTinfo.YAC_values[i]); 
 writebyte(DHTinfo.HTCbDCinfo); 
 for (i=0;i<16;i++)  writebyte(DHTinfo.CbDC_nrcodes[i]); 
 for (i=0;i<=11;i++)  writebyte(DHTinfo.CbDC_values[i]); 
 writebyte(DHTinfo.HTCbACinfo); 
 for (i=0;i<16;i++)  writebyte(DHTinfo.CbAC_nrcodes[i]); 
 for (i=0;i<=161;i++) writebyte(DHTinfo.CbAC_values[i]); 
} 
 
void set_DHTinfo() 
{ 
 BYTE i; 
 DHTinfo.marker=0xFFC4; 
 DHTinfo.length=0x01A2; 
 DHTinfo.HTYDCinfo=0; 
 for (i=0;i<16;i++)  DHTinfo.YDC_nrcodes[i]=std_dc_luminance_nrcodes[i+1]; 
 for (i=0;i<=11;i++)  DHTinfo.YDC_values[i]=std_dc_luminance_values[i]; 
 DHTinfo.HTYACinfo=0x10; 
 for (i=0;i<16;i++)  DHTinfo.YAC_nrcodes[i]=std_ac_luminance_nrcodes[i+1]; 
 for (i=0;i<=161;i++) DHTinfo.YAC_values[i]=std_ac_luminance_values[i]; 
 DHTinfo.HTCbDCinfo=1; 
 for (i=0;i<16;i++)  DHTinfo.CbDC_nrcodes[i]=std_dc_chrominance_nrcodes[i+1]; 
 for (i=0;i<=11;i++)  DHTinfo.CbDC_values[i]=std_dc_chrominance_values[i]; 
 DHTinfo.HTCbACinfo=0x11; 
 for (i=0;i<16;i++)  DHTinfo.CbAC_nrcodes[i]=std_ac_chrominance_nrcodes[i+1]; 
 for (i=0;i<=161;i++) DHTinfo.CbAC_values[i]=std_ac_chrominance_values[i]; 
} 
 
void write_SOSinfo() 
//Nothing to overwrite for SOSinfo 
{ 
 writeword(SOSinfo.marker); 
 writeword(SOSinfo.length); 
 writebyte(SOSinfo.nrofcomponents); 
 writebyte(SOSinfo.IdY);writebyte(SOSinfo.HTY); 
 writebyte(SOSinfo.IdCb);writebyte(SOSinfo.HTCb); 
 writebyte(SOSinfo.IdCr);writebyte(SOSinfo.HTCr); 
 writebyte(SOSinfo.Ss);writebyte(SOSinfo.Se);writebyte(SOSinfo.Bf); 
} 
 
void write_comment(BYTE *comment) 
{ 
 WORD i,length; 
 writeword(0xFFFE); //The COM marker 
 length=strlen((const char *)comment); 
 writeword(length+2); 
 for (i=0;i=0 
 value=bs.value; 
 posval=bs.length-1; 
 while (posval>=0) 
  { 
   if (value & mask[posval]) bytenew|=mask[bytepos]; 
   posval--;bytepos--; 
   if (bytepos<0) { if (bytenew==0xFF) {writebyte(0xFF);writebyte(0);} 
		     else {writebyte(bytenew);} 
		    bytepos=7;bytenew=0; 
		  } 
  } 
} 
 
void compute_Huffman_table(BYTE *nrcodes,BYTE *std_table,bitstring *HT) 
{ 
 BYTE k,j; 
 BYTE pos_in_table; 
 WORD codevalue; 
 codevalue=0; pos_in_table=0; 
 for (k=1;k<=16;k++) 
   { 
     for (j=1;j<=nrcodes[k];j++) {HT[std_table[pos_in_table]].value=codevalue; 
				  HT[std_table[pos_in_table]].length=k; 
				  pos_in_table++; 
				  codevalue++; 
				 } 
     codevalue*=2; 
   } 
} 
void init_Huffman_tables() 
{ 
 compute_Huffman_table(std_dc_luminance_nrcodes,std_dc_luminance_values,YDC_HT); 
 compute_Huffman_table(std_dc_chrominance_nrcodes,std_dc_chrominance_values,CbDC_HT); 
 compute_Huffman_table(std_ac_luminance_nrcodes,std_ac_luminance_values,YAC_HT); 
 compute_Huffman_table(std_ac_chrominance_nrcodes,std_ac_chrominance_values,CbAC_HT); 
} 
 
void exitmessage(char *error_message) 
{ 
 printf("%s\n",error_message);exit(EXIT_FAILURE); 
} 
 
void set_numbers_category_and_bitcode() 
{ 
 SDWORD nr; 
 SDWORD nrlower,nrupper; 
 BYTE cat,value; 
 
 category_alloc=(BYTE *)malloc(65535*sizeof(BYTE)); 
 if (category_alloc==NULL) exitmessage("Not enough memory."); 
 category=category_alloc+32767; //allow negative subscripts 
 bitcode_alloc=(bitstring *)malloc(65535*sizeof(bitstring)); 
 if (bitcode_alloc==NULL) exitmessage("Not enough memory."); 
 bitcode=bitcode_alloc+32767; 
 nrlower=1;nrupper=2; 
 for (cat=1;cat<=15;cat++) { 
				 //Positive numbers 
				 for (nr=nrlower;nr= 0; ctr--) { 
	tmp0 = dataptr[0] + dataptr[7]; 
    tmp7 = dataptr[0] - dataptr[7]; 
    tmp1 = dataptr[1] + dataptr[6]; 
    tmp6 = dataptr[1] - dataptr[6]; 
    tmp2 = dataptr[2] + dataptr[5]; 
    tmp5 = dataptr[2] - dataptr[5]; 
    tmp3 = dataptr[3] + dataptr[4]; 
    tmp4 = dataptr[3] - dataptr[4]; 
 
	/* Even part */ 
 
    tmp10 = tmp0 + tmp3;	/* phase 2 */ 
    tmp13 = tmp0 - tmp3; 
    tmp11 = tmp1 + tmp2; 
    tmp12 = tmp1 - tmp2; 
 
    dataptr[0] = tmp10 + tmp11; /* phase 3 */ 
    dataptr[4] = tmp10 - tmp11; 
 
    z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */ 
	dataptr[2] = tmp13 + z1;	/* phase 5 */ 
    dataptr[6] = tmp13 - z1; 
 
    /* Odd part */ 
 
    tmp10 = tmp4 + tmp5;	/* phase 2 */ 
    tmp11 = tmp5 + tmp6; 
    tmp12 = tmp6 + tmp7; 
 
	/* The rotator is modified from fig 4-8 to avoid extra negations. */ 
    z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */ 
    z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */ 
    z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */ 
    z3 = tmp11 * ((float) 0.707106781); /* c4 */ 
 
    z11 = tmp7 + z3;		/* phase 5 */ 
    z13 = tmp7 - z3; 
 
    dataptr[5] = z13 + z2;	/* phase 6 */ 
    dataptr[3] = z13 - z2; 
	dataptr[1] = z11 + z4; 
    dataptr[7] = z11 - z4; 
 
    dataptr += 8;		/* advance pointer to next row */ 
  } 
 
  /* Pass 2: process columns. */ 
 
  dataptr = datafloat; 
  for (ctr = 7; ctr >= 0; ctr--) { 
    tmp0 = dataptr[0] + dataptr[56]; 
    tmp7 = dataptr[0] - dataptr[56]; 
    tmp1 = dataptr[8] + dataptr[48]; 
    tmp6 = dataptr[8] - dataptr[48]; 
    tmp2 = dataptr[16] + dataptr[40]; 
    tmp5 = dataptr[16] - dataptr[40]; 
    tmp3 = dataptr[24] + dataptr[32]; 
    tmp4 = dataptr[24] - dataptr[32]; 
 
    /* Even part */ 
 
    tmp10 = tmp0 + tmp3;	/* phase 2 */ 
    tmp13 = tmp0 - tmp3; 
    tmp11 = tmp1 + tmp2; 
    tmp12 = tmp1 - tmp2; 
 
    dataptr[0] = tmp10 + tmp11; /* phase 3 */ 
    dataptr[32] = tmp10 - tmp11; 
 
	z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */ 
    dataptr[16] = tmp13 + z1; /* phase 5 */ 
    dataptr[48] = tmp13 - z1; 
 
    /* Odd part */ 
 
    tmp10 = tmp4 + tmp5;	/* phase 2 */ 
    tmp11 = tmp5 + tmp6; 
    tmp12 = tmp6 + tmp7; 
 
    /* The rotator is modified from fig 4-8 to avoid extra negations. */ 
	z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */ 
    z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */ 
    z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */ 
    z3 = tmp11 * ((float) 0.707106781); /* c4 */ 
 
    z11 = tmp7 + z3;		/* phase 5 */ 
    z13 = tmp7 - z3; 
 
    dataptr[40] = z13 + z2; /* phase 6 */ 
	dataptr[24] = z13 - z2; 
    dataptr[8] = z11 + z4; 
    dataptr[56] = z11 - z4; 
 
    dataptr++;			/* advance pointer to next column */ 
  } 
 
// Quantize/descale the coefficients, and store into output array 
 for (i = 0; i < 64; i++) { 
 /* Apply the quantization and scaling factor */ 
			   temp = datafloat[i] * fdtbl[i]; 
/* Round to nearest integer. 
   Since C does not specify the direction of rounding for negative 
   quotients, we have to force the dividend positive for portability. 
   The maximum coefficient size is +-16K (for 12-bit data), so this 
   code should work for either 16-bit or 32-bit ints. 
*/ 
	   outdata[i] = (SWORD) ((SWORD)(temp + 16384.5) - 16384); 
			  } 
} 
 
void process_DU(SBYTE *ComponentDU,float *fdtbl,SWORD *DC, 
		bitstring *HTDC,bitstring *HTAC) 
{ 
 bitstring EOB=HTAC[0x00]; 
 bitstring M16zeroes=HTAC[0xF0]; 
 BYTE i; 
 BYTE startpos; 
 BYTE end0pos; 
 BYTE nrzeroes; 
 BYTE nrmarker; 
 SWORD Diff; 
 
 fdct_and_quantization(ComponentDU,fdtbl,DU_DCT); 
 //zigzag reorder 
 for (i=0;i<=63;i++) DU[zigzag[i]]=DU_DCT[i]; 
 Diff=DU[0]-*DC; 
 *DC=DU[0]; 
 //Encode DC 
 if (Diff==0) writebits(HTDC[0]); //Diff might be 0 
  else {writebits(HTDC[category[Diff]]); 
	writebits(bitcode[Diff]); 
       } 
 //Encode ACs 
 for (end0pos=63;(end0pos>0)&&(DU[end0pos]==0);end0pos--) ; 
 //end0pos = first element in reverse order !=0 
 if (end0pos==0) {writebits(EOB);return;} 
 
 i=1; 
 while (i<=end0pos) 
  { 
   startpos=i; 
   for (; (DU[i]==0)&&(i<=end0pos);i++) ; 
   nrzeroes=i-startpos; 
   if (nrzeroes>=16) { 
      for (nrmarker=1;nrmarker<=nrzeroes/16;nrmarker++) writebits(M16zeroes); 
      nrzeroes=nrzeroes%16; 
		     } 
   writebits(HTAC[nrzeroes*16+category[DU[i]]]);writebits(bitcode[DU[i]]); 
   i++; 
  } 
 if (end0pos!=63) writebits(EOB); 
} 
 
void load_data_units_from_RGB_buffer(WORD xpos,WORD ypos) 
{ 
 BYTE x,y; 
 BYTE pos=0; 
 DWORD location; 
 BYTE R,G,B; 
 location=ypos*Ximage+xpos; 
 for (y=0;y<8;y++) 
 { 
  for (x=0;x<8;x++) 
   { 
    R=RGB_buffer[location].R;G=RGB_buffer[location].G;B=RGB_buffer[location].B; 
    YDU[pos]=Y(R,G,B); 
    CbDU[pos]=Cb(R,G,B); 
    CrDU[pos]=Cr(R,G,B); 
    location++;pos++; 
   } 
  location+=Ximage-8; 
 } 
} 
 
void main_encoder() 
{ 
 SWORD DCY=0,DCCb=0,DCCr=0; //DC coefficients used for differential encoding 
 WORD xpos,ypos; 
 for (ypos=0;yposnrline_dn;nrline_up--,nrline_dn++) 
  { 
   memcpy(tmpline,RGB_buffer+nrline_up*Ximage, dimline); 
   memcpy(RGB_buffer+nrline_up*Ximage,RGB_buffer+nrline_dn*Ximage,dimline); 
   memcpy(RGB_buffer+nrline_dn*Ximage,tmpline,dimline); 
  } 
 // Y completion: 
 memcpy(tmpline,RGB_buffer+(Yimage-1)*Ximage,dimline); 
 for (nrline=Yimage;nrline1) { strcpy(BMP_filename,argv[1]); 
		   if (argc>2) strcpy(JPG_filename,argv[2]); 
		else { strcpy(JPG_filename,BMP_filename); 
			   len_filename=strlen(BMP_filename); 
			   strcpy(JPG_filename+(len_filename-3),"jpg"); 
			 } 
		 } 
  else exitmessage("Syntax: enc fis.bmp [fis.jpg]"); 
 load_bitmap(BMP_filename, &Ximage_original, &Yimage_original); 
 fp_jpeg_stream=fopen(JPG_filename,"wb"); 
 init_all(); 
 SOF0info.width=Ximage_original; 
 SOF0info.height=Yimage_original; 
 writeword(0xFFD8); //SOI 
 write_APP0info(); 
 // write_comment("Cris made this JPEG with his own encoder"); 
 write_DQTinfo(); 
 write_SOF0info(); 
 write_DHTinfo(); 
 write_SOSinfo(); 
 
 bytenew=0;bytepos=7; 
 main_encoder(); 
 //Do the bit alignment of the EOI marker 
 if (bytepos>=0) { 
		   fillbits.length=bytepos+1; 
		   fillbits.value=(1<<(bytepos+1))-1; 
		   writebits(fillbits); 
		 } 
 writeword(0xFFD9); //EOI 
 free(RGB_buffer); free(category_alloc);free(bitcode_alloc); 
 fclose(fp_jpeg_stream); 
}