📄 jpgencoder.~cpp
字号:
max_vertical_frequency,
image_components [YCOMPONENT],
image_components [CBCOMPONENT],
image_components [CRCOMPONENT]) ;
++ current_pass ;
image_components [YCOMPONENT].sampleComponent (*this,
max_horizontal_frequency,
max_vertical_frequency) ;
++ current_pass ;
image_components [CBCOMPONENT].sampleComponent (*this,
max_horizontal_frequency,
max_vertical_frequency) ;
++ current_pass ;
image_components [CRCOMPONENT].sampleComponent (*this,
max_horizontal_frequency,
max_vertical_frequency) ;
// Output JPEG SOS Marker
// Section B.2.2
outputMarker (outputstream, SOF2) ;
outputstream.writeBigEndianWord (8 + 3 * 3) ;
outputstream.writeByte (8) ; // Precision
outputstream.writeBigEndianWord (image.getHeight ()) ;
outputstream.writeBigEndianWord (image.getWidth ()) ;
outputstream.writeByte (3) ; // Component Count
outputstream.writeByte(YCOMPONENT) ;
outputstream.writeByte (
(image_components [YCOMPONENT].getHorizontalFrequency () << 4)
| image_components [YCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [YCOMPONENT]) ;
outputstream.writeByte(CBCOMPONENT) ;
outputstream.writeByte (
(image_components [CBCOMPONENT].getHorizontalFrequency () << 4)
| image_components [CBCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [CBCOMPONENT]) ; // Quantization Table
outputstream.writeByte(CRCOMPONENT) ;
outputstream.writeByte (
(image_components [CRCOMPONENT].getHorizontalFrequency () << 4)
| image_components [CRCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [CRCOMPONENT]) ; // Quantization Table
printQuantizationTables (outputstream) ;
// Because of successive approximation we may have to go through the
// scan list several times. This flag gets set each time a scan
// is processed. The first time we search the scan list and do
// nothing this flag will be false and we are all done.
bool doingwork ;
do
{
doingwork = false ;
for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
{
findComponentsInScan (image_scans [ii]) ;
if (scan_component_count != 0
&& image_scans [ii].successive_approximation_low >= 0)
{
++ current_pass ;
printProgressiveScan (outputstream, image_scans [ii]) ;
doingwork = true ;
image_scans [ii].successive_approximation_high
= image_scans [ii].successive_approximation_low ;
-- image_scans [ii].successive_approximation_low ;
}
}
} while (doingwork) ;
}
return ;
}
//
// Description:
//
// This function enables or disables progressive output. When the mode is
// changed the image_scans is initialized with a default set of values for
// the new mode.
//
// Parameters:
// value: (true=>Progressive Mode, false=>Sequential Mode)
//
void JpegEncoder::setProgressive (bool value)
{
if (value == progressive_mode)
return ;
progressive_mode = value ;
memset (image_scans, 0, sizeof (image_scans)) ;
if (progressive_mode)
{
// For Progressive Scans our default is four scans. The first
// contains the DC coefficients for all three components. The next
// three scans contain the AC coefficients for each component.
image_scans [0].component_mask = (1<<YCOMPONENT)
|(1<<CBCOMPONENT)
|(1<<CRCOMPONENT) ;
image_scans [1].component_mask = (1<<YCOMPONENT) ;
image_scans [1].spectral_selection_end = 63 ;
image_scans [2].component_mask = (1<<CBCOMPONENT) ;
image_scans [2].spectral_selection_end = 63 ;
image_scans [3].component_mask = (1<<CRCOMPONENT) ;
image_scans [3].spectral_selection_end = 63 ;
}
else
{
// For sequential mode the default is to create one scan with
// all components.
image_scans [0].component_mask = (1<<YCOMPONENT)
|(1<<CBCOMPONENT)
|(1<<CRCOMPONENT) ;
}
return ;
}
//
// Description:
//
// This function writes a sequential scan to the output stream.
//
// Parameters:
// scan: The scan descriptor
//
void JpegEncoder::printSequentialScan (JpegOutputStream &outputstream,
const Scan &scan)
{
ASSERT (scan_component_count != 0) ; // No components defined for scan
// Output the restart interval and the Huffman tables. We must set the
// restart interval *BEFORE* gathering statistics.
if (scan_component_count != 1)
{
outputRestartInterval (outputstream, rows_per_restart * mcu_cols) ;
}
else
{
outputRestartInterval (outputstream,
rows_per_restart * scan_components [0]->dataUnitCols ()) ;
}
// Gather Huffman Statistics
if ((scan.component_mask & (1<<YCOMPONENT)) != 0)
{
dc_tables [0].reset () ;
ac_tables [0].reset () ;
}
if ((scan.component_mask & (1<<YCOMPONENT)) == 0
|| scan_component_count != 1)
{
ac_tables [1].reset () ;
dc_tables [1].reset () ;
}
if (scan_component_count != 1)
{
interleavedPass (
outputstream,
false,
&JpegEncoderComponent::encodeSequential,
&JpegEncoderComponent::gatherDcData,
&JpegEncoderComponent::gatherAcData,
0, JPEGSAMPLESIZE - 1, 0) ;
}
else
{
noninterleavedPass (
outputstream,
false,
&JpegEncoderComponent::encodeSequential,
&JpegEncoderComponent::gatherDcData,
&JpegEncoderComponent::gatherAcData,
0, JPEGSAMPLESIZE - 1, 0) ;
}
// Create the Huffman Tables
if ((scan.component_mask & (1<<YCOMPONENT)) != 0)
{
dc_tables [0].buildTable () ;
ac_tables [0].buildTable () ;
}
if ((scan.component_mask & (1<<YCOMPONENT)) == 0
|| scan_component_count != 1)
{
ac_tables [1].buildTable () ;
dc_tables [1].buildTable () ;
}
// Output the Huffman tables
printHuffmanTables (outputstream, scan, true, true) ; // Output DC and AC tables.
// Create the scan marker.
// Section B.2.3
outputMarker (outputstream, SOS) ;
outputstream.writeBigEndianWord (6 + 2 * scan_component_count) ; // Length
outputstream.writeByte (scan_component_count) ; // Component Count
if ((scan.component_mask & (1<<YCOMPONENT)) != 0)
{
outputstream.writeByte (0x01) ; // YCOMPONENT
outputstream.writeByte (0x00) ; // Entropy Tables
}
if (! gray_scale)
{
if ((scan.component_mask & (1<<CBCOMPONENT)) != 0)
{
outputstream.writeByte (0x02) ; // CBCOMPONENT
outputstream.writeByte (0x11) ; // Entropy Tables
}
if ((scan.component_mask & (1<<CRCOMPONENT)) != 0)
{
outputstream.writeByte (0x03) ; // CRCOMPONENT
outputstream.writeByte (0x11) ; // Entropy Tables
}
}
outputstream.writeByte (0) ; // Spectral Selection Start
outputstream.writeByte (JPEGSAMPLESIZE - 1) ; // Spectral Selection End
outputstream.writeByte (0) ; // Successive Approximation
// Output the Scan data.
outputstream.enterBitMode (CHAR_BIT) ;
if (scan_component_count != 1)
{
interleavedPass (
outputstream,
true,
&JpegEncoderComponent::encodeSequential,
&JpegEncoderComponent::printDcData,
&JpegEncoderComponent::printAcData,
0, JPEGSAMPLESIZE - 1, 0) ;
}
else
{
noninterleavedPass (
outputstream,
true,
&JpegEncoderComponent::encodeSequential,
&JpegEncoderComponent::printDcData,
&JpegEncoderComponent::printAcData,
0, JPEGSAMPLESIZE - 1, 0) ;
}
outputstream.exitBitMode () ;
return ;
}
//
// Description:
//
// This function makes a pass through the data units for a non-interleaved
// Scan.
//
// The reason for having a generic function that uses pointers to member
// functions to do processing is that there are several places where the
// control processing has to be identical in multiple passes where the
// low level actions are different. For example, the processing here when
// gathering Huffman statistics has to be identical to the processing when
// writing values to the output file. Using separate functions turned out
// to be error prone due to the difficulty of keeping multiple functions
// exactly in synchronization.
//
// Parameters:
// writerestarts: false => This is a statistics gathering pass
// true => This pass is writing data to the output file.
// passfunctions: Pointer to EncoderComponent member function used
// to process this pass.
// dcfunction: Pointer to the EncoderComponent member function used
// to process DC coefficient values.
// acfunction: Pointer to the EncoderComponent member function used
// to process AC coefficient values.
// sss: Spectral Selection Start (0-63)
// sse: Spectral Selection End (0-63)
// ssa: Successive Approximation (0-13)
//
void JpegEncoder::noninterleavedPass (
JpegOutputStream &outputstream,
bool writedata,
JpegEncoderComponent::COMPONENTPASSFUNCTION passfunction,
JpegEncoderComponent::DCOUTPUTFUNCTION dcfunction,
JpegEncoderComponent::ACOUTPUTFUNCTION acfunction,
unsigned int sss,
unsigned int sse,
unsigned int ssa)
{
// We use a scale integer to keep trake of progress to lessen the
// change that the progress increment will be zero.
const int progressscale = 8 ;
unsigned int progress ;
unsigned int progressincrement ;
if (writedata)
progress = 50 << progressscale ;
else
progress = 0 ;
progressincrement = (100 << progressscale)
/ (2 * scan_components [0]->dataUnitRows ()) ;
resetDcValues () ;
unsigned int intervalcount = 0 ;
unsigned int restartmarker = 0 ;
for (unsigned int row = 0 ;
row < scan_components [0]->noninterleavedDuRows () ;
++ row)
{
for (unsigned int col = 0 ;
col < scan_components [0]->noninterleavedDuColumns () ;
++ col, ++ intervalcount)
{
if (restart_interval != 0)
{
if (intervalcount == restart_interval && restart_interval != 0)
{
// If there are any outstanding EOB runs we flush them before the
// restart marker. This is not explicitly stated in the JPEG
// standard. The definition of "Restart Interval" in section 4.1
// states that restart markers separate independent sequences,
// something we would not have if we did not output the EOB run
// here.
scan_components [0]->printEobRun (acfunction) ;
// E.1.4
if (writedata)
outputRestartMarker (outputstream, restartmarker) ;
resetDcValues () ;
++ restartmarker ;
restartmarker %= 8 ;
intervalcount = 0 ;
}
}
(scan_components [0]->*passfunction) (
row,
col,
dcfunction,
acfunction,
sss, sse,
ssa) ;
}
progress += progressincrement ;
callProgressFunction (progress >> progressscale) ;
}
if (writedata)
callProgressFunction (100) ;
else
callProgressFunction (50) ;
return ;
}
//
// Description:
//
// This function makes a pass through the data units for an interleaved
// Scan.
//
// The reason for having a generic function that uses pointers to member
// functions to do processing is that there are several places where the
// control processing has to be identical in multiple passes where the
// low level actions are different. For example, the processing here when
// gathering Huffman statistics has to be identical to the processing when
// writing values to the output file. Using separate functions turned out
// to be error prone due to the difficulty of keeping multiple functions
// exactly in synchronization.
//
// Parameters:
// writerestarts: false => This is a statistics gathering pass
// true => This pass is writing data to the output file.
// passfunctions: Pointer to EncoderComponent member function used
// to process this pass.
// dcfunction: Pointer to the EncoderComponent member function used
// to process DC coefficient values.
// acfunction: Pointer to the EncoderComponent member function used
// to process AC coefficient values.
// sss: Spectral Selection Start (0-63)
// sse: Spectral Selection End (0-63)
// ssa: Successive Approximation (0-13)
//
void JpegEncoder::interleavedPass (
JpegOutputStream &outputstream,
bool writedata,
JpegEncoderComponent::COMPONENTPASSFUNCTION passfunction,
JpegEncoderComponent::DCOUTPUTFUNCTION dcfunction,
JpegEncoderComponent::ACOUTPUTFUNCTION acfunction,
unsigned int sss,
unsigned int sse,
unsigned int ssa)
{
const int progressscale = 8 ;
unsigned int progress ;
unsigned int progressincrement ;
if (writedata)
progress = 50 << progressscale ;
else
progress = 0 ;
progressincrement = (100 << progressscale) / (2 * mcu_rows) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -