📄 jpgdecoder.~cpp
字号:
//
// 标题: JPEG解码器类实现
//
#include <iostream>
#include <climits>
#include "jpgdecoder.h"
#include "jfif.h"
#include "jpghuffmandecoder.h"
#include "bitmapimage.h"
#include "jpgdecoderquantization.h"
#include "jpgdecodercomponent.h"
#include "jpginputfilestream.h"
#include "jpginputmapstream.h"
#include "vcl.h"
#include "jpgcoefficient.h"
using namespace std ;
using namespace ColosseumPrivate ;
namespace Colosseum
{
//
// 描述:
//
// 类缺省构造函数
//
JpegDecoder::JpegDecoder ()
{
initialize () ;
return ;
}
//
// 描述:
//
// 类复制构造函数
//
JpegDecoder::JpegDecoder (const JpegDecoder &source)
{
initialize () ;
doCopy (source) ;
return ;
}
//
// 描述:
//
// 类析构函数
//
JpegDecoder::~JpegDecoder ()
{
delete [] ac_tables ; ac_tables = 0 ;
delete [] dc_tables ; dc_tables = 0 ;
delete [] quantization_tables ; quantization_tables = 0 ;
delete [] components ; components = 0 ;
delete [] component_indices ; component_indices = 0 ;
delete [] scan_components ; scan_components = 0 ;
return ;
}
//
// 描述:
// 赋值
//
JpegDecoder &JpegDecoder::operator=(const JpegDecoder &source)
{
doCopy (source) ;
return *this ;
}
//
// 描述:
//
// 类初始化
//
void JpegDecoder::initialize ()
{
verbose_flag = false ;
strict_jfif = false ;
processing_image = false ;
ac_tables = new JpegHuffmanDecoder [JPEGMAXHUFFMANTABLES] ;
dc_tables = new JpegHuffmanDecoder [JPEGMAXHUFFMANTABLES] ;
quantization_tables = new JpegDecoderQuantizationTable [JPEGMAXQUANTIZATIONTABLES] ;
components = new JpegDecoderComponent [JPEGMAXCOMPONENTSPERFRAME] ;
component_indices = new unsigned int [JPEGMAXCOMPONENTSPERFRAME] ;
scan_components = new JpegDecoderComponent * [JPEGMAXCOMPONENTSPERFRAME] ;
use_filters = false ;
return ;
}
//
// 描述:
//
// 复制函数
//
void JpegDecoder::doCopy (const JpegDecoder &source)
{
verbose_flag = source.verbose_flag ;
strict_jfif = source.strict_jfif ;
BitmapImageCoder::operator=(source) ;
return ;
}
//
// 描述:
//
// 读JPEG文件开头的SOI标记和JFIF APP0标记
//
// APP0在SIO标记之后,可能中间插入COM标记
//
void JpegDecoder::readStreamHeader (JpegInputStream &inputstream)
{
if (inputstream.getByte () != SOB)
throw JpegBadStream ("Missing SOI Marker") ;
if (inputstream.getByte () != SOI)
throw JpegBadStream ("Missing SOI Marker") ;
if (inputstream.getByte () != SOB)
throw JpegBadStream ("Missing JFIF APP0 Marker") ;
if (inputstream.getByte () != APP0)
throw JpegBadStream ("Missing JFIF APP0 Marker") ;
JfifHeader header ;
inputstream.read (reinterpret_cast<char*>(&header), sizeof (header)) ;
if (memcmp ("JFIF", reinterpret_cast<char *>(header.identifier), 4) != 0)
throw JpegBadStream ("Not a JFIF file") ;
if (verbose_flag)
{
cout << "{ Start Of Image }" << endl ;
cout << "{ JFIF APP0 Marker" << endl ;
cout << " Length: " << dec << BigEndianToSystem (header.length) << endl ;
cout << " Version: " << dec << (unsigned int) header.version [0]
<< "." << (unsigned int) header.version [0] << endl ;
// density unit = 0 => Only the aspect ratio is specified.
// density unit = 1 => Density in pixels per inch.
// density unit = 2 => Density in pixels per centimeter.
cout << " Density Unit: " ;
switch (header.units)
{
case 0: cout << " (aspect ratio)" << endl ; break ;
case 1: cout << " (pixels per inch)" << endl ; break ;
case 2: cout << " (pixels/cm)" << endl ; break ;
default: cout << " (????)" << endl ; break ;
}
cout << " X Density: " << dec << BigEndianToSystem (header.xdensity) << endl ;
cout << " Y Density: " << dec << BigEndianToSystem (header.xdensity) << endl ;
cout << " Thumbnail Width: " << dec << (unsigned int) header.xthumbnail << endl ;
cout << " Thumbnail Height: " << dec << (unsigned int) header.xthumbnail << endl ;
cout << "}" << endl ;
}
// Skip over any thumbnail data.
for (int ii = sizeof (header) ; ii < BigEndianToSystem (header.length) ; ++ ii)
inputstream.getByte () ;
return ;
}
//
// 描述:
//
// 读下一个标记
//
void JpegDecoder::readMarker (JpegInputStream &inputstream)
{
while (inputstream.moreData ())
{
UBYTE1 type = inputstream.getByte () ;
switch (type)
{
case SOB:
// According to E.1.2, 0xFF is allowed as fill when a
// marker is expected.
break ;
case SOI:
if (verbose_flag)
cout << "{ Start Of Image }" << endl ;
return ; // SOI has no data.
case DQT:
readQuantization (inputstream) ;
return ;
case DHP:
throw JpegBadStream ("DHP marker not supported") ;
// The only difference between a Sequential DCT Frame
// (SOF0) and an extended Sequential DCT Frame (SOF1)
// is that a baseline frame may only have 2 DC and 2 AC
// Huffman tables per scan (F.1.2) and and extended
// Sequential Frame may have up to 4 DC and 4 AC Huffman
// tables per scan (F.1.3). Both are decoded identically
// for 8-bit precision. Extended Sequential frames may
// use 12-bit precision (F, Table B.2) which we do not
// support.
case SOF0:
case SOF1:
case SOF2:
readStartOfFrame (inputstream, type) ;
return ;
case SOF3:
throw JpegBadStream ("Lossless Huffman Coding Not Supported") ;
case SOF5:
throw JpegBadStream (
"Differential Sequential Huffman Coding Not Supported") ;
case SOF6:
throw JpegBadStream (
"Differential Progressive Huffman Coding Not Supported") ;
case SOF7:
throw JpegBadStream (
"Differential Lossless Huffman Coding Not Supported") ;
// These are markers for frames using arithmetic coding.
// Arithmetic coding is covered by patents so we ignore
// this type.
case SOF9:
case SOFA:
case SOFB:
case SOFD:
case SOFE:
case SOFF:
throw JpegBadStream (
"Cannot read image - Arithmetic Coding covered by patents") ;
case DHT:
readHuffmanTable (inputstream) ;
return ;
case SOS:
readStartOfScan (inputstream) ;
return ;
case DRI:
readRestartInterval (inputstream) ;
return ;
case EOI:
eoi_found = true ;
if (verbose_flag)
cout << "{ End Of Image }" << endl ;
return ; // End of Image marker has no data
case APP0:
case APP1:
case APP2:
case APP3:
case APP4:
case APP5:
case APP6:
case APP7:
case APP8:
case APP9:
case APPA:
case APPB:
case APPC:
case APPD:
case APPE:
case APPF:
case COM:
readApplication (type, inputstream) ;
return ;
default:
// We call ReadByte to make sure the problem
// is not a premature EOF.
inputstream.getByte () ;
throw JpegBadStream (
"Unknown, unsupported, or reserved marker encountered") ;
}
}
throw JpegBadStream ("Premature end of file") ;
}
//
// 描述:
//
// 读应用和注释标记
//
//
// 参数:
// type: 标记类型
//
void JpegDecoder::readApplication (UBYTE1 type, JpegInputStream &inputstream)
{
unsigned int length = inputstream.getBigEndianWord () ;
char id [512] ;
int ii = 0 ;
id [ii] = inputstream.getByte () ;
for (ii = 1 ; id [ii - 1] != '\000'
&& ii < sizeof (id)
&& ii < length - sizeof (UBYTE2) ; ++ ii)
{
id [ii] = inputstream.getByte () ;
}
for ( ; ii < length - sizeof (UBYTE2) ; ++ ii)
(void) inputstream.getByte () ;
if (verbose_flag)
{
if (type == COM)
cout << "( Comment Marker" << endl ;
else
cout << "{ APP" << hex << (UBYTE2) (type & 0x0F) << " Marker" << endl ;
cout << "Length: " << dec << length << endl ;
cout << "ID: " << id << endl ;
cout << "}" << endl ;
}
return ;
}
//
// 描述:
//
// 读 a Define Huffman Table标记
//
void JpegDecoder::readHuffmanTable (JpegInputStream &inputstream)
{
// Section B.2.4.2
if (verbose_flag)
cout << "{ Define Huffman Table" << endl ;
UBYTE2 length = inputstream.getBigEndianWord () ;
unsigned int remaining = length - sizeof (length) ;
while (remaining > 0)
{
UBYTE1 data = inputstream.getByte () ; -- remaining ;
// Tc in standard 0=>DC, 1=>AC
unsigned int tableclass = data >> 4 ;
unsigned int id = data & 0x0F ; // Th in standard
if (id > 3)
{
throw JpegBadStream (
"Huffman Table Index outside range [0..3]") ;
}
if (verbose_flag)
{
cout << " Table Index " << (int) id << endl ;
if (tableclass == 0)
cout << " Table Class: DC" << endl ;
else
cout << " Table Class: AC" << endl ;
}
if (id > 3)
{
cout << "Bad index " << id << endl ;
return ;
}
JpegHuffmanDecoder *table ;
if (tableclass != 0)
table = &ac_tables [id] ;
else
table = &dc_tables [id] ;
// Read the table data into the table object
remaining -= table->readTable (inputstream) ;
if (verbose_flag)
{
table->printOn (cout) ;
}
}
if (verbose_flag)
cout << "}" << endl ;
return ;
}
//
// 描述:
//
// 读DQT标记
//
void JpegDecoder::readQuantization (JpegInputStream &inputstream)
{
// Defined in Section B.2.4.1
UBYTE2 length = inputstream.getBigEndianWord () ;
UBYTE1 data ;
// Maintain a counter for the number of bytes remaining to be read in
// the quantization table.
int remaining = length - sizeof (length) ;
if (verbose_flag)
{
cout << "{ Define Quantization Table" << endl ;
cout << " Length: " << length << endl ;
}
while (remaining > 0)
{
data = inputstream.getByte () ; -- remaining ;
unsigned int precision = data >> 4 ; // Pq in standard
unsigned int index = data & 0x0F ; // Tq in standard
if (index >= JPEGMAXQUANTIZATIONTABLES)
throw JpegBadStream ("Quantization Table Index Too Large") ;
if (verbose_flag)
{
cout << " Table Index: " << dec << index << endl ;
cout << " Table Precision: " << dec << precision << endl ;
}
switch (precision)
{
case 1:
remaining -= sizeof(UBYTE2) * JPEGSAMPLESIZE ;
break ;
case 0:
remaining -= sizeof (UBYTE1) * JPEGSAMPLESIZE ;
break ;
}
// Read the table data into the table object
quantization_tables [index].readTable (inputstream, precision) ;
int c[64];
quantization_tables [index].printOnArray(c);
if (verbose_flag)
{
cout << " Table Values: " ;
quantization_tables [index].printOn (cout) ;
cout << endl << "}" << endl ;
}
}
return ;
}
//
// 描述:
//
// 读重启间隔标记
//
void JpegDecoder::readRestartInterval (JpegInputStream &inputstream)
{
// Section B.2.4.4
UBYTE2 length = inputstream.getBigEndianWord () ;
restart_interval = inputstream.getBigEndianWord () ;
if (verbose_flag)
{
cout << "{ Define Restart Interval" << endl ;
cout << " Length: " << dec << length << endl ; // Should be 4
cout << " Interval: " << dec << restart_interval << endl ;
cout << "}" << endl ;
}
return ;
}
//
// 描述:
//
// 读SOF标记
//
// 参数:
// type: 帧的标记类型
//
void JpegDecoder::readStartOfFrame (JpegInputStream &inputstream, UBYTE1 type)
{
if (type == SOF2)
progressive_frame = true ;
else
progressive_frame = false ;
// Section B.2.2
// Read in the image dimensions
unsigned int length = inputstream.getBigEndianWord () ;
unsigned int dataprecision = inputstream.getByte () ; // P in standard
if (dataprecision != 8)
throw JpegBadStream ("Only 8-bit data supported") ;
frame_height = inputstream.getBigEndianWord () ; // Y in standard
frame_width = inputstream.getBigEndianWord () ; // X in standard
component_count = inputstream.getByte () ; // Nf in standard
// JFIF only allows 1 or 3 components.
if (component_count != 1 && component_count != 3)
throw JpegBadStream ("JFIF only supports 1 and 3 component streams") ;
frame_type = type ;
if (verbose_flag)
{
cout << "{ Start Of Frame " << endl ;
cout << " Length: " << dec << length << endl ;
cout << " Precision: " << dec << dataprecision << endl ;
cout << " Height: " << dec << frame_height << endl ;
cout << " Width: " << dec << frame_width << endl ;
cout << " Component Count: " << component_count << endl ;
}
if (length != (component_count * 3 + 8))
throw JpegBadStream ("Invalid Frame Size") ;
// Rread the component descriptions
max_horizontal_frequency = 0 ;
max_vertical_frequency = 0 ;
for (unsigned int ii = 0 ; ii < component_count ; ++ ii)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -