📄 jpgencodercomponent.cpp
字号:
// Description:
//
// This function is use to output a data unit for the first pass
// DC progressive scan. The DC coefficients are encoded in the same manner
// as in a sequential scan except for the point transform.
//
// This function gets called twice for each data unit in the scan. The
// first pass is used to gather Huffman statistics and the second is
// used to Huffman-encode the data and write it to the output stream.
// We use pointers to the statistics/output functions to ensure that
// both passes are performed in the exact same manner.
//
// Parameters:
// row,col: Data unit position
// dcfunction: Function for outputting DC coefficient values.
// successiveapproximation: Successive Approximation
//
// This function is of the type COMPONENTPASSFUNCTION.
//
void JpegEncoderComponent::progressiveDcFirst (
unsigned int row, unsigned int col,
DCOUTPUTFUNCTION dcfunction, ACOUTPUTFUNCTION,
unsigned int, unsigned int,
unsigned int successiveapproximation)
{
// G.1.2.1
// DC value calculation
// A.4
int value = dct_coefficients [row * du_cols + col][0]
>> successiveapproximation ;
// Section F.1.2
int diff = value - last_dc_value ;
last_dc_value = value ;
// Break the difference into a category for Huffman coding and additional
// raw bits for refinement.
int bits ;
if (diff >= 0)
{
bits = diff ;
}
else
{
diff = -diff ;
bits = ~diff ;
}
int ssss = 0 ; // Category
while (diff != 0)
{
++ ssss ;
diff >>= 1 ;
}
(this->*dcfunction) (ssss, bits) ;
return ;
}
//
// Description:
//
// This function outputs DC coefficient data for refining scans in a
// progressive frame. This is the only thing simple about progressive
// JPEG. In this scan we simply encode an additional bit for each
// DC coefficient.
//
// Since there is no Huffman coding for this refining DC scans this function
// only gets called once per data unit in a scan. Therefore we do not
// use the output function pararmeters.
//
// Parameters:
// row,col: Data unit position
// ssa: Successive Approximation
//
// This function is of the type COMPONENTPASSFUNCTION.
//
void JpegEncoderComponent::progressiveDcRefine (
unsigned int row, unsigned int col,
DCOUTPUTFUNCTION, ACOUTPUTFUNCTION,
unsigned int, unsigned int,
unsigned int ssa)
{
// Section G.1.2.1
int value = (dct_coefficients [row * du_cols + col][0] >> ssa) & 0x1 ;
output_stream->outputBits (value, 1) ;
return ;
}
//
// Description:
//
// This function encodes a data unit for the first AC coefficient scan
// for a spectral range in a progressive frame. The procedure here
// is taken literally from the JPEG specification.
//
// The AC encoding complexity is significantly increased over that of
// sequential scans because End of Bands can span data units.
//
// Parameters:
// row,col: Data unit position
// acfunction: Function for outputting AC coefficient values
// sss: Spectral Selection Start
// sse: Spectral Selection End
// ssa: Successive Approximation
//
void JpegEncoderComponent::progressiveAcFirst (
unsigned int row, unsigned int col,
ACOUTPUTFUNCTION acfunction,
unsigned int sss, unsigned int sse,
unsigned int ssa)
{
JpegCoefficientBlock &du = dct_coefficients [row * du_cols + col] ;
// G.1.2.2 Figure G.3
unsigned int zerorun = 0 ;
for (unsigned int ii = sss ; ii <= sse ; ++ ii)
{
int value = du [JpegZigZagInputOrder (ii)] ;
// Point Transform
value = value / (1 << ssa) ;
if (value == 0)
{
++ zerorun ;
}
else
{
printEobRun (acfunction) ;
// Figure G.5
while (zerorun >= 16)
{
(this->*acfunction)(0xF0, 0, 0) ;
zerorun -= 16 ;
}
int bits ;
if (value >= 0)
{
bits = value ;
}
else
{
value = -value ;
bits = ~value ;
}
int ssss = 0 ;
while (value != 0)
{
++ ssss ;
value >>= 1 ;
}
unsigned int rrrrssss = (zerorun << 4) | ssss ;
(this->*acfunction) (rrrrssss, bits, ssss) ;
zerorun = 0 ;
if (ii >= sse)
return ;
}
}
++ eob_run ;
// Do not allow the EOB run to exceed 0x7FFF.
// G.1.2.2
if (eob_run == 0x7FFF)
printEobRun (acfunction) ;
return ;
}
//
// Description:
//
// This function encodes the AC coefficients for a refining scan in a
// progressive frame.
//
// The JPEG standard is nebulous here (Section G.1.2.3). It is
// unfortunate that for such a brain-damaged encoding method as
// this that they should be unclear. In addition to the complexity
// of having EOB runs span data units, data does not get written
// out in the order it occurs.
//
// This is why there are no section references in the code other than
// the one above. I am simply guessing here, sorry. I created this code by
// guessing and running the output through various applications that handle
// progressive JPEG until I could find no complaints.
//
// If you thing this is bad wait until you get to the part about decoding
// progressive scans (G.2)!
//
// Parameters:
// row,col: Data unit position
// acfunction: Function for outputting AC coefficient values
// sss: Spectral Selection Start
// sse: Spectral Selection End
// ssa: Successive Approximation
//
void JpegEncoderComponent::progressiveAcRefine (
unsigned int row, unsigned int col,
ACOUTPUTFUNCTION acfunction,
unsigned int sss, unsigned int sse,
unsigned int ssa)
{
JpegCoefficientBlock &du = dct_coefficients [row * du_cols + col] ;
// Number of zero coefficients - Note that existing non-zero coefficients
// are not included in this count.
unsigned int zerorun = 0 ;
// The start of the zero run.
unsigned int zerostart = sss ;
// Number of existing non-zero coefficients - used only for error checking.
unsigned int correctioncount = 0 ;
for (unsigned int ii = sss ; ii <= sse ; ++ ii)
{
// Point Transform
int value = du [JpegZigZagInputOrder (ii)] / (1 << ssa) ;
// We have three types of values:
// o A Zero
// o A coefficient that was zero in all previous scan that we are
// going to make non-zero in this scan (value = +/-1)
// o An coefficient that was made non-zero in a previous scan
// (value > 1 OR value < -1)
if (value == 0)
{
++ zerorun ;
}
else if (value == 1 || value == -1)
{
// If way have an EOB run then print it out.
printRefineEobRun (acfunction, sss, sse, ssa) ;
// The longest zero run we can have is 16.
while (zerorun >= 16)
{
(this->*acfunction)(0xF0, 0, 0) ;
zerorun -= 16 ;
// Refine all the existing coefficients skipped by the zero run.
for (int zerocount = 0 ;
zerocount < 16 ;
++ zerostart)
{
ASSERT (zerostart >= sss && zerostart <= sse && correctioncount <= JPEGSAMPLESIZE) ; // Invalid Zero Run
int oldvalue = du [JpegZigZagInputOrder (zerostart)] / (1 << ssa) ;
if (oldvalue < 0)
oldvalue = - oldvalue ;
if (oldvalue > 1)
{
(this->*acfunction)(-1, (oldvalue & 0x1), 1) ;
-- correctioncount ;
}
else if (oldvalue == 0)
{
// Because we need to count only zero values we our loop counter
// gets incremented here.
++ zerocount ;
}
else
{
// If the value is +/- 1 we should have already processed it.
throw JpegEncoder::JpegError ("INTERNAL ERROR - Bad Value") ;
}
}
}
// This is the first time this value has been nonzero.
int output = (zerorun << 0x4) | 1 ;
if (value > 0)
(this->*acfunction)(output, 1, 1) ;
else
(this->*acfunction)(output, 0, 1) ;
zerorun = 0 ;
// No go back and refine all the previously non-zero coefficients
// skipped by this zero run.
for (unsigned int jj = zerostart ; jj < ii ; ++ jj)
{
int oldvalue = du [JpegZigZagInputOrder (jj)] / (1 << ssa) ;
if (oldvalue < 0)
oldvalue = - oldvalue ;
if (oldvalue > 1)
{
(this->*acfunction)(-1, (oldvalue & 0x1), 1) ;
-- correctioncount ;
}
}
zerostart = ii + 1 ;
if (ii == sse)
return ; // All finished with this data unit.
}
else
{
// We only use this counter for error checking. It contains the
// number of previously non-zero coefficients that we have skipped
/// as part of a zero run.
++ correctioncount ;
}
}
// If we get here then the data unit ends with a string of zero coefficients
// or previously non-zero coefficients that we are skipping.
if (eob_run == 0)
{
// We are beginning and End of Band run. Mark the starting position
// including the spectral position.
eob_start_du_row = row ;
eob_start_du_col = col ;
eob_start_position = zerostart ;
}
++ eob_run ;
// G.1.2.2
if (eob_run == 0x7FFF)
printRefineEobRun (acfunction, sss, sse, ssa) ;
return ;
}
//
// Description:
//
// This function Resets the End of Band run counters. It should be called
// before beginning to output a scan.
//
void JpegEncoderComponent::resetEobRun ()
{
eob_run = 0 ;
// We use values here that should make an error easier to detect.
eob_start_du_row = du_cols * du_rows ;
eob_start_du_col = du_cols * du_rows ;
eob_start_position = JPEGSAMPLESIZE ;
return ;
}
//
// Description:
//
// This function outputs an End of Band run in a refining AC ceofficient
// scan of a progressive frame. As for the rest of the refining AC scan
// data I am mostly guessing here. I have taken the process from
// Figure G.4 and the vague description in Section G.1.2.3. It seems to
// work.
//
// Parameters:
// acfunction: Function for outputting AC coefficient values
// sss: Spectral Selection Start
// sse: Spectral Selection End
// ssa: Successive Approximation
//
void JpegEncoderComponent::printRefineEobRun (ACOUTPUTFUNCTION acfunction,
unsigned int sss, unsigned int sse,
unsigned int ssa)
{
if (eob_run != 0)
{
unsigned int bits = eob_run ;
unsigned int value = bits >> 1 ;
unsigned int ssss = 0 ; // Category (Table G.1)
while (value != 0)
{
value >>= 1 ;
++ ssss ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -