home *** CD-ROM | disk | FTP | other *** search
- //
- // 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 Encoder Library.
- //
- // Title: JpegEncoderComponent Class Implementation
- //
- // Author: John M. Miano miano@colosseumbuilders.com
- //
- //
-
- #include "jpegenco.h"
- #include "jpencomp.h"
- #include "jfif.h"
- #include "jpencobk.h"
- #include "jpendu.h"
- #include "jpenhuff.h"
-
- //
- // Description:
- //
- // Class Default Constructor
- //
-
- JpegEncoderComponent::JpegEncoderComponent ()
- {
-
- jpeg_encoder = NULL ;
- dct_coefficients = NULL ;
-
- du_rows = 0 ;
- du_cols = 0 ;
-
- eob_run = 0 ;
- eob_start_du_row = 0 ;
- eob_start_du_col = 0 ;
- eob_start_position = 0 ;
-
- v_frequency = 1 ;
- h_frequency = 1 ;
-
- ac_table = NULL ;
- dc_table = NULL ;
-
- return ;
- }
-
- //
- // Description:
- //
- // Class Destructor
- //
- JpegEncoderComponent::~JpegEncoderComponent ()
- {
- FreeDynamicStorage () ;
- return ;
- }
-
- //
- // Description:
- //
- // This function gets rid of all the memory allocated by the component.
- // This allows the encoder to free memory after each image is written
- // rather than waiting until the decoder is deleted.
- //
- void JpegEncoderComponent::FreeDynamicStorage ()
- {
- delete [] dct_coefficients ; dct_coefficients = NULL ;
- return ;
- }
-
- //
- // Description:
- //
- // This function allocates the buffer used to hold DCT coefficients.
- //
- // Parameters:
- // image: The image being output
- // maxhf: The maximum horizontal frequency for all components.
- // maxvf: The maximum vertical frequency for all components.
- //
- void JpegEncoderComponent::CalculateDuDimensions (const BitmapImage &image,
- unsigned int maxhf,
- unsigned int maxvf)
- {
- du_cols = (image.Width () * h_frequency + (JpegSampleWidth * maxhf - 1))
- / (JpegSampleWidth * maxhf) ;
- du_rows = (image.Height () * v_frequency + (JpegSampleWidth * maxvf - 1))
- / (JpegSampleWidth * maxvf) ;
-
- v_period = maxvf / v_frequency ;
- h_period = maxhf / h_frequency ;
-
- dct_coefficients = new JpegEncoderCoefficientBlock [du_cols * du_rows] ;
- return ;
- }
-
- //
- // Description:
- //
- // This function samples a component where the horizontal and
- // vertical sampling frequencies are equal to the maximum values
- // for all components.
- //
- // Parameters:
- // image: The image to sample
- // function: A color conversion function
- //
-
- void JpegEncoderComponent::Sample1to1Component (const BitmapImage &image,
- RGBTOYCBCRFUNCTION function)
- {
- const int progressscale = 8 ;
- unsigned int progress = 0 ;
- unsigned int progressincrement = (100 << progressscale) / (du_rows) ;
-
- UBYTE1 red ;
- UBYTE1 green ;
- UBYTE1 blue ;
-
- JpegEncoderDataUnit data ;
-
- unsigned int index = 0 ;
- for (unsigned int ii = 0 ; ii < du_rows ; ++ ii)
- {
- for (unsigned int jj = 0 ; jj < du_cols ; ++ jj, ++ index)
- {
- unsigned int row = ii * JpegSampleWidth ;
- for (unsigned int dr = 0 ; dr < JpegSampleWidth ; ++ dr, ++ row)
- {
- unsigned int col = jj * JpegSampleWidth ;
- for (unsigned int dc = 0 ; dc < JpegSampleWidth ; ++ dc, ++ col)
- {
- if (row < image.Height ())
- {
- if (col < image.Width ())
- {
- image.GetRGB (row, col, red, green, blue) ;
- data [dr][dc] = function (red, green, blue) ;
- }
- else if (dc != 0)
- {
- // Extend the rightmost column
- data [dr][dc] = data [dr][dc-1] ;
- }
- else
- {
- // This data unit is completely off the edge of the image.
- data [dr][dc] = JpegMidpointSampleValue ;
- }
- }
- else if (dr != 0)
- {
- // Extend the last row of the image.
- data [dr][dc] = data [dr-1][dc] ;
- }
- else
- {
- // This data unit is completely off the edge of the image.
- data [dr][dc] = JpegMidpointSampleValue ;
- }
- } // Data Unit Columns
- } // Data Unit Rows
-
- data.ForwardDct (*quantization_table, dct_coefficients [index]) ;
- } // Columns of Data Units
- progress += progressincrement ;
- jpeg_encoder->CallProgressFunction (progress >> progressscale) ;
- } // Rows of Data Units
- return ;
- }
-
- //
- // Description:
- //
- // This function downsamples a component where the horizontal and
- // vertical sampling frequencies are not equal to the maximum values
- // for all components.
- //
- // Parameters:
- // image: The image to sample
- // function: A color conversion function
- //
- void JpegEncoderComponent::SampleNtoNComponent (const BitmapImage &image,
- RGBTOYCBCRFUNCTION function)
- {
- const int progressscale = 8 ;
- unsigned int progress = 0 ;
- unsigned int progressincrement = (100 << progressscale) / (du_rows) ;
-
- JpegEncoderDataUnit data ;
-
- // Sample the image.
- unsigned int index = 0 ;
- unsigned int imagerow = 0 ;
- for (unsigned int yy = 0 ;
- yy < du_rows ;
- ++ yy, imagerow += JpegSampleWidth * v_period)
- {
- unsigned int imagecol = 0 ;
- for (unsigned int xx = 0 ;
- xx < du_cols ;
- ++ xx, ++ index, imagecol += JpegSampleWidth * h_period)
- {
- // Loop for each row in the data unit.
- for (unsigned int outrow = 0 ; outrow < JpegSampleWidth ; ++ outrow)
- {
- // Loop for each column in the data unit.
- for (unsigned int outcol = 0 ; outcol < JpegSampleWidth ; ++ outcol)
- {
- // The nested loops handle sampling.
-
- int value = 0 ; // Sum of all sample values
- unsigned int count = 0 ; // Number of sample values.
- // Vertical sampling loop.
- for (unsigned int srcrow = 0 ; srcrow < v_period ; ++ srcrow)
- {
- // Horizontal sampling loop.
- unsigned int row = imagerow + srcrow + outrow * v_period ;
- for (unsigned int srccol = 0 ; srccol < h_period ; ++ srccol)
- {
- // Extract the values from the image.
- unsigned int col = imagecol + srccol + outcol * h_period ;
- if (row < image.Height () && col < image.Width ())
- {
- ++ count ;
- UBYTE1 red, green, blue ;
- image.GetRGB (row, col, red, green, blue) ;
- value += function (red, green, blue) ;
- }
- }
- }
- // Convert the total sample value to an average.
- if (count != 0)
- {
- data [outrow][outcol] = (value + count - 1) / count ;
- }
- else
- {
- // If we get here that means the data unit goes past the edge of
- // the input image. We attempt to duplicate the last column and if
- // we can't to that we copy the last row. If the entire data unit
- // is off the edge then we use zero for the value.
- if (outcol != 0)
- data [outrow][outcol] = data [outrow][outcol - 1] ;
- else if (outrow != 0)
- data [outrow][outcol] = data [outrow-1][outcol] ;
- else
- data [outrow][outcol] = 0 ;
- }
- }
- }
-
- data.ForwardDct (*quantization_table, dct_coefficients [index]) ;
- }
- progress += progressincrement ;
- jpeg_encoder->CallProgressFunction (progress >> progressscale) ;
- }
- return ;
- }
-
- //
- // Description:
- //
- // This function samples the Y component for the image.
- //
- // What we do here is determine how much memory is required
- // to hold the image, what color conversion function to use
- // for the component, and if downsampling is required.
- //
- // Parameters:
- // encoder: The JPEG encoder that owns the component
- // image: The image to be sampled
- // maxhf: The maximum horizontal frequency of all components
- // maxvf: The maximum vertical frequency of all components
- //
- void JpegEncoderComponent::SampleYComponent (JpegEncoder &encoder,
- const BitmapImage &image,
- unsigned int maxhf,
- unsigned int maxvf)
- {
- jpeg_encoder = &encoder ;
- CalculateDuDimensions (image, maxhf, maxvf) ;
-
- if (maxhf == h_frequency && maxvf == v_frequency)
- {
- Sample1to1Component (image, RGBToY) ;
- }
- else
- {
- SampleNtoNComponent (image, RGBToY) ;
- }
-
- return ;
- }
-
- //
- // Description:
- //
- // This function samples the Cb component for the image.
- //
- // What we do here is determine how much memory is required
- // to hold the image, what color conversion function to use
- // for the component, and if downsampling is required.
- //
- // Parameters:
- // encoder: The JPEG encoder that owns the component
- // image: The image to be sampled
- // maxhf: The maximum horizontal frequency of all components
- // maxvf: The maximum vertical frequency of all components
- //
- void JpegEncoderComponent::SampleCbComponent (JpegEncoder &encoder,
- const BitmapImage &image,
- unsigned int maxhf,
- unsigned int maxvf)
- {
- jpeg_encoder = &encoder ;
- CalculateDuDimensions (image, maxhf, maxvf) ;
-
- if (maxhf == h_frequency && maxvf == v_frequency)
- {
- Sample1to1Component (image, RGBToCb) ;
- }
- else
- {
- SampleNtoNComponent (image, RGBToCb) ;
- }
-
- return ;
- }
-
- //
- // Description:
- //
- // This function samples the Cr component for the image.
- //
- // What we do here is determine how much memory is required
- // to hold the image, what color conversion function to use
- // for the component, and if downsampling is required.
- //
- // Parameters:
- // encoder: The JPEG encoder that owns the component
- // image: The image to be sampled
- // maxhf: The maximum horizontal frequency of all components
- // maxvf: The maximum vertical frequency of all components
- //
-
- void JpegEncoderComponent::SampleCrComponent (JpegEncoder &encoder,
- const BitmapImage &image,
- unsigned int maxhf,
- unsigned int maxvf)
- {
- jpeg_encoder = &encoder ;
- CalculateDuDimensions (image, maxhf, maxvf) ;
-
- if (maxhf == h_frequency && maxvf == v_frequency)
- {
- Sample1to1Component (image, RGBToCr) ;
- }
- else
- {
- SampleNtoNComponent (image, RGBToCr) ;
- }
-
- return ;
- }
-
- //
- // Description:
- //
- // This function is use to gather Huffman statistics for DC coefficients.
- // The calling sequences is idential to PrintDcData (). Only the huffvalue
- // parameter is used here.
- //
- // Parameters:
- // huffvalue: The Huffman value (not code) to process.
- //
- void JpegEncoderComponent::GatherDcData (int huffvalue, int)
- {
- dc_table->IncrementFrequency (huffvalue) ;
- return ;
- }
-
- //
- // Description:
- //
- // This function is use to gather Huffman statistics for AC coefficients.
- // The calling sequences is idential to PrintAcData (). Only the huffvalue
- // parameter is used here.
- //
- // If huffval==-1 then an unencoded bit string would be output by
- // PrintAcData (). In that situation this function does nothing.
- //
- // Parameters:
- // huffvalue: The Huffman value (not code) to process
- //
- void JpegEncoderComponent::GatherAcData (int huffvalue, int, int)
- {
- if (huffvalue >= 0)
- {
- ac_table->IncrementFrequency (huffvalue) ;
- }
- return ;
- }
-
- //
- // Description:
- //
- // This function is use to output Huffman-encoded data for a DC value.
- //
- // Parameters:
- // huffvalue: The Huffman value
- // bits: The additional data bits
- //
- // 8-bit DC values are in the range 0..11. The value specifies the number
- // of additional bits of refining data (bits).
- //
-
- void JpegEncoderComponent::PrintDcData (int huffvalue, int bits)
- {
- UBYTE2 huffcode ;
- UBYTE1 huffsize ;
-
- // Section F.1.2.1
- dc_table->Encode (huffvalue, huffcode, huffsize) ;
- jpeg_encoder->OutputBits (huffcode, huffsize) ;
- if (huffvalue != 0)
- jpeg_encoder->OutputBits (bits, huffvalue) ;
- return ;
- }
-
- //
- // Description:
- //
- // This function is use to output Huffman-encoded data for an AC value.
- //
- // Parameters:
- // huffvalue: The Huffman value
- // value: The additional data bits
- // size: The number of additional data bits.
- //
- // When huffvalue==-1 this function is also used to output unencoded bit
- // strings.
- //
- void JpegEncoderComponent::PrintAcData (int huffvalue, int value, int size)
- {
- UBYTE2 huffcode ;
- UBYTE1 huffsize ;
-
- // Section F.1.2.2.1
- if (huffvalue >= 0)
- {
- ac_table->Encode (huffvalue, huffcode, huffsize) ;
- jpeg_encoder->OutputBits (huffcode, huffsize) ;
- }
- if (size != 0)
- jpeg_encoder->OutputBits (value, size) ;
- return ;
- }
- //
- // Description:
- //
- // This function is used for two purposes in a sequential scan:
- //
- // o To gather statistics for generating Huffman Tables
- // o To encode and output a data unit.
- //
- // The dcfunction and acfunction arguments are determine which of these
- // actions are performed. If these arguments are PrintDcData () and
- // PrintAcData () the data unit is encoded and written to the output
- // stream. If the arguments are GatherDcData () and GatherAcData ()
- // usage statistics are gathered.
- //
- // While creating a separate function for each purpose may have been clearer,
- // it would create maintenance problems because they would have to be kept
- // in strict synchronization with each other.
- //
- // Parameters:
- // row,col: Data unit position
- // dcfunction: Function for outputting DC coefficient values.
- // acfunction: Function for outputting AC coefficient values.
- //
- // This function is of the type COMPONENTPASSFUNCTION.
- //
- void JpegEncoderComponent::EncodeSequential (
- unsigned int row, unsigned int col,
- DCOUTPUTFUNCTION dcfunction,
- ACOUTPUTFUNCTION acfunction,
- unsigned int, unsigned int, unsigned int)
- {
- JpegEncoderCoefficientBlock *du = &dct_coefficients [row * du_cols + col] ;
-
- // DC value calculation
- // Section F.1.2.1.3
- int diff = (*du) [0][0] - last_dc_value ;
- last_dc_value = (*du)[0][0] ;
-
- // Break the DC coefficient into a category (Table F.12) and
- // additional bits.
- 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) ;
-
- // AC coefficient coding
- // F.1.2.2.3 Figure F.2
- int zerorun = 0 ; // Called rrrr in the specification.
- for (unsigned int index = 1 ; index < JpegSampleSize ; ++ index)
- {
- if (du->ZigZagInput (index) != 0)
- {
- // 16 is the longest run of zeros that can be encoded except for the
- // final EOB code.
- while (zerorun >= 16)
- {
- // 0xF0 is the code to skip 16 zeros (Figure F.1)
- (this->*acfunction) (0xF0, 0, 0) ;
- zerorun -= 16 ;
- }
-
- // Non-zero AC coefficients are encoded with
- // 8-bit Huffman-encoded values of the form rrrrssss followed by
- // 1..10 additional bits of data. rrrr is the number of zero values
- // to skip (0..15). ssss is the category (1..10) which specifies the
- // number of additional raw bits to follow. (Figure F.1)
- int value = du->ZigZagInput (index) ;
- int bits ;
- if (value >= 0)
- {
- bits = value ;
- }
- else
- {
- value = -value ;
- bits = ~value ;
- }
- int ssss = 0 ;
- while (value != 0)
- {
- value >>= 1 ;
- ++ ssss ;
- }
-
- int rrrrssss = (zerorun << 4) | ssss ;
- (this->*acfunction) (rrrrssss, bits, ssss) ;
- zerorun = 0 ;
- }
- else
- {
- ++ zerorun ;
- }
- }
- // The code 0x00 indicates all remaining AC coefficients are zero.
- if (zerorun > 0)
- {
- (this->*acfunction) (0, 0, 0) ;
- }
-
- return ;
- }
-
- //
- // Description
- //
- // This function sets the horizontal sampling frequency for the
- // component.
- //
- // Parameters:
- // value: The new sampling frequency.
- //
- void JpegEncoderComponent::SetHorizontalFrequency (unsigned int value)
- {
- if (value > JpegMaxSamplingFrequency || value < JpegMinSamplingFrequency)
- throw EJpegValueOutOfRange () ;
-
- h_frequency = value ;
- return ;
- }
-
- //
- // Description
- //
- // This function sets the vertical sampling frequency for the
- // component.
- //
- // Parameters:
- // value: The new sampling frequency.
- //
- void JpegEncoderComponent::SetVerticalFrequency (unsigned int value)
- {
- if (value > JpegMaxSamplingFrequency || value < JpegMinSamplingFrequency)
- throw EJpegValueOutOfRange () ;
-
- v_frequency = value ;
- return ;
- }
-
-