jpeg 解码成bmp格式

jpeg decode

/***************************************************************************/
/*                                                                         */
/*  File: loadjpg.cpp                                                      */
/*  Author: [email protected]                                           */
/*  Date: 19-01-06                                                         */
/*                                                                         */
/*  Revised: 26-07-07                                                      */
/*                                                                         */
/***************************************************************************/
/*
    About:
	Simplified jpg/jpeg decoder image loader - so we can take a .jpg file
	either from memory or file, and convert it either to a .bmp or directly
	to its rgb pixel data information.

	Simplified, and only deals with basic jpgs, but it covers all the
	information of how the jpg format works :)

	Can be used to convert a jpg in memory to rgb pixels in memory.

	Or you can pass it a jpg file name and an output bmp filename, and it
	loads and writes out a bmp file.

	i.e.
	ConvertJpgFile("cross.jpg", "cross.bmp")
*/
/***************************************************************************/

#pragma once

#include <stdio.h>		// sprintf(..), fopen(..)
#include <stdarg.h>     // So we can use ... (in dprintf)
#include <string.h>		// memset(..)
#include <math.h>		// sqrt(..), cos(..)
#include <stdbool.h>	//bool datatype




extern void dprintf(const char *fmt, ...);
//for c++
/*void dprintf(const char *fmt, ...)
{
	va_list parms;
	char buf[256];

	// Try to print in the allocated space.
	va_start(parms, fmt);
	vsprintf (buf, fmt, parms);
	va_end(parms);

	// Write the information out to a txt file
	FILE *fp = fopen("output.txt", "a+");
	fprintf(fp, "%s", buf);
	fclose(fp);

}// End dprintf(..)
*/
/*
__forceinline void dprintf(const char *fmt, ...) 
{
	va_list parms;
	char buf[256];

	// Try to print in the allocated space.
	va_start(parms, fmt);
	vsprintf (buf, fmt, parms);
	va_end(parms);

	// Write the information out to a txt file
	FILE *fp = fopen("output.txt", "a+");
	fprintf(fp, "%s",  buf);
	fclose(fp);

}// End dprintf(..)
*/

/***************************************************************************/

#define DQT 	 0xDB	// Define Quantization Table
#define SOF 	 0xC0	// Start of Frame (size information)
#define DHT 	 0xC4	// Huffman Table
#define SOI 	 0xD8	// Start of Image
#define SOS 	 0xDA	// Start of Scan
#define EOI 	 0xD9	// End of Image, or End of File
#define APP0	 0xE0

#define BYTE_TO_WORD(x) (((x)[0]<<8)|(x)[1])


#define HUFFMAN_TABLES		4
#define COMPONENTS			4

#define cY	1
#define cCb	2
#define cCr	3

static int ZigZagArray[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,
};

/***************************************************************************/

//size = 4 + 4 +2
//	     = 10
typedef struct 
{
     int value;					// Decodes to.
     int length;				// Length in bits.
     unsigned short int code;	// 2 byte code (variable length)
}stBlock;

/***************************************************************************/

//size = 4*17 + 4*257 + 4 + 10*1024
//	     = 11336
typedef struct 
{
	unsigned char	m_length[17];		// 17 values from jpg file, 
										// k =1-16 ; L[k] indicates the number of Huffman codes of length k
	unsigned char	m_hufVal[257];		// 256 codes read in from the jpeg file

	int				m_numBlocks;
	stBlock			m_blocks[1024];
}stHuffmanTable;

// size = 4 + 4 +4 + 11336 + 11336 + 2 +4
// 	      = 22690
typedef struct  
{
  unsigned int			m_hFactor;
  unsigned int			m_vFactor;
  float *				m_qTable;			// Pointer to the quantisation table to use
  stHuffmanTable*		m_acTable;
  stHuffmanTable*		m_dcTable;
  short int				m_DCT[65];			// DCT coef
  int					m_previousDC;
}stComponent;

//size of a stJpegData = 4(m_rgb) + 2*4(m_width+m_height) + 4(m_stream) + 4*22690 (m_component_info)
//					        + 64*4*32 (m_Q_tables) + 2*4*11336 (m_HTDC+m_HTAC) + 4*64*4 (m_Y) + 4*64 (m_Cr) + 4*64(m_Cb)
//						+ 4 (m_colourspace)
//					    = 191196
typedef struct 
{
	unsigned char*		m_rgb;				// Final Red Green Blue pixel data
	unsigned int		m_width;			// Width of image
	unsigned int		m_height;			// Height of image

	const unsigned char*m_stream;			// Pointer to the current stream

	stComponent			m_component_info[COMPONENTS];

	float				m_Q_tables[COMPONENTS][64];	// quantization tables
	stHuffmanTable		m_HTDC[HUFFMAN_TABLES];		// DC huffman tables  
	stHuffmanTable		m_HTAC[HUFFMAN_TABLES];		// AC huffman tables

	// Temp space used after the IDCT to store each components
	unsigned char		m_Y[64*4];
	unsigned char		m_Cr[64];
	unsigned char		m_Cb[64];

	// Internal Pointer use for colorspace conversion, do not modify it !!!
	unsigned char *		m_colourspace;
}stJpegData;


/***************************************************************************/
// 
//  Returns the size of the file in bytes
//
/***************************************************************************/
inline int FileSize(FILE *fp)
{
	long pos;
	fseek(fp, 0, SEEK_END);
	pos = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	return pos;
}

/***************************************************************************/

// Clamp our integer between 0 and 255
inline unsigned char Clamp(int i)
{
	if (i<0)
		return 0;
	else if (i>255)
		return 255;
	else
		return i;
}   

/***************************************************************************/

void GenHuffCodes( int num_codes, stBlock* arr, unsigned char* huffVal )
{
     int hufcounter = 0;
     int codelengthcounter = 1;
     int cc;
     
	for(cc=0; cc< num_codes; cc++)
	{
		 while ( arr[cc].length > codelengthcounter )
		 {
			hufcounter = hufcounter << 1;
			codelengthcounter++;
		 }

		 arr[cc].code = hufcounter;
		 arr[cc].value = huffVal[cc];
		 hufcounter = hufcounter + 1;
	}
}

/***************************************************************************/

float C(int u)
{
    if (u == 0)
         return (1.0f/sqrtf(2));
    else
         return 1.0f;
}


int func(int x, int y, const int block[8][8])
{
	const float PI = 3.14f;
    float sum=0;
	int u,v;
    for(  u=0; u<8; u++)
    {
         for(v=0; v<8; v++)
         {
             sum += ( C(u) * C(v) ) * block[u][v] * cosf( ((2*x+1) * u * PI) / 16)  * cosf( ((2*y+1) * v * PI) / 16);
         }
    }         
    return (int) ((1.0/4.0) * sum);
}

void PerformIDCT(int outBlock[8][8], const int inBlock[8][8])
{
	int x,y;
	for(y=0; y<8; y++)
	{
		for(x=0; x<8; x++)
		{
			outBlock[x][y]  =  func( x, y, inBlock);
		}
	}
}

/***************************************************************************/

void DequantizeBlock( int block[64], const float quantBlock[64] )
{

	int c;
	for( c=0; c<64; c++)
	{
		block[c] = (int)(block[c] * quantBlock[c]);
	}
}

/***************************************************************************/

void DeZigZag(int outBlock[64], const int inBlock[64])
{
	int i;
	for( i=0; i<64; i++)
	{
		outBlock[ i ] = inBlock[ZigZagArray[i]];
	}
}

/***************************************************************************/

void TransformArray(int outArray[8][8], const int inArray[64])
{
	int cc = 0;
	int x,y;
	for( y=0; y<8; y++)
	{
		for(x=0; x<8; x++)
		{
			outArray[x][y]  =  inArray[cc];
			cc++;
		}
	}
}

/***************************************************************************/

void DumpDecodedBlock(int val[8][8])
{
	int x,y;
	dprintf("# Decoded 8x8 Block#\n");
	for( y=0; y<8; y++)
	{
		for( x=0; x<8; x++)
		{
			dprintf("%2x ", val[x][y]);
		}
		dprintf("\n");
	}
}

/***************************************************************************/

inline void DecodeSingleBlock(stComponent *comp, unsigned char *outputBuf, int stride)
{
	short* inptr    = comp->m_DCT;
	float* quantptr = comp->m_qTable;
	int i,x,y;

	// Create a temp 8x8, i.e. 64 array for the data
	int data[64] = {0};

	// Copy our data into the temp array
	for (i=0; i<64; i++)
	{
		data[i] = inptr[i];
	}

	// De-Quantize
	DequantizeBlock(data, quantptr);

	// De-Zig-Zag
	int block[64] = {0};
	DeZigZag(block, data);

	// Create an 8x8 array
	int arrayBlock[8][8]={0};
	TransformArray(arrayBlock, block);

	// Inverse DCT
	int val[8][8]={0};
	PerformIDCT(val, arrayBlock);

	// Level Shift each element (i.e. add 128), and copy to our
	// output
	unsigned char *outptr = outputBuf;
	for (y = 0; y < 8; y++) 
	{
		for (x=0; x<8; x++)
		{
			val[x][y] += 128;

			outptr[x] = Clamp(val[x][y]);
		}

		outptr += stride;
	}

	DumpDecodedBlock(val);
}

/***************************************************************************/

/***************************************************************************/
//
// Save a buffer in 24bits Bitmap (.bmp) format 
//
/***************************************************************************/
inline void WriteBMP24(const char* szBmpFileName, int Width, int Height, unsigned char* RGB)
{
	#pragma pack(1)
	typedef struct // BitmapFileHeader & BitmapInfoHeader
	{
		// BitmapFileHeader
		char         bmtype[2];     // 2 bytes - 'B' 'M'
		unsigned int iFileSize;     // 4 bytes
		short int    reserved1;     // 2 bytes
		short int    reserved2;     // 2 bytes
		unsigned int iOffsetBits;   // 4 bytes
		// End of stBMFH structure - size of 14 bytes
		// BitmapInfoHeader
		unsigned int iSizeHeader;    // 4 bytes - 40
		unsigned int iWidth;         // 4 bytes
		unsigned int iHeight;        // 4 bytes
		short int    iPlanes;        // 2 bytes
		short int    iBitCount;      // 2 bytes
		unsigned int Compression;    // 4 bytes
		unsigned int iSizeImage;     // 4 bytes
		unsigned int iXPelsPerMeter; // 4 bytes
		unsigned int iYPelsPerMeter; // 4 bytes
		unsigned int iClrUsed;       // 4 bytes
		unsigned int iClrImportant;  // 4 bytes
		// End of stBMIF structure - size 40 bytes
		// Total size - 54 bytes
	}stBMFH ;
	#pragma pack()
	int x,y;
	// Round up the width to the nearest DWORD boundary
	int iNumPaddedBytes = 4 - (Width * 3) % 4;
	iNumPaddedBytes = iNumPaddedBytes % 4;

	stBMFH bh;
	memset(&bh, 0, sizeof(bh));
	bh.bmtype[0]='B';
	bh.bmtype[1]='M';
	bh.iFileSize = (Width*Height*3) + (Height*iNumPaddedBytes) + sizeof(bh);
	bh.iOffsetBits = sizeof(stBMFH);
	bh.iSizeHeader = 40;
	bh.iPlanes = 1;
	bh.iWidth = Width;
	bh.iHeight = Height;
	bh.iBitCount = 24;


	char temp[1024]={0};
	sprintf(temp, "%s", szBmpFileName);
	FILE* fp = fopen(temp, "wb");
	fwrite(&bh, sizeof(bh), 1, fp);
	for ( y=Height-1; y>=0; y--)
	{
		for (x=0; x<Width; x++)
		{
			int i = (x + (Width)*y) * 3;
			unsigned int rgbpix = (RGB[i]<<16)|(RGB[i+1]<<8)|(RGB[i+2]<<0);
			fwrite(&rgbpix, 3, 1, fp);
		}
		if (iNumPaddedBytes>0)
		{
			unsigned char pad = 0;
			fwrite(&pad, iNumPaddedBytes, 1, fp);
		}
	}
	fclose(fp);
}

/***************************************************************************/

// Takes two array of bits, and build the huffman table for size, and code

/***************************************************************************/
inline void BuildHuffmanTable(const unsigned char *bits, const unsigned char *stream, stHuffmanTable *HT)
{
	int i,j;
	for (j=1; j<=16; j++) 
	{
		HT->m_length[j] = bits[j];
	}

	// Work out the total number of codes
	int numBlocks = 0;
	for (i=1; i<=16; i++)
	{
		numBlocks += HT->m_length[i];
	}
	HT->m_numBlocks = numBlocks;

	// Fill in the data our our blocks, so we know how many bits each
	// one is
	int c=0;
	for (i=1; i<=16; i++)
	{
		for (j=0; j<HT->m_length[i]; j++)
		{
			HT->m_blocks[c].length = i;
			c++;
		}

	}

	GenHuffCodes(HT->m_numBlocks, HT->m_blocks, HT->m_hufVal);
}

/***************************************************************************/

inline void PrintSOF(const unsigned char *stream)
{
	int width;
	int height;
	int nr_components;
	int precision;

	const char *nr_components_to_string[] =	{	"????",
												"Grayscale",
												"????",
												"YCbCr",
												"CYMK" };

	precision = stream[2];
	height = BYTE_TO_WORD(stream+3);
	width  = BYTE_TO_WORD(stream+5);
	nr_components = stream[7];

	dprintf("> SOF marker\n");
	dprintf("Size:%dx%d nr_components:%d (%s)  precision:%d\n", 
							width, height,
							nr_components, 
							nr_components_to_string[nr_components],
							precision);
}

/***************************************************************************/

inline int ParseSOF(stJpegData *jdata, const unsigned char *stream)
{
	/*
	SOF		16		0xffc0		Start Of Frame
	Lf		16		3Nf+8		Frame header length
	P		8		8			Sample precision
	Y		16		0-65535		Number of lines
	X		16		1-65535		Samples per line
	Nf		8		1-255		Number of image components (e.g. Y, U and V).

	---------Repeats for the number of components (e.g. Nf)-----------------
	Ci		8		0-255		Component identifier
	Hi		4		1-4			Horizontal Sampling Factor
	Vi		4		1-4			Vertical Sampling Factor
	Tqi		8		0-3			Quantization Table Selector.
	*/

	PrintSOF(stream);

	int height = BYTE_TO_WORD(stream+3);
	int width  = BYTE_TO_WORD(stream+5);
	int nr_components = stream[7];
	int i;
	stream += 8;
	for (i=0; i<nr_components; i++) 
	{
		int cid				= *stream++;
		int sampling_factor = *stream++;
		int Q_table			= *stream++;

		stComponent *c = &jdata->m_component_info[cid];
		c->m_vFactor = sampling_factor&0xf;
		c->m_hFactor = sampling_factor>>4;
		c->m_qTable = jdata->m_Q_tables[Q_table];

		dprintf("Component:%d  factor:%dx%d  Quantization table:%d\n",
				cid, 
				c->m_vFactor, 
				c->m_hFactor, 
				Q_table );
	}
	jdata->m_width = width;
	jdata->m_height = height;

	return 0;
}

/***************************************************************************/

inline void BuildQuantizationTable(float *qtable, const unsigned char *ref_table)
{
	int c = 0;
	int i,j;
	for (i=0; i<8; i++) 
	{
		for ( j=0; j<8; j++) 
		{
			unsigned char val = ref_table[c];

			qtable[c] = val;
			c++;
		}
	}
}


/***************************************************************************/

inline int ParseDQT(stJpegData *jdata, const unsigned char *stream)
{
	int length, qi;
	float *table;

	dprintf("> DQT marker\n");
	length = BYTE_TO_WORD(stream) - 2;
	stream += 2;	// Skip length

	while (length>0)
	{
		qi = *stream++;

		int qprecision = qi>>4;	 // upper 4 bits specify the precision
		int qindex     = qi&0xf; // index is lower 4 bits

		if (qprecision)
		{
			// precision in this case is either 0 or 1 and indicates the precision 
			// of the quantized values;
			// 8-bit (baseline) for 0 and  up to 16-bit for 1 

			dprintf("Error - 16 bits quantization table is not supported\n");
		}

		if (qindex>4)
		{
			dprintf("Error - No more 4 quantization table is supported (got %d)\n", qi);
		}

		// The quantization table is the next 64 bytes
		table = jdata->m_Q_tables[qindex];

		// the quantization tables are stored in zigzag format, so we
		// use this functino to read them all in and de-zig zag them
		BuildQuantizationTable(table, stream);
		stream += 64;
		length -= 65;
	}
	return 0;
}

/***************************************************************************/

inline int ParseSOS(stJpegData *jdata, const unsigned char *stream)
{
	/*
	SOS		16		0xffd8			Start Of Scan
	Ls		16		2Ns + 6			Scan header length
	Ns		8		1-4				Number of image components
	Csj		8		0-255			Scan Component Selector
	Tdj		4		0-1				DC Coding Table Selector
	Taj		4		0-1				AC Coding Table Selector
	Ss		8		0				Start of spectral selection
	Se		8		63				End of spectral selection
	Ah		4		0				Successive Approximation Bit High
	Ai		4		0				Successive Approximation Bit Low
	*/

	unsigned int nr_components = stream[2];
	unsigned int i;
	dprintf("> SOS marker\n");

	if (nr_components != 3)
	{
		dprintf("Error - We only support YCbCr image\n");
	}


	stream += 3;
	for ( i=0;i<nr_components;i++) 
	{
		unsigned int cid   = *stream++;
		unsigned int table = *stream++;

		if ((table&0xf)>=4)
		{
			dprintf("Error - We do not support more than 2 AC Huffman table\n");
		}
		if ((table>>4)>=4)
		{
			dprintf("Error - We do not support more than 2 DC Huffman table\n");
		}
		dprintf("ComponentId:%d  tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);

		jdata->m_component_info[cid].m_acTable = &jdata->m_HTAC[table&0xf];
		jdata->m_component_info[cid].m_dcTable = &jdata->m_HTDC[table>>4];
	}
	jdata->m_stream = stream+3;
	return 0;
}

/***************************************************************************/

inline int ParseDHT(stJpegData *jdata, const unsigned char *stream)
{
	/*
	u8 0xff 
	u8 0xc4 (type of segment) 
	u16 be length of segment 
	4-bits class (0 is DC, 1 is AC, more on this later) 
	4-bits table id 
	array of 16 u8 number of elements for each of 16 depths 
	array of u8 elements, in order of depth 
	*/

	unsigned int count, i;
	unsigned char huff_bits[17];
	int length, index;

	length = BYTE_TO_WORD(stream) - 2;
	stream += 2;	// Skip length

	dprintf("> DHT marker (length=%d)\n", length);

	while (length>0) 
	{
		index = *stream++;

		// We need to calculate the number of bytes 'vals' will takes
		huff_bits[0] = 0;
		count = 0;
		for (i=1; i<17; i++) 
		{
			huff_bits[i] = *stream++;
			count += huff_bits[i];
		}

		if (count > 256)
		{
			dprintf("Error - No more than 1024 bytes is allowed to describe a huffman table");
		}
		if ( (index &0xf) >= HUFFMAN_TABLES)
		{
			dprintf("Error - No mode than %d Huffman tables is supported\n", HUFFMAN_TABLES);
		}
		dprintf("Huffman table %s n%d\n", (index&0xf0)?"AC":"DC", index&0xf);
		dprintf("Length of the table: %d\n", count);

		if (index & 0xf0 )
		{
			unsigned char* huffval = jdata->m_HTAC[index&0xf].m_hufVal;
			for (i = 0; i < count; i++)
				huffval[i] = *stream++;

			BuildHuffmanTable(huff_bits, stream, &jdata->m_HTAC[index&0xf]); // AC
		}
		else
		{
			unsigned char* huffval = jdata->m_HTDC[index&0xf].m_hufVal;
			for (i = 0; i < count; i++)
				huffval[i] = *stream++;

			BuildHuffmanTable(huff_bits, stream, &jdata->m_HTDC[index&0xf]); // DC
		}

		length -= 1;
		length -= 16;
		length -= count;
	}
	dprintf("< DHT marker\n");
	return 0;
}

/***************************************************************************/

inline int ParseJFIF(stJpegData *jdata, const unsigned char *stream)
{
	int chuck_len;
	int marker;
	int sos_marker_found = 0;
	int dht_marker_found = 0;

	// Parse marker
	while (!sos_marker_found)
	{
		if (*stream++ != 0xff)
		{
			goto bogus_jpeg_format;
		}

		// Skip any padding ff byte (this is normal)
		while (*stream == 0xff)
		{
			stream++;
		}

		marker = *stream++;
		chuck_len = BYTE_TO_WORD(stream);

		switch (marker)
		{
			case SOF:
			{
				if (ParseSOF(jdata, stream) < 0)
					return -1;
			}
			break;

			case DQT:
			{
				if (ParseDQT(jdata, stream) < 0)
					return -1;
			}
			break;

			case SOS:
			{
				if (ParseSOS(jdata, stream) < 0)
					return -1;
				sos_marker_found = 1;
			}
			break;

			case DHT:
			{
				if (ParseDHT(jdata, stream) < 0)
					return -1;
				dht_marker_found = 1;
			}
			break;

			// The reason I added these additional skips here, is because for
			// certain jpg compressions, like swf, it splits the encoding 
			// and image data with SOI & EOI extra tags, so we need to skip
			// over them here and decode the whole image
			case SOI:
			case EOI:
			{
				chuck_len = 0;
				break;
			}
			break;

			case 0xDD: //DRI: Restart_markers=1;
			{
				dprintf("DRI - Restart_marker\n");
			}
			break;

			case APP0:
			{
				dprintf("APP0 Chunk ('txt' information) skipping\n");
			}
			break;

			default:
			{
				dprintf("ERROR> Unknown marker %2.2x\n", marker);
			}
			break;
		}

		stream += chuck_len;
	}

	if (!dht_marker_found) 
	{
		dprintf("ERROR> No Huffman table loaded\n");
	}

	return 0;

	bogus_jpeg_format:
	dprintf("ERROR> Bogus jpeg format\n");
	return -1;
}

/***************************************************************************/

inline int JpegParseHeader(stJpegData *jdata, const unsigned char *buf, unsigned int size)
{
	// Identify the file
	if ((buf[0] != 0xFF) || (buf[1] != SOI))
	{
		dprintf("Not a JPG file ?\n");
		return -1;
	}

	const unsigned char* startStream = buf+2;
	const int fileSize = size-2;

	dprintf("-|- File thinks its size is: %d bytes\n", fileSize);

	int ret = ParseJFIF(jdata, startStream);

	return ret;
}

/***************************************************************************/

inline void JpegGetImageSize(stJpegData *jdata, unsigned int *width, unsigned int *height)
{
	*width  = jdata->m_width;
	*height = jdata->m_height;
}

/***************************************************************************/

unsigned int g_reservoir = 0;
unsigned int g_nbits_in_reservoir = 0;

inline void FillNBits(const unsigned char** stream, int nbits_wanted)
{
	while ((int)g_nbits_in_reservoir<nbits_wanted)
	{
		const unsigned char c = *(*stream)++;
		g_reservoir <<= 8;
		if (c == 0xff && (**stream) == 0x00)
			(*stream)++;
		g_reservoir |= c;
		g_nbits_in_reservoir+=8;
	}
}

inline short GetNBits(const unsigned char** stream, int nbits_wanted)
{
	FillNBits(stream, nbits_wanted);
	
	short result = ((g_reservoir)>>(g_nbits_in_reservoir-(nbits_wanted))); 

	g_nbits_in_reservoir -= (nbits_wanted); 
	g_reservoir &= ((1U<<g_nbits_in_reservoir)-1);

	/*
	// Could do the sign conversion here!
	if (result < (short)(1UL<<((nbits_wanted)-1)))
	{
		result = result + (short)(0xFFFFFFFFUL<<(nbits_wanted))+1;
	}
	*/
	return result;
}

inline int LookNBits(const unsigned char** stream, int nbits_wanted)
{
	FillNBits(stream, nbits_wanted);

	int result = ((g_reservoir)>>(g_nbits_in_reservoir-(nbits_wanted)));
	return result;
}

inline void SkipNBits(const unsigned char** stream, int nbits_wanted)
{
	FillNBits(stream, nbits_wanted);

	g_nbits_in_reservoir -= (nbits_wanted); 
	g_reservoir &= ((1U<<g_nbits_in_reservoir)-1);
}


/***************************************************************************/


bool IsInHuffmanCodes(int code, int numCodeBits, int numBlocks, stBlock* blocks, int* outValue)
{

	int j;
	for ( j=0; j<numBlocks; j++)
	{
		int hufhCode		= blocks[j].code;
		int hufCodeLenBits	= blocks[j].length;
		int hufValue		= blocks[j].value;

		// We've got a match!
		if ((code==hufhCode) && (numCodeBits==hufCodeLenBits))
		{
			*outValue = hufValue;
			return true;
		}
	}
	return false;
}

/***************************************************************************/

int DetermineSign(int val, int nBits)
{
	bool negative = val < (1<<(nBits-1));

	if (negative)
	{
		// (-1 << (s)), makes the last bit a 1, so we have 1000,0000 for example for 8 bits

		val = val + (-1 << (nBits)) + 1; 
	}

	// Else its unsigned, just return
	return val;
}

/***************************************************************************/

char g_bigBuf[1024] = {0};
char* IntToBinary(int val, int bits)
{
	int i;
	for (i=0; i<32; i++) g_bigBuf[i]='\0';

	int c = 0;
	for (i=bits-1; i>=0; i--)
	{
		bool on = (val & (1<<i)) ? 1 : 0;
		g_bigBuf[c] = on ? '1' : '0';
		c++;
	}

	return &g_bigBuf[0];
}

/***************************************************************************/

void DumpHufCodes(stHuffmanTable* table)
{
	int i;
	dprintf("HufCodes\n");
	dprintf("Num: %d\n", table->m_numBlocks);
	for (i = 0; i<table->m_numBlocks; i++)
	{
		dprintf("%03d\t [%s]\n", i, IntToBinary(table->m_blocks[i].code, table->m_blocks[i].length));
	}
	dprintf("\n");

}

/***************************************************************************/

void DumpDCTValues(short dct[64])
{
	int i;
	dprintf("\n#Extracted DCT values from SOS#\n");
	int c = 0;
	for ( i=0; i<64; i++)
	{
		dprintf("% 4d  ", dct[c++]);

		if ( (c>0) && (c%8==0) ) dprintf("\n");
	}
	dprintf("\n");
}


/***************************************************************************/

void ProcessHuffmanDataUnit(stJpegData *jdata, int indx)
{
	stComponent *c = &jdata->m_component_info[indx];

	// Start Huffman decoding

	// We memset it here, as later on we can just skip along, when we have lots
	// of leading zeros, for our AC run length encoding :)
	short DCT_tcoeff[64];
	memset(DCT_tcoeff, 0, sizeof(DCT_tcoeff)); //Initialize DCT_tcoeff


	bool found = false;
	int decodedValue = 0;

	int k,j;

//	DumpHufCodes(c->m_dcTable);
//	DumpHufCodes(c->m_acTable);

	dprintf("\nHuff Block:\n\n");


	// First thing is get the 1 DC coefficient at the start of our 64 element
	// block
	for (k=1; k<16; k++)
	{
		// Keep grabbing one bit at a time till we find one thats a huffman code
		int code = LookNBits(&jdata->m_stream, k);

		// Check if its one of our huffman codes
		if (IsInHuffmanCodes(code, k,  c->m_dcTable->m_numBlocks, c->m_dcTable->m_blocks, &decodedValue))
		{
			// Skip over the rest of the bits now.
			SkipNBits(&jdata->m_stream, k);

			found = true;

			// The decoded value is the number of bits we have to read in next
			int numDataBits = decodedValue;

			// We know the next k bits are for the actual data
			if (numDataBits==0)
			{
				DCT_tcoeff[0] = c->m_previousDC;
			}
			else
			{
				short data = GetNBits(&jdata->m_stream, numDataBits);

				data = DetermineSign(data, numDataBits);

				DCT_tcoeff[0] = data + c->m_previousDC;
				c->m_previousDC = DCT_tcoeff[0];
			}

			// Found so we can exit out
			break;
		}
	}

	if (!found)
	{
		dprintf("-|- ##ERROR## We have a *serious* error, unable to find huffman code\n");
	}

	// Second, the 63 AC coefficient
	int nr=1; 
	bool EOB_found=false;
	while ( (nr<=63)&&(!EOB_found) )
	{
		k = 0;
		for (k=1; k<=16; k++)
		{
			// Keep grabbing one bit at a time till we find one thats a huffman code
			int code = LookNBits(&jdata->m_stream, k);


			// Check if its one of our huffman codes
			if (IsInHuffmanCodes(code, k,  c->m_acTable->m_numBlocks, c->m_acTable->m_blocks, &decodedValue))
			{

				// Skip over k bits, since we found the huffman value
				SkipNBits(&jdata->m_stream, k);


				// Our decoded value is broken down into 2 parts, repeating RLE, and then
				// the number of bits that make up the actual value next
				int valCode = decodedValue;

				unsigned char size_val = valCode&0xF;	// Number of bits for our data
				unsigned char count_0  = valCode>>4;	// Number RunLengthZeros

				if (size_val==0) 
				{// RLE 
					if (count_0==0)EOB_found=true;	// EOB found, go out
					else if (count_0==0xF) nr+=16;  // skip 16 zeros
				}
				else
				{
					nr+=count_0; //skip count_0 zeroes
					
					if (nr > 63)
					{
						dprintf("-|- ##ERROR## Huffman Decoding\n");
					}

					short data = GetNBits(&jdata->m_stream, size_val );

					data = DetermineSign(data, size_val);

					DCT_tcoeff[nr++]=data;

				}
				break;
			}
		}

		if (k>16)
		{	
			nr++;
		}
	}


	DumpDCTValues(DCT_tcoeff);


	// We've decoded a block of data, so copy it across to our buffer
	for ( j = 0; j < 64; j++)
	{
		c->m_DCT[j] = DCT_tcoeff[j];
	}

}

/***************************************************************************/

inline void ConvertYCrCbtoRGB(int y, int cb, int cr,
							  int* r, int* g, int* b)

{
	float red, green, blue;

	red   = y + 1.402f*(cb-128);
	green = y-0.34414f*(cr-128)-0.71414f*(cb-128);
	blue  = y+1.772f*(cr-128);

	*r = (int) Clamp((int)red);
	*g = (int) Clamp((int)green);
	*b = (int) Clamp((int)blue);
}

/***************************************************************************/

inline void YCrCB_to_RGB24_Block8x8(stJpegData *jdata, int w, int h, int imgx, int imgy, int imgw, int imgh)
{
	const unsigned char *Y, *Cb, *Cr;
	unsigned char *pix;

	int x,y;
	
	int r, g, b;

	Y  = jdata->m_Y;
	Cb = jdata->m_Cb;
	Cr = jdata->m_Cr;

	int olw = 0; // overlap
	if ( imgx > (imgw-8*w) )
	{
		olw = imgw-imgx;
	}

	int olh = 0; // overlap
	if ( imgy > (imgh-8*h) )
	{
		olh = imgh-imgy;
	}

//	dprintf("***pix***\n\n");
	for ( y=0; y<(8*h - olh); y++)
	{
		for ( x=0; x<(8*w - olw); x++)
		{
			int poff = x*3 + jdata->m_width*3*y;
			pix = &(jdata->m_colourspace[poff]);
			
			int yoff = x + y*(w*8);
			int coff = (int)(x*(1.0f/w)) + (int)(y*(1.0f/h))*8;

			int yc =  Y[yoff];
			int cb = Cb[coff];
			int cr = Cr[coff];

			ConvertYCrCbtoRGB(yc,cr,cb,&r,&g,&b);

			pix[0] = Clamp(r);
			pix[1] = Clamp(g);
			pix[2] = Clamp(b);

//			dprintf("-[%d][%d][%d]-\t", poff, yoff, coff);
		}
//		dprintf("\n");
	}
//	dprintf("\n\n");
}

/***************************************************************************/
//
//  Decoding
//  .-------.
//  | 1 | 2 |
//  |---+---|
//  | 3 | 4 |
//  `-------'
//
/***************************************************************************/
inline void DecodeMCU(stJpegData *jdata, int w, int h)
{

	int x,y;
	// Y
	for (y=0; y<h; y++)
	{
		for (x=0; x<w; x++)
		{
			int stride = w*8;
			int offset = x*8 + y*64*w;

			ProcessHuffmanDataUnit(jdata, cY);

			DecodeSingleBlock(&jdata->m_component_info[cY], &jdata->m_Y[offset], stride);
		}
	}

	// Cb
	ProcessHuffmanDataUnit(jdata, cCb);
	DecodeSingleBlock(&jdata->m_component_info[cCb], jdata->m_Cb, 8);

	// Cr
	ProcessHuffmanDataUnit(jdata, cCr);
	DecodeSingleBlock(&jdata->m_component_info[cCr], jdata->m_Cr, 8);
}

/***************************************************************************/

inline int JpegDecode(stJpegData *jdata)
{
	int x,y;

	int hFactor = jdata->m_component_info[cY].m_hFactor;
	int vFactor = jdata->m_component_info[cY].m_vFactor;

	// RGB24:
	if (jdata->m_rgb == NULL)
	{
		int h = jdata->m_height*3;
		int w = jdata->m_width*3;
		int height = h + (8*hFactor) - (h%(8*hFactor));
		int width  = w + (8*vFactor) - (w%(8*vFactor));

		//of implementation new in c language
		//no need for c++
		jdata->m_rgb = malloc(width * height);
		///////////////////////////////////

		//in c++
		//jdata->m_rgb = new unsigned char[width * height];

		memset(jdata->m_rgb, 0, width*height);
	}

	jdata->m_component_info[0].m_previousDC = 0;
	jdata->m_component_info[1].m_previousDC = 0;
	jdata->m_component_info[2].m_previousDC = 0;
	jdata->m_component_info[3].m_previousDC = 0;

	int xstride_by_mcu = 8*hFactor;
	int ystride_by_mcu = 8*vFactor;

	// Don't forget to that block can be either 8 or 16 lines
	unsigned int bytes_per_blocklines = jdata->m_width*3 * ystride_by_mcu;

	unsigned int bytes_per_mcu = 3*xstride_by_mcu;

	// Just the decode the image by 'macroblock' (size is 8x8, 8x16, or 16x16)
	for (y=0 ; y<(int)jdata->m_height; y+=ystride_by_mcu)
	{
		for (x=0; x<(int)jdata->m_width; x+=xstride_by_mcu)
		{
			jdata->m_colourspace = jdata->m_rgb + x*3 + (y *jdata->m_width*3);

			// Decode MCU Plane
			DecodeMCU(jdata, hFactor, vFactor );

			YCrCB_to_RGB24_Block8x8(jdata, hFactor, vFactor, x, y, jdata->m_width, jdata->m_height);
		}
	}


	return 0;
}

/***************************************************************************/
//
// Take Jpg data, i.e. jpg file read into memory, and decompress it to an
// array of rgb pixel values.
//
// Note - Memory is allocated for this function, so delete it when finished
//
/***************************************************************************/
int DecodeJpgFileData(const unsigned char* buf, // Jpg file in memory
					  const int sizeBuf,		// Size jpg in bytes in memory
					  unsigned char** rgbpix,	// Output rgb pixels
					  unsigned int* width,		// Output image width
					  unsigned int* height)		// Output image height
{
	// Allocate memory for our decoded jpg structure, all our data will be
	// decompressed and stored in here for the various stages of our jpeg decoding
	//c++
	//stJpegData* jdec = new stJpegData();
	//c
	stJpegData* jdec = malloc(191196);

	if (jdec == NULL)
	{
		dprintf("Not enough memory to alloc the structure need for decompressing\n");
		return 0;
	}

	// Start Parsing.....reading & storing data
	if (JpegParseHeader(jdec, buf, sizeBuf)<0)
	{
		dprintf("ERROR > parsing jpg header\n");
	}

	// We've read it all in, now start using it, to decompress and create rgb values
	dprintf("Decoding JPEG image...\n");
	JpegDecode(jdec);

	// Get the size of the image
	JpegGetImageSize(jdec, width, height);

	*rgbpix = jdec->m_rgb;

	// Release the memory for our jpeg decoder structure jdec
	//c++
	//delete jdec;

	// c
	free(jdec);	
		
	return 1;
}

/***************************************************************************/
//
// Load one jpeg image, and decompress it, and save the result.
//
/***************************************************************************/
int ConvertJpgFile(char* szJpgFileInName, char * szBmpFileOutName)
{
	FILE *fp;
	unsigned int lengthOfFile;
	unsigned char *buf;
	

	// Load the Jpeg into memory
	fp = fopen(szJpgFileInName, "rb");
	if (fp == NULL)
	{
		dprintf("Cannot open jpg file: %s\n", szJpgFileInName);
		return 0;
	}

	lengthOfFile = FileSize(fp);
	//c++
	//buf = new unsigned char[lengthOfFile + 4];
	//c
	buf=malloc((unsigned int)(lengthOfFile+4));
	if (buf == NULL)
	{
		dprintf("Not enough memory for loading file\n");
		return 0;
	}
	fread(buf, lengthOfFile, 1, fp);
	fclose(fp);

	unsigned char* rgbpix = NULL;
	unsigned int width  = 0;
	unsigned int height = 0;
	DecodeJpgFileData(buf, lengthOfFile, &rgbpix, &width, &height);

	if (rgbpix==NULL)
	{
		dprintf("Failed to decode jpg\n");
		return 0;
	}

	// Delete our data we read in from the file
	//c++
	//delete[] buf;
	//c
	free(buf);

	// Save it
	WriteBMP24(szBmpFileOutName, width, height, rgbpix);

	// Since we don't need the pixel information anymore, we must
	// release this as well
	//c++
//	delete[] rgbpix;
	//c
	free(rgbpix);

	return 1;
}

/***************************************************************************/

int main(){
	if (ConvertJpgFile("smiley.jpg","1.bmp"))
		printf("successful");
return 1;
}


你可能感兴趣的:(image,Stream,table,FP,Components,structure)