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; }