- 浏览: 1236808 次
文章分类
最新评论
JPEG File Format
JPEG File Format Get mor data for your byte... |
Jpeg (.jpg) Image Source Decoder
by bkenwright@xbdev.net
Well I don't usually like dumping large pieces of source code, but sometimes it nice to just scroll through other peoples code...especially when its colour coded...so you can see how I read in the bits, or how I performed the Inverse Discrete Cosine.
The whole jpeg decode source code is in a single .cpp, and decompresses simple jpegs....it doesn't include progressive jpegs...works for most cases, and can be used to decode the flash .swf embeded jpegs which is what I used it for :)
The demo source code decompresses the jpg file, and exports a bmp file. It also writes out debug information about the file, such as the huffman tables, IDCT values, width height etc etc...to a txt file called output.txt which you can look at. |
Download Full Source Code Compiles with Visual Studio (Win32) |
Jpeg Decode Demo Source Code |
/***************************************************************************/ /* */ /* File: loadjpg.cpp */ /* Author: bkenwright@xbdev.net */ /* 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(..) extern void dprintf(const char *fmt, ...); /* __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, }; /***************************************************************************/ struct stBlock { int value; // Decodes to. int length; // Length in bits. unsigned short int code; // 2 byte code (variable length) }; /***************************************************************************/ struct stHuffmanTable { 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]; }; struct stComponent { 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; }; struct stJpegData { 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; }; /***************************************************************************/ // // 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; for(int 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; for( int u=0; u<8; u++) { for(int 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]) { for(int y=0; y<8; y++) { for(int x=0; x<8; x++) { outBlock[x][y] = func( x, y, inBlock); } } } /***************************************************************************/ void DequantizeBlock( int block[64], const float quantBlock[64] ) { for( int c=0; c<64; c++) { block[c] = (int)(block[c] * quantBlock[c]); } } /***************************************************************************/ void DeZigZag(int outBlock[64], const int inBlock[64]) { for(int i=0; i<64; i++) { outBlock[ i ] = inBlock[ZigZagArray[i]]; } } /***************************************************************************/ void TransformArray(int outArray[8][8], const int inArray[64]) { int cc = 0; for( int y=0; y<8; y++) { for( int x=0; x<8; x++) { outArray[x][y] = inArray[cc]; cc++; } } } /***************************************************************************/ void DumpDecodedBlock(int val[8][8]) { dprintf("# Decoded 8x8 Block#\n"); for( int y=0; y<8; y++) { for( int 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; // Create a temp 8x8, i.e. 64 array for the data int data[64] = {0}; // Copy our data into the temp array for (int 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 (int y = 0; y < 8; y++) { for (int 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) struct stBMFH // 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 }; #pragma pack() // 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 (int y=Height-1; y>=0; y--) { for (int 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) { for (int j=1; j<=16; j++) { HT->m_length[j] = bits[j]; } // Work out the total number of codes int numBlocks = 0; for (int 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 (int i=1; i<=16; i++) { for (int 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]; stream += 8; for (int 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; for (int i=0; i<8; i++) { for (int 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]; dprintf("> SOS marker\n"); if (nr_components != 3) { dprintf("Error - We only support YCbCr image\n"); } stream += 3; for (unsigned int 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) { for (int 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) { for (int i=0; i<32; i++) g_bigBuf[i]='\0'; int c = 0; for (int 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) { dprintf("HufCodes\n"); dprintf("Num: %d\n", table->m_numBlocks); for (int 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]) { dprintf("\n#Extracted DCT values from SOS#\n"); int c = 0; for (int 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; // 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 (int 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) ) { int 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 (int 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 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 (int y=0; y<(8*h - olh); y++) { for (int 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) { // Y for (int y=0; y<h; y++) { for (int 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 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)); 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 (int y=0 ; y<(int)jdata->m_height; y+=ystride_by_mcu) { for (int 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 stJpegData* jdec = new stJpegData(); 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 delete 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); buf = new unsigned char[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 delete[] buf; // Save it WriteBMP24(szBmpFileOutName, width, height, rgbpix); // Since we don't need the pixel information anymore, we must // release this as well delete[] rgbpix; return 1; } /***************************************************************************/ |
相关推荐
JPEG file format.pdf需要大于20个字符,不支持HTML标签。
JPEG File Interchange FormatJPEG File Interchange Format
JPEG文件交换格式官方文档,详细介绍了JFIF文件格式的特征,RGB到YCbCr的转换,图像取向,图像分量的空间关系,以及JFIF的语法组成等。
JPEG, PNG, GIF, XBM, BMP
本节主要介绍JPEG图像压缩编码算法(DCT变换算法)、图像数据文件格式 (JFIF,JPEG File Interchange Format)。最后,对JPEG 2000进行一个简单的介绍
(TIFF = Tagged Image File Format.) The TIFF file format is a widely accepted standard, supported by many applications on a wide range of platforms due to its capabilities and flexibility. Please see ...
Definition of a MPO file in Wikipedia : Also known as a Multi-Picture Object or Multi-Picture Format, the MPO file format was first used in the FinePix REAL 3D W1 camera, made by FujiFilm. The format ...
1 Introduction to Data Compression 2 Source Coding Algorithms 3 JPEG: Still Image ...8 Code-Stream Organization and File Format 9 VLSI Architectures for JPEG2000 10 Beyond Part 1 of JPEG2000 Standard
for user friendly interfaces based on Zinc Application Framework, multidimensional trees in the internal data structure for the fast and accurate file parsing and rendering, Independent JPEG Group's ...
例如,常见的 BMP(Bitmap)、 TIFF( Tagged Image File Format)、 PNG(Portable Network Graphics)均支持光栅格式与调色板格式编码,对这两种格式 编码分别又支持多种具体编码方法 LSB 隐写算法 --- • LSB ...
It is the Photoshop File Format Encode/Decode Library. It supports for Adobe Photoshop CS4 version, and is compatible with the previous versions of Photoshop. run-time lib is:MultiThread DLL, debug ...
Dropbox 开源的超强无损压缩算法,比 JPEG 平均节省 22% 的存储空间.zip,Lepton is a tool and file format for losslessly compressing JPEGs by an average of 22%.
Source images can be imported into DjVuer directly from a TWAIN scanner, or loaded from common file formats such as JPEG files and Windows bitmap files. These images can then be converted and saved as...
Compressed file format for minimizing drawing file size Advanced pocket calculator with equation solver MeeSoft Image Analyzer integration for bitmap image editing and extended file format support -...
* Extensive support for working with the JP2 file format. The "kdu_show" application demonstrates the capabilities required of a conformant JP2 reader: palette mapping; interpolation of components ...
获取USB摄像头的1080p的JPEG格式的图片20180608_1806.7z 电脑上的系统:ubuntu14.04 // http://www.linuxidc.com/Linux/2011-03/33020.htm // V4L2摄像头获取单幅图片测试程序(MMAP模式) // [日期:2011-03-06] ...
_picture = Image.FromFile(filePath); } #endregion #region -- Public methods -- /// /// This method returns EXIF property values. /// /// <param name="exifCode">EXIF property to be returned....
例如,常见的BMP(Bitmap)、 TIFF( Tagged Image File Format)、 PNG(Portable Network Graphics)均支持光栅格式与调色板格式编码,对这两种格式 编码分别又支持多种具体编码方法 LSB隐写算法 LSB隐写是最基础...
TIFF格式也叫TIF,属于位图格式,全名是Tag Image File Format。TIFF格式和JPEG及PNG都是属于一种主流且高位彩色图像格式。使用过扫描仪或传真的小伙伴应该还记得,很多品牌及其默认文件就是.tiff后缀。因为TIFF最初...