📄 jpegdeco.cpp
字号:
//
// Copyright (c) 1997,1998 Colosseum Builders, Inc.
// All rights reserved.
//
// Colosseum Builders, Inc. makes no warranty, expressed or implied
// with regards to this software. It is provided as is.
//
// See the README.TXT file that came with this software for restrictions
// on the use and redistribution of this file or send E-mail to
// info@colosseumbuilders.com
//
//
// JPEG Decoder Class Implementation
//
// Author: John M. Miano miano@colosseumbuilders.com
//
#include <iostream>
#include "jpegdeco.h"
#include "jfif.h"
#include "jpdehuff.h"
#include "bitimage.h"
#include "jpdequan.h"
#include "jpdecomp.h"
#include <limits.h>
using namespace std ;
//
// Description:
//
// Class Default Constructor
//
JpegDecoder::JpegDecoder ()
{
Initialize () ;
return ;
}
//
// Description:
//
// Class copy constructor
//
JpegDecoder::JpegDecoder (const JpegDecoder &source)
{
Initialize () ;
DoCopy (source) ;
return ;
}
//
// Description:
//
// Class Destructor
//
JpegDecoder::~JpegDecoder ()
{
delete [] ac_tables ; ac_tables = NULL ;
delete [] dc_tables ; dc_tables = NULL ;
delete [] quantization_tables ; quantization_tables = NULL ;
delete [] components ; components = NULL ;
delete [] component_indices ; component_indices = NULL ;
delete [] scan_components ; scan_components = NULL ;
return ;
}
//
// Description:
//
JpegDecoder &JpegDecoder::operator=(const JpegDecoder &source)
{
DoCopy (source) ;
return *this ;
}
//
// Description:
//
// Class initialization procudure for use by constructors.
//
void JpegDecoder::Initialize ()
{
verbose_flag = false ;
strict_jfif = false ;
ac_tables = new JpegHuffmanDecoder [JpegMaxHuffmanTables] ;
dc_tables = new JpegHuffmanDecoder [JpegMaxHuffmanTables] ;
quantization_tables = new JpegDecoderQuantizationTable [MaxQuantizationTables] ;
components = new JpegDecoderComponent [JpegMaxComponentsPerFrame] ;
component_indices = new unsigned int [JpegMaxComponentsPerFrame] ;
scan_components = new JpegDecoderComponent * [JpegMaxComponentsPerScan] ;
return ;
}
//
// Description:
//
// Copy function. This function is called by the assignment operator
// and copy constructor to copy the state of one object to another.
// we only copy user configurable parameters. We do not support
// copying while a decode operation is in progress.
//
void JpegDecoder::DoCopy (const JpegDecoder &source)
{
verbose_flag = source.verbose_flag ;
strict_jfif = source.strict_jfif ;
BitmapImageCoder::operator=(source) ;
return ;
}
//
// Description:
//
// This function returns the next byte from the input stream.
//
UBYTE1 JpegDecoder::ReadByte ()
{
UBYTE1 value ;
input_stream->read ((char *) &value, sizeof (value)) ;
bit_position = 0 ;
if (input_stream->eof ())
throw EJpegBadData ("Premature end of file") ;
return value ;
}
//
// Description:
//
// This function reads the next 2-byte integer from the input stream
// and returns the value in the correct format for the system.
//
UBYTE2 JpegDecoder::ReadWord ()
{
bit_position = 0 ;
UBYTE2 value ;
input_stream->read ((char *) &value, sizeof (value)) ;
return BigEndianToSystem (value) ;
}
//
// Description:
//
// Section F.2.2.4
//
// Extracts the next "count" bits from the input stream.
//
int JpegDecoder::Receive (unsigned int count)
{
int result = 0 ;
for (unsigned int ii = 0 ; ii < count ; ++ii)
{
result <<= 1 ;
result |= NextBit () ;
}
return result ;
}
//
// Description:
//
// This function reads the Start of Image Marker and the JFIF APP0
// marker that begin a JPEG file.
//
// The JFIF standard states "The JPEG FIF APP0 marker is mandatory
// right after the SOI marker."
//
// I have come across some JPEG files that have a COM marker between
// the SOI marker and APP0. This code will reject these non-conforming
// files.
//
void JpegDecoder::ReadStreamHeader ()
{
if (ReadByte () != SOB)
throw EJpegBadData ("Missing SOI Marker") ;
if (ReadByte () != SOI)
throw EJpegBadData ("Missing SOI Marker") ;
if (ReadByte () != SOB)
throw EJpegBadData ("Missing JFIF APP0 Marker") ;
if (ReadByte () != APP0)
throw EJpegBadData ("Missing JFIF APP0 Marker") ;
JfifHeader header ;
input_stream->read ((char *) &header, sizeof (header)) ;
if (memcmp ("JFIF", (char *) header.identifier, 4) != 0)
throw EJpegBadData ("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)
(void) ReadByte () ;
return ;
}
//
// Description:
//
// This function reads the next marker in the input
// stream. If the marker is followed by a data block
// this function dispatches a routine to read the
// data.
//
void JpegDecoder::ReadMarker ()
{
while (! input_stream->eof ())
{
UBYTE1 type = ReadByte () ;
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 () ;
return ;
case DHP:
throw EJpegBadData ("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:
ReadStartOfFrame (type) ;
return ;
case SOF2:
throw EJpegBadData ("Progressive JPEG Not Supported") ;
case SOF3:
throw EJpegBadData ("Lossless Huffman Coding Not Supported") ;
case SOF5:
throw EJpegBadData (
"Differential Sequential Huffman Coding Not Supported") ;
case SOF6:
throw EJpegBadData (
"Differential Progressive Huffman Coding Not Supported") ;
case SOF7:
throw EJpegBadData (
"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 EJpegBadData (
"Cannot read image - Arithmetic Coding covered by patents") ;
case DHT:
ReadHuffmanTable () ;
return ;
case SOS:
ReadStartOfScan () ;
return ;
case DRI:
ReadRestartInterval () ;
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) ;
return ;
default:
// We call ReadByte to make sure the problem
// is not a premature EOF.
(void) ReadByte () ;
throw EJpegBadData (
"Unknown, unsupported, or reserved marker encountered") ;
}
}
throw EJpegBadData ("Premature end of file") ;
}
//
// Description:
//
// This method reads an application or comment marker
// from the input stream.
//
// Parameters:
// type: The marker type
//
void JpegDecoder::ReadApplication (UBYTE1 type)
{
unsigned int length = ReadWord () ;
char id [512] ;
int ii = 0 ;
id [ii] = ReadByte () ;
for (ii = 1 ; id [ii - 1] != '\000'
&& ii < sizeof (id)
&& ii < length - sizeof (UBYTE2) ; ++ ii)
{
id [ii] = ReadByte () ;
}
for ( ; ii < length - sizeof (UBYTE2) ; ++ ii)
(void) ReadByte () ;
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 ;
}
//
// Description:
//
// The function reads a Define Huffman Table marker from the input
// stream.
//
void JpegDecoder::ReadHuffmanTable ()
{
// Section B.2.4.2
if (verbose_flag)
cout << "{ Define Huffman Table" << endl ;
UBYTE2 length = ReadWord () ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -