📄 jpgencoder.~cpp
字号:
//
// JPEG编码库
//
// 标题: JpegEncoder类实现
//
// 修改:
//
// 10-January-1999 Changed to use predefined quantization tables
// rather than tables scaled from the ones in the
// JPEG standard.
//
#include <math.h>
#include <string>
#include <cerrno>
#include "jpgencoder.h"
#include "bitmapimage.h"
#include "jfif.h"
#include "jpgencoderquantization.h"
#include "jpghuffmanencoder.h"
#include "jpgoutputstream.h"
#include "jpgoutputfilestream.h"
#include "jpgqtbls.h"
using namespace std ;
using namespace ColosseumPrivate ;
//量化表(亮度)
const unsigned int luminance_quantization_tables [][JPEGSAMPLESIZE] =
{
QTABLEWORST,
QTABLEDODQ1,
QTABLEDODQ2,
QTABLENIMAQ1,
QTABLEJPEGL1,
QTABLENIMAQ2,
QTABLEJPEGL2,
QTABLENIMAQ3,
QTABLEDODQ3,
QTABLEDODQ4,
QTABLENIMAQ4,
QTABLEBEST
} ;
//量化表(色度)
const unsigned int chrominance_quantization_tables [][JPEGSAMPLESIZE] =
{
QTABLEWORST,
QTABLENIMADOWNSAMPLE,
QTABLEJPEGC1,
QTABLEJPEGC2,
QTABLEBEST
} ;
namespace Colosseum
{
//
// 描述:
//
// 类缺省构造函数
//
JpegEncoder::JpegEncoder ()
{
initialize () ;
return ;
}
//
// 描述:
//
// 类复制构造函数
//
JpegEncoder::JpegEncoder (const JpegEncoder &source)
{
initialize () ;
doCopy (source) ;
return ;
}
//
// 描述:
//
// 类析构函数
//
JpegEncoder::~JpegEncoder ()
{
delete [] ac_tables ; ac_tables = 0 ;
delete [] dc_tables ; dc_tables = 0 ;
delete [] quantization_tables ;
quantization_tables = 0 ;
return ;
}
//
// 描述:
//
// 类赋值操作符
//
JpegEncoder &JpegEncoder::operator=(const JpegEncoder &source)
{
if (&source != this)
doCopy (source) ;
return *this ;
}
//
// 描述:
//
// Class copy function. This function gets called from the
// copy constructor and assignment operator. The only thing
// we copy are the use settable parameters.
//
void JpegEncoder::doCopy (const JpegEncoder &source)
{
//可设定的参数
gray_scale = source.gray_scale ;
rows_per_restart = source.rows_per_restart ;
comment_string = source.comment_string ;
image_quality = source.image_quality ;
progressive_mode = source.progressive_mode ;
//扫描线的复制
for (unsigned int ii = 0 ; ii < MAXSCANS ; ++ ii)
image_scans [ii] = source.image_scans [ii] ;
BitmapImageCoder::operator=(source) ;
//量化表的复制
memcpy (quantization_table_assignments,
source.quantization_table_assignments,
sizeof (quantization_table_assignments)) ;
memcpy (quantization_tables,
source.quantization_tables,
sizeof (quantization_tables)) ;
return ;
}
//
// 描述:
//
// 将一幅图像写到 the output stream.
//
// Parameters:
// strm: The output stream to write the image to. This most be opened in
// binary mode
// image: The image to output.
//
void JpegEncoder::writeImage (JpegOutputStream &outputstream, const BitmapImage &image)
{
//图像的三个成分
image_components [YCOMPONENT].setOutputStream (outputstream) ;
image_components [CBCOMPONENT].setOutputStream (outputstream) ;
image_components [CRCOMPONENT].setOutputStream (outputstream) ;
//使用
for (unsigned int ii = 0 ; ii < JPEGMAXQUANTIZATIONTABLES ; ++ ii)
quantization_tables [ii].isUsed (false) ;
if (gray_scale)
{
quantization_tables [quantization_table_assignments [YCOMPONENT]].isUsed (true) ;
}
else
{
quantization_tables [quantization_table_assignments [YCOMPONENT]].isUsed (true) ;
quantization_tables [quantization_table_assignments [CBCOMPONENT]].isUsed (true) ;
quantization_tables [quantization_table_assignments [CRCOMPONENT]].isUsed (true) ;
}
//?
BILLSELLSPOOP
for (unsigned int ii = 0 ; ii < JPEGMAXQUANTIZATIONTABLES ; ++ ii)
{
if (quantization_tables [ii].isUsed ())
{
quantization_tables [ii].buildScaledTables () ;
}
}
ENDBILLSELLSPOOP
//高、宽
frame_height = image.getHeight () ;
frame_width = image.getWidth () ;
// Find the MCU size and maximum sampling frequencies.
calculateMcuDimensions () ;
// Validate Parameters. If there is an error this function will throw
// an exception.
validateParameters () ;
countPassesForProgressReporting () ;
// Write the image header.
outputMarker (outputstream, SOI) ;
outputMarker (outputstream, APP0) ;
outputJfifHeader (outputstream) ;
if (comment_string != "")
printComment (outputstream, comment_string) ;
printComment (outputstream, "Created using the Colosseum Builders JPEG library") ;
if (progressive_mode)
printProgressiveFrame (outputstream, image) ;
else
printSequentialFrame (outputstream, image) ;
outputMarker (outputstream, EOI) ;
// Make sure that we are not holding on to any memory we do not
// need any more.
image_components [YCOMPONENT].freeDynamicStorage () ;
image_components [CBCOMPONENT].freeDynamicStorage () ;
image_components [CRCOMPONENT].freeDynamicStorage () ;
return ;
}
//
// 描述:
//
// Class Initialization function. This function is intended to be
// called from constructors.
//
void JpegEncoder::initialize ()
{
//Huffma表初始化
dc_tables = new JpegHuffmanEncoder [2] ;
ac_tables = new JpegHuffmanEncoder [2] ;
//量化表初始化
quantization_tables = new JpegEncoderQuantizationTable [JPEGMAXQUANTIZATIONTABLES] ;
//扫描
memset (image_scans, 0, sizeof (image_scans)) ;
image_scans [0].component_mask = (1<<YCOMPONENT)
|(1<<CBCOMPONENT)
|(1<<CRCOMPONENT) ;
//属性初始化
progressive_mode = false ;
setQuality (75) ;
progress_function = 0 ;
progress_data = 0 ;
restart_interval = 0 ;
rows_per_restart = 0 ;
gray_scale = false ;
for (unsigned int ii = 0 ; ii < MAXCOMPONENTS ; ++ ii)
{
image_components [ii].setHorizontalFrequency (1) ;
image_components [ii].setVerticalFrequency (1) ;
}
quantization_table_assignments [YCOMPONENT] = 0 ;
quantization_table_assignments [CBCOMPONENT] = 1 ;
quantization_table_assignments [CRCOMPONENT] = 1 ;
image_components [YCOMPONENT].setHuffmanTables (dc_tables [0],
ac_tables [0]) ;
image_components [CBCOMPONENT].setHuffmanTables (dc_tables [1],
ac_tables [1]) ;
image_components [CRCOMPONENT].setHuffmanTables (dc_tables [1],
ac_tables [1]) ;
image_components [YCOMPONENT].setQuantizationTable (
quantization_tables [quantization_table_assignments [YCOMPONENT]]) ; ;
image_components [CBCOMPONENT].setQuantizationTable (
quantization_tables [quantization_table_assignments [CBCOMPONENT]]) ; ;
image_components [CRCOMPONENT].setQuantizationTable (
quantization_tables [quantization_table_assignments [CRCOMPONENT]]) ; ;
return ;
}
// 描述:
// This function writes a marker to the output stream.
//
// Parameters:
// marker: The marker to be written to the output stream
//
void JpegEncoder::outputMarker (JpegOutputStream &outputstream,
ColosseumPrivate::JpegMarker marker)
{
outputstream.writeByte (SOB) ;
outputstream.writeByte (marker) ;
return ;
}
//
// 描述:
//
// This function validates the user-set output parameters. If an error is
// detected an EJpegBadOutputParameter exception is thrown.
//
void JpegEncoder::validateParameters ()
{
const int ALL = (1<<YCOMPONENT)|(1<<CBCOMPONENT)|(1<<CRCOMPONENT) ;
// Ensure we do not have fractional sampling of pixels.
if (! gray_scale)
{
if (image_components [YCOMPONENT].getHorizontalFrequency () == 3
|| image_components [CBCOMPONENT].getHorizontalFrequency () == 3
|| image_components [CRCOMPONENT].getHorizontalFrequency () == 3)
{
if (image_components [YCOMPONENT].getHorizontalFrequency () == 2
|| image_components [YCOMPONENT].getHorizontalFrequency () == 4
|| image_components [CBCOMPONENT].getHorizontalFrequency () == 2
|| image_components [CBCOMPONENT].getHorizontalFrequency () == 4
|| image_components [CRCOMPONENT].getHorizontalFrequency () == 2
|| image_components [CRCOMPONENT].getHorizontalFrequency () == 4)
{
throw JpegError ("Fractional Horizontal Sampling") ;
}
}
if (image_components [YCOMPONENT].getVerticalFrequency () == 3
|| image_components [CBCOMPONENT].getVerticalFrequency () == 3
|| image_components [CRCOMPONENT].getVerticalFrequency () == 3)
{
if (image_components [YCOMPONENT].getVerticalFrequency () == 2
|| image_components [YCOMPONENT].getVerticalFrequency () == 4
|| image_components [CBCOMPONENT].getVerticalFrequency () == 2
|| image_components [CBCOMPONENT].getVerticalFrequency () == 4
|| image_components [CRCOMPONENT].getVerticalFrequency () == 2
|| image_components [CRCOMPONENT].getVerticalFrequency () == 4)
{
throw JpegError ("Fractional Vertical Sampling") ;
}
}
}
if (progressive_mode)
{
// For a progressive scan the following rules apply
//
// o The spectral selection start can be zero if and only if
// the spectral selection end is zero.
//
// o For each component the zero spectral selection start must occur
// before any other.
//
// o If the spectral selection start is not zero there may only be
// one component in a scan.
//
// o The entire spectral range must be specified for each component.
//
// o There can be no overlapping spectral ranges in scans.
//
int lasty = -1 ;
int lastcb = -1 ;
int lastcr = -1 ;
if (gray_scale)
{
// For a grayscale image the Cb and Cr components are not used.
lastcb = 63 ;
lastcr = 63 ;
}
for (scan_count = 0 ; scan_count < MAXSCANS ; ++ scan_count)
{
if (lasty == 63 && lastcb == 63 && lastcr == 63)
break ;
if (image_scans [scan_count].component_mask == 0)
throw JpegError ("Scan contains no components") ;
if (image_scans [scan_count].successive_approximation
> JPEGMAXSUCCESSIVAPPROXIMATION)
{
throw JpegError ("Successive Approximation too large") ;
}
image_scans [scan_count].successive_approximation_low =
image_scans [scan_count].successive_approximation ;
image_scans [scan_count].successive_approximation_high = 0 ;
// Y Component Validation
if ((image_scans [scan_count].component_mask & (1<<YCOMPONENT)) != 0)
{
if (image_scans [scan_count].spectral_selection_end == 0)
{
if (lasty != -1)
throw JpegError ("Duplicate Y Component Scan") ;
image_scans [scan_count].spectral_selection_start = 0 ;
lasty = 0 ;
}
else
{
if (image_scans [scan_count].component_mask != (1<<YCOMPONENT))
throw JpegError ("Multiple Components in AC Scan") ;
if (image_scans [scan_count].spectral_selection_end != 0
&& lasty == -1)
{
throw JpegError (
"AC Scan specified before DC scan for Y Component") ;
}
if (image_scans [scan_count].spectral_selection_end <= lasty)
throw JpegError ("Duplicate or overlapping spectral selection for Y Component") ;
image_scans [scan_count].spectral_selection_start = lasty + 1 ;
lasty = image_scans [scan_count].spectral_selection_end ;
}
}
if (! gray_scale)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -