📄 jpgencoder.~cpp
字号:
{
// Cb Component Validation
if ((image_scans [scan_count].component_mask & (1<<CBCOMPONENT)) != 0)
{
if (image_scans [scan_count].spectral_selection_end == 0)
{
if (lastcb != -1)
throw JpegError ("Duplicate Cb Component Scan") ;
image_scans [scan_count].spectral_selection_start = 0 ;
lastcb = 0 ;
}
else
{
if (image_scans [scan_count].component_mask != (1<<CBCOMPONENT))
throw JpegError ("Multiple Components in AC Scan") ;
if (image_scans [scan_count].spectral_selection_end != 0 && lastcb == -1)
throw JpegError ("AC Scan specified before DC scan for cb Component") ;
if (image_scans [scan_count].spectral_selection_end <= lastcb)
{
throw JpegError (
"Duplicate or overlapping spectral selection for Cb Component") ;
}
image_scans [scan_count].spectral_selection_start = lastcb + 1 ;
lastcb = image_scans [scan_count].spectral_selection_end ;
}
}
// Cr Component Validation
if ((image_scans [scan_count].component_mask & (1<<CRCOMPONENT)) != 0)
{
if (image_scans [scan_count].spectral_selection_end == 0)
{
if (lastcr != -1)
throw JpegError ("Duplicate Cr Component Scan") ;
image_scans [scan_count].spectral_selection_start = 0 ;
lastcr = 0 ;
}
else
{
if (image_scans [scan_count].component_mask != (1<<CRCOMPONENT))
throw JpegError ("Multiple Components in AC Scan") ;
if (image_scans [scan_count].spectral_selection_end != 0
&& lastcr== -1)
{
throw JpegError (
"AC Scan specified before DC scan for Cr Component") ;
}
if (image_scans [scan_count].spectral_selection_end <= lastcr)
{
throw JpegError (
"Duplicate or overlapping spectral selection for Cr Component") ;
}
image_scans [scan_count].spectral_selection_start = lastcr + 1 ;
lastcr = image_scans [scan_count].spectral_selection_end ;
}
}
}
}
if (lasty != 63)
throw JpegError ("Y Component not completely defined by scans") ;
if (! gray_scale)
{
if (lastcb != 63)
throw JpegError ("Cb Component not completely defined by scans") ;
if (lastcr != 63)
throw JpegError ("Cr Component not completely defined by scans") ;
}
}
else
{
if (! gray_scale)
{
if ((image_scans [0].component_mask
|image_scans [1].component_mask
|image_scans [2].component_mask)
!= ALL)
{
throw JpegError ("Not all components specified in scans") ;
}
if ((image_scans [0].component_mask
+image_scans [1].component_mask
+image_scans [2].component_mask)
!= ALL)
{
throw JpegError ("Component in more than one scan") ;
}
if (image_scans [2].component_mask != 0)
scan_count = 3 ;
else if (image_scans [1].component_mask != 0)
scan_count = 2 ;
else
scan_count = 1 ;
}
else
{
scan_count = 1 ;
}
}
// Enforce the MCU size limitation in Section B.2.3
//
// I am not certain why this limitation of 10 data units per MCU even
// exists. It seems to be an silly arbitrary limit. Maybe its to set
// a maximum upper size for an MCU decoding buffer. In any event we
// must abide by it.
if (! gray_scale)
{
for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
{
unsigned int dataunits = 0 ;
unsigned int componentcount = 0 ;
if ((image_scans [ii].component_mask & (1<<YCOMPONENT)) != 0)
{
dataunits += image_components [YCOMPONENT].getHorizontalFrequency ()
* image_components [YCOMPONENT].getVerticalFrequency () ;
++ componentcount ;
}
if ((image_scans [ii].component_mask & (1<<CBCOMPONENT)) != 0)
{
dataunits += image_components [CBCOMPONENT].getHorizontalFrequency ()
* image_components [CBCOMPONENT].getVerticalFrequency () ;
++ componentcount ;
}
if ((image_scans [ii].component_mask & (1<<CRCOMPONENT)) != 0)
{
dataunits += image_components [CRCOMPONENT].getHorizontalFrequency ()
* image_components [CRCOMPONENT].getVerticalFrequency () ;
++ componentcount ;
}
if (dataunits > JPEGMAXDATAUNITSPERMCU && componentcount > 1)
throw JpegError ("Data units in MCU exceeds 10") ;
}
}
return ;
}
//
// 描述:
//
// This function writes a comment marker to the output stream.
//
// Parameters:
// str: The comment string
//
void JpegEncoder::printComment (JpegOutputStream &outputstream, const std::string &str)
{
unsigned int length = sizeof (UBYTE2) + str.length () + 1 ;
outputMarker (outputstream, COM) ;
outputstream.writeBigEndianWord (length) ;
outputstream.write (str.c_str (), str.length ()) ;
outputstream.writeByte (0) ; // Terminator
return ;
}
//
// Description:
//
// This function writes the quantization tables to the output stream.
//
void JpegEncoder::printQuantizationTables (JpegOutputStream &outputstream)
{
const int precision = 0 ; // Byte Precision
UBYTE1 pqtq ;
// Count the number of quantization tables needed by the frame and
// create the scaled version of the table used in the DCT.
unsigned int tablecount = 0 ;
for (unsigned int ii = 0 ; ii < JPEGMAXQUANTIZATIONTABLES ; ++ ii)
{
if (quantization_tables [ii].isUsed ())
++ tablecount ;
}
// Section B.2.4.1
outputMarker (outputstream, DQT) ;
outputstream.writeBigEndianWord (sizeof(UBYTE2) + tablecount * (sizeof (pqtq) + JPEGSAMPLESIZE)) ;
BILLSELLSPOOP
for (unsigned int ii = 0 ; ii < JPEGMAXQUANTIZATIONTABLES ; ++ ii)
{
if (quantization_tables [ii].isUsed ())
{
pqtq = (precision << 4) | ii ;
outputstream.writeByte (pqtq) ;
for (unsigned int jj = 0 ; jj < JPEGSAMPLESIZE ; ++ jj)
outputstream.writeByte (quantization_tables [ii][JpegZigZagInputOrder (jj)]) ;
}
}
ENDBILLSELLSPOOP
return ;
}
//
// Description:
//
// This function is called by a scan to write a restart interval to the
// output stream. We do not output a Define Restart Interval marker if
// the restart interval is not changing.
//
// Parameters:
// restartinterval: The new restart interval
//
void JpegEncoder::outputRestartInterval (JpegOutputStream &outputstream,
unsigned int restartinterval)
{
if (restartinterval == restart_interval)
return ;
restart_interval = restartinterval ;
// B.2.4.4
outputMarker (outputstream, DRI) ;
outputstream.writeBigEndianWord (4) ;
outputstream.writeBigEndianWord (restartinterval) ;
return ;
}
//
// Description:
//
// This function writes a sequential frame to the output stream. We create
// frames with either one (black & white) or three (color) components.
//
// Parameters:
// image: The image to be written in the frame
//
void JpegEncoder::printSequentialFrame (JpegOutputStream &outputstream,
const BitmapImage &image)
{
// Sample the components
if (gray_scale)
{
++ current_pass ;
++ current_pass ;
JpegEncoderComponent::grayScaleConvert (*this,
image,
image_components [YCOMPONENT]) ;
}
else
{
++ current_pass ;
JpegEncoderComponent::rgbConvert (*this,
image,
max_horizontal_frequency,
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) ;
}
// Write the Frame Header
// Section B.2.2
outputMarker (outputstream, SOF0) ;
if (gray_scale) // Length
outputstream.writeBigEndianWord (8 + 3) ;
else
outputstream.writeBigEndianWord (8 + 3 * 3) ;
outputstream.writeByte (8) ; // Precision
outputstream.writeBigEndianWord (image.getHeight ()) ;
outputstream.writeBigEndianWord (image.getWidth ()) ;
if (gray_scale)
{
outputstream.writeByte (1) ; // Component Count
outputstream.writeByte(YCOMPONENT) ;
outputstream.writeByte (
(image_components [YCOMPONENT].getHorizontalFrequency () << 4)
| image_components [YCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [YCOMPONENT]) ;
printQuantizationTables (outputstream) ;
scan_component_count = 1 ;
scan_components [0] = &image_components [YCOMPONENT] ;
++ current_pass ;
printSequentialScan (outputstream, image_scans [0]) ;
}
else
{
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]) ;
outputstream.writeByte(CRCOMPONENT) ;
outputstream.writeByte (
(image_components [CRCOMPONENT].getHorizontalFrequency () << 4)
| image_components [CRCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [CRCOMPONENT]) ;
printQuantizationTables (outputstream) ;
// Print the scans that make up the frame.
for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
{
++ current_pass ;
if (image_scans [ii].component_mask != 0)
{
findComponentsInScan (image_scans [ii]) ;
printSequentialScan (outputstream, image_scans [ii]) ;
}
}
}
return ;
}
//
// Description:
//
// This function writes a progressive frame to the output stream.
//
// Parameters:
// image: The image to be written in the frame
//
void JpegEncoder::printProgressiveFrame (JpegOutputStream &outputstream,
const BitmapImage &image)
{
if (gray_scale)
{
++ current_pass ;
JpegEncoderComponent::grayScaleConvert (*this,
image,
image_components [YCOMPONENT]) ;
// Output JPEG SOF Marker
// Section B.2.2
outputMarker (outputstream, SOF2) ;
outputstream.writeBigEndianWord (8 + 3) ;
outputstream.writeByte (8) ; // Precision
outputstream.writeBigEndianWord (image.getHeight ()) ;
outputstream.writeBigEndianWord (image.getWidth ()) ;
outputstream.writeByte (1) ; // Component Count
outputstream.writeByte(YCOMPONENT) ;
outputstream.writeByte (
(image_components [YCOMPONENT].getHorizontalFrequency () << 4)
| image_components [YCOMPONENT].getVerticalFrequency ()) ;
outputstream.writeByte (quantization_table_assignments [YCOMPONENT]) ;
printQuantizationTables (outputstream) ;
scan_component_count = 1 ;
scan_components [0] = &image_components [YCOMPONENT] ;
bool doingwork ;
do
{
doingwork = false ;
for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
{
if ((image_scans [ii].component_mask & (1<<YCOMPONENT)) != 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) ;
}
else
{
++ current_pass ;
JpegEncoderComponent::rgbConvert (*this,
image,
max_horizontal_frequency,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -