?? tonyjpegdecoder.cpp
字號:
/****************************************************************************
* Author: Dr. Tony Lin *
* Email: lintong@cis.pku.edu.cn *
* Release Date: Dec. 2002 *
* *
* Name: TonyJpegLib, rewritten from IJG codes *
* Source: IJG v.6a JPEG LIB *
* Purpose: Support real jpeg file, with readable code *
* *
* Acknowlegement: Thanks for great IJG, and Chris Losinger *
* *
* Legal Issues: (almost same as IJG with followings) *
* *
* 1. We don't promise that this software works. *
* 2. You can use this software for whatever you want. *
* You don't have to pay. *
* 3. You may not pretend that you wrote this software. If you use it *
* in a program, you must acknowledge somewhere. That is, please *
* metion IJG, and Me, Dr. Tony Lin. *
* *
*****************************************************************************/
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TonyJpegDecoder.h"
typedef enum { /* JPEG marker codes */
M_SOF0 = 0xc0,
M_SOF1 = 0xc1,
M_SOF2 = 0xc2,
M_SOF3 = 0xc3,
M_SOF5 = 0xc5,
M_SOF6 = 0xc6,
M_SOF7 = 0xc7,
M_JPG = 0xc8,
M_SOF9 = 0xc9,
M_SOF10 = 0xca,
M_SOF11 = 0xcb,
M_SOF13 = 0xcd,
M_SOF14 = 0xce,
M_SOF15 = 0xcf,
M_DHT = 0xc4,
M_DAC = 0xcc,
M_RST0 = 0xd0,
M_RST1 = 0xd1,
M_RST2 = 0xd2,
M_RST3 = 0xd3,
M_RST4 = 0xd4,
M_RST5 = 0xd5,
M_RST6 = 0xd6,
M_RST7 = 0xd7,
M_SOI = 0xd8,
M_EOI = 0xd9,
M_SOS = 0xda,
M_DQT = 0xdb,
M_DNL = 0xdc,
M_DRI = 0xdd,
M_DHP = 0xde,
M_EXP = 0xdf,
M_APP0 = 0xe0,
M_APP1 = 0xe1,
M_APP2 = 0xe2,
M_APP3 = 0xe3,
M_APP4 = 0xe4,
M_APP5 = 0xe5,
M_APP6 = 0xe6,
M_APP7 = 0xe7,
M_APP8 = 0xe8,
M_APP9 = 0xe9,
M_APP10 = 0xea,
M_APP11 = 0xeb,
M_APP12 = 0xec,
M_APP13 = 0xed,
M_APP14 = 0xee,
M_APP15 = 0xef,
M_JPG0 = 0xf0,
M_JPG13 = 0xfd,
M_COM = 0xfe,
M_TEM = 0x01,
M_ERROR = 0x100
} JPEG_MARKER;
/*
* jpeg_natural_order[i] is the natural-order position of the i'th
* element of zigzag order.
*
* When reading corrupted data, the Huffman decoders could attempt
* to reference an entry beyond the end of this array (if the decoded
* zero run length reaches past the end of the block). To prevent
* wild stores without adding an inner-loop test, we put some extra
* "63"s after the real entries. This will cause the extra coefficient
* to be stored in location 63 of the block, not somewhere random.
* The worst case would be a run-length of 15, which means we need 16
* fake entries.
*/
static const int jpeg_natural_order[64+16] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63,
63, 63, 63, 63, 63, 63, 63, 63,//extra entries for safety
63, 63, 63, 63, 63, 63, 63, 63
};
#define INPUT_2BYTES(src) (unsigned short)(((*src)<<8)+(*(src+1)));src+=2;
/*
unsigned short INPUT_2BYTES(unsigned char *src)
{
unsigned short tmp = (*src++)<<8; // Can not use:(((*src++)<<8) + (*src++))
tmp += (*src++);
return tmp;
}*/
#define INPUT_BYTE(src) (unsigned char)(*src++)
////////////////////////////////////////////////////////////////////////////////
CTonyJpegDecoder::CTonyJpegDecoder( )
{
}
CTonyJpegDecoder::~CTonyJpegDecoder( )
{
}
////////////////////////////////////////////////////////////////////////////////
bool CTonyJpegDecoder::ReadJpgHeader(
unsigned char *pInBuf, //in, source data, in jpg format
int cbInBuf, //in, count bytes for in buffer
int& nWidth, //out, image width in pixels
int& nHeight, //out, image height
int& nHeadSize //out, header size in bytes
)
{
// Step 1:
if( read_markers( pInBuf, cbInBuf, nWidth, nHeight, nHeadSize )==-1 )
{
AfxMessageBox("Can not read the file header");
return false;
}
if(( m_nWidth <= 0 )||( m_nHeight <= 0 ))
return false;
m_nDataBytesLeft = cbInBuf - nHeadSize;
// Step 2: Prepare for decoding here
InitDecoder( );
return true;
}
////////////////////////////////////////////////////////////////////////////////
// read exact marker, two bytes, no stuffing allowed
int CTonyJpegDecoder::ReadOneMarker(void)
{
if( INPUT_BYTE(m_pData) != 255 )
return -1;
int marker = INPUT_BYTE(m_pData);
return marker;
}
////////////////////////////////////////////////////////////////////////////////
// Skip over an unknown or uninteresting variable-length marker
void CTonyJpegDecoder::SkipMarker(void)
{
int length = (int)INPUT_2BYTES(m_pData);
// Just skip; who care what info is?
m_pData += length - 2;
}
////////////////////////////////////////////////////////////////////////////////
void CTonyJpegDecoder::GetDqt( void )
{
int length;
length = (int)INPUT_2BYTES(m_pData);
length -= 2;
unsigned short *qtb;
int n, prec, i;
while (length > 0)
{
n = INPUT_BYTE(m_pData);
length --;
prec = n >> 4;
n &= 0x0F;//dqt for Y, or Cb/Cr?
if( n == 0 )
qtb = m_qtblY;
else
qtb = m_qtblCbCr;
for (i = 0; i < 64; i++)
{
qtb[jpeg_natural_order[i]] = INPUT_BYTE(m_pData);
}
length -= 64;
}
}
////////////////////////////////////////////////////////////////////////////////
// get width and height, and component info
void CTonyJpegDecoder::get_sof (bool is_prog, bool is_arith)
{
int length = (int)INPUT_2BYTES(m_pData);
m_nPrecision = (int)INPUT_BYTE(m_pData);//1 byte
m_nHeight = (unsigned short)INPUT_2BYTES(m_pData);
m_nWidth = (unsigned short)INPUT_2BYTES(m_pData);
m_nComponent = (int)INPUT_BYTE(m_pData);//1 byte
length -= 8;
jpeg_component_info *compptr;
compptr = comp_info;
int ci, c;
for (ci = 0; ci < m_nComponent; ci++)
{
compptr->component_index = ci;
compptr->component_id = (int)INPUT_BYTE(m_pData);//1 byte
c = (int)INPUT_BYTE(m_pData);//1 byte
compptr->h_samp_factor = (c >> 4) & 15;
compptr->v_samp_factor = (c ) & 15;
if(( ci==0 )&&( c!=34 ))
{
char info[100];
sprintf(info, "comp 0 samp_factor = %d", c );
AfxMessageBox(info);
}
compptr->quant_tbl_no = (int)INPUT_BYTE(m_pData);//1 byte
compptr++;
}
if( ( comp_info[0].h_samp_factor == 1 )&&
( comp_info[0].v_samp_factor == 1 ))
{
m_nMcuSize = 8;
m_nBlocksInMcu = 3;
}
else
{
m_nMcuSize = 16;//default
m_nBlocksInMcu = 6;
}
}
///////////////////////////////////////////////////////////////////////////////
void CTonyJpegDecoder::get_dht(void)
{
int length = (int)INPUT_2BYTES(m_pData);
length -= 2;
while(length>0)
{
//0:dc_huff_tbl[0]; 16:ac_huff_tbl[0];
//1:dc_huff_tbl[1]; 17:ac_huff_tbl[1]
int index = INPUT_BYTE(m_pData);
// decide which table to receive data
HUFFTABLE* htblptr;
switch(index){
case 0:
htblptr = &m_htblYDC;
break;
case 16:
htblptr = &m_htblYAC;
break;
case 1:
htblptr = &m_htblCbCrDC;
break;
case 17:
htblptr = &m_htblCbCrAC;
break;
}
int count, i;
//
// read in bits[]
//
htblptr->bits[0] = 0;
count = 0;
for (i = 1; i <= 16; i++) {
htblptr->bits[i] = INPUT_BYTE(m_pData);
count += htblptr->bits[i];
}
length -= (1 + 16);
//
// read in huffval
//
for (i = 0; i < count; i++){
htblptr->huffval[i] = INPUT_BYTE(m_pData);
}
length -= count;
}
}
///////////////////////////////////////////////////////////////////////////////
void CTonyJpegDecoder::get_sos(void)
{
int length = (int)INPUT_2BYTES(m_pData);
int n = INPUT_BYTE(m_pData);// Number of components
// Collect the component-spec parameters
int i, cc, c, ci=0;
for (i = 0; i < n; i++)
{
cc = INPUT_BYTE(m_pData);
c = INPUT_BYTE(m_pData);
// find the match comp_id; Current we do nothing
// if cc=1,c=0: showing comp 1 will use tbl 0
// if cc=2,c=17: showing comp 2 will use tbl 1
// if cc=3,c=17: showing comp 3 will use tbl 1
/*
for ( ci = 0, compptr = cinfo->comp_info;
ci < cinfo->num_components;
ci++, compptr++)
{
if (cc == compptr->component_id)
{
cinfo->cur_comp_info[i] = compptr;
compptr->dc_tbl_no = (c >> 4) & 15;
compptr->ac_tbl_no = (c ) & 15;
break;
}
}
*/
// ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
}
// Collect the additional scan parameters Ss, Se, Ah/Al.
int Ss, Se, Ah, Al;
Ss = INPUT_BYTE(m_pData);
Se = INPUT_BYTE(m_pData);
c = INPUT_BYTE(m_pData);
Ah = (c >> 4) & 15;
Al = (c ) & 15;
next_restart_num = 0;
}
////////////////////////////////////////////////////////////////////////////////
void CTonyJpegDecoder::get_dri()
{
int length = (int)INPUT_2BYTES(m_pData);
restart_interval = INPUT_2BYTES(m_pData);
restarts_to_go = restart_interval;
char info[100];
sprintf(info, "restart_interval=%d", restart_interval );
AfxMessageBox(info);
}
////////////////////////////////////////////////////////////////////////////////
//return: -1, error; 0, SOS, start of scan; 1: EOI, end of image
int CTonyJpegDecoder::read_markers (
unsigned char *pInBuf, //in, source data, in jpg format
int cbInBuf, //in, count bytes for in buffer
int& nWidth, //out, image width in pixels
int& nHeight, //out, image height
int& nHeadSize //out, header size in bytes
)
{
m_pData = pInBuf;
int retval = -1;
for (;;)
{
// IJG use first_marker() and next_marker()
int marker = ReadOneMarker();
// read more info according to the marker
// the order of cases is in jpg file made by ms paint
switch (marker)
{
case M_SOI:
// if (! get_soi(cinfo))
// return -1;//JPEG_SUSPENDED;
break;
case M_APP0:
case M_APP1:
case M_APP2:
case M_APP3:
case M_APP4:
case M_APP5:
case M_APP6:
case M_APP7:
case M_APP8:
case M_APP9:
case M_APP10:
case M_APP11:
case M_APP12:
case M_APP13:
case M_APP14:
case M_APP15:
SkipMarker();//JFIF APP0 marker, or Adobe APP14 marker
break;
case M_DQT:// maybe twice, one for Y, another for Cb/Cr
GetDqt();
break;
case M_SOF0: //* Baseline
case M_SOF1: //* Extended sequential, Huffman
get_sof(false, false);
break;
case M_SOF2: //* Progressive, Huffman
//get_sof(true, false);
AfxMessageBox("Prog + Huff is not supported");
return -1;
break;
case M_SOF9: //* Extended sequential, arithmetic
//get_sof(false, true);
AfxMessageBox("sequential + Arith is not supported");
return -1;
break;
case M_SOF10: //* Progressive, arithmetic
//get_sof(true, true);
AfxMessageBox("Prog + Arith is not supported");
return -1;
break;
case M_DHT:
get_dht();//4 tables: dc/ac * Y/CbCr
break;
case M_SOS://Start of Scan
get_sos();
retval = 0;//JPEG_REACHED_SOS;
nWidth = m_nWidth;
nHeight = m_nHeight;
nHeadSize = m_pData - pInBuf;
return retval;
break;
//the following marker are not needed for jpg made by ms paint
case M_COM:
SkipMarker();
break;
case M_DRI:
get_dri();
break;
/*
//* Currently unsupported SOFn types
case M_SOF3: //* Lossless, Huffman
case M_SOF5: //* Differential sequential, Huffman
case M_SOF6: //* Differential progressive, Huffman
case M_SOF7: //* Differential lossless, Huffman
case M_JPG: //* Reserved for JPEG extensions
case M_SOF11: //* Lossless, arithmetic
case M_SOF13: //* Differential sequential, arithmetic
case M_SOF14: //* Differential progressive, arithmetic
case M_SOF15: //* Differential lossless, arithmetic
return -1;//ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
break;
case M_EOI:
TRACEMS(cinfo, 1, JTRC_EOI);
cinfo->unread_marker = 0; //* processed the marker
return 1;//JPEG_REACHED_EOI;
case M_DAC:
if (! get_dac(cinfo))
return -1;//JPEG_SUSPENDED;
break;
case M_RST0: //* these are all parameterless
case M_RST1:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -