home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Examples / c09 / src / jpegenco.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-24  |  41.3 KB  |  1,420 lines

  1. //
  2. // Copyright (c) 1997,1998 Colosseum Builders, Inc.
  3. // All rights reserved.
  4. //
  5. // Colosseum Builders, Inc. makes no warranty, expressed or implied
  6. // with regards to this software. It is provided as is.
  7. //
  8. // See the README.TXT file that came with this software for information
  9. // on redistribution or send E-mail to info@colosseumbuilders.com
  10. //
  11. // o The user assumes all risk for using this software. The authors of this
  12. //   software shall be liable for no damages of any kind.
  13. //
  14. // o If the source code is distributed then this copyright notice must
  15. //   remain unaltered and any modification must be noted.
  16. //
  17. // o If this code is shipped in binary format the accompanying documentation
  18. //   should state that "this software is based, in part, on the work of
  19. //   Colosseum Builders, Inc."
  20. //
  21.  
  22. //
  23. // JPEG Encoder Library.
  24. //
  25. // Title:   JpegEncoder Class Implementation
  26. //
  27. // Author: John M. Miano  miano@colosseumbuilders.com
  28. //
  29. //
  30.  
  31. #include <math.h>
  32. #include <string>
  33. #include "jpegenco.h"
  34. #include "bitimage.h"
  35. #include "jfif.h"
  36. #include "jpenquan.h"
  37. #include "jpenhuff.h"         
  38.  
  39.  
  40. //
  41. // These are sample quantization tables defined in the the JPEG Standard.
  42. //
  43.  
  44. // From Section K.1 Table K-1
  45. static const unsigned int default_luminance_table [JpegSampleSize]  =
  46. {
  47. 16, 11, 10, 16,  24,  40,  51,  61,
  48. 12, 12, 14, 19,  26,  58,  60,  55,
  49. 14, 13, 16, 24,  40,  57,  69,  56,
  50. 14, 17, 22, 29,  51,  87,  80,  62,
  51. 18, 22, 37, 56,  68, 109, 103,  77,
  52. 24, 35, 55, 64,  81, 104, 113,  92,
  53. 49, 64, 78, 87, 103, 121, 120, 101,
  54. 72, 92, 95, 98, 112, 100, 103,  99,
  55. } ;
  56.  
  57. // From Section K.1 Table K-2
  58. static const unsigned int default_chrominance_table [JpegSampleSize] =
  59. {
  60. 17, 18, 24, 47, 99, 99, 99, 99,
  61. 18, 21, 26, 66, 99, 99, 99, 99,
  62. 24, 26, 56, 99, 99, 99, 99, 99,
  63. 47, 66, 99, 99, 99, 99, 99, 99,
  64. 99, 99, 99, 99, 99, 99, 99, 99,
  65. 99, 99, 99, 99, 99, 99, 99, 99,
  66. 99, 99, 99, 99, 99, 99, 99, 99,
  67. 99, 99, 99, 99, 99, 99, 99, 99,
  68. } ;
  69.  
  70. //
  71. //  Description:
  72. //
  73. //    Class Default Constructor
  74. //
  75. JpegEncoder::JpegEncoder ()
  76. {
  77.   Initialize () ;
  78.   return ;
  79. }
  80.  
  81. //
  82. //  Description:
  83. //
  84. //    Class Copy Constructor
  85. //
  86. JpegEncoder::JpegEncoder (const JpegEncoder &source)
  87. {
  88.   Initialize () ;
  89.   DoCopy (source) ;
  90.   return ;
  91. }
  92.  
  93. //
  94. //  Description:
  95. //
  96. //    Class Destructor
  97. //
  98. JpegEncoder::~JpegEncoder ()
  99. {
  100.   delete [] ac_tables ; ac_tables = NULL ;
  101.   delete [] dc_tables ; dc_tables = NULL ;
  102.   delete chrominance_quanttbl ; chrominance_quanttbl = NULL ;
  103.   delete luminance_quanttbl ; luminance_quanttbl = NULL ;
  104.   return ;
  105. }
  106. //
  107. //  Description:
  108. //
  109. //    Class assignment operator.
  110. //
  111. JpegEncoder &JpegEncoder::operator=(const JpegEncoder &source)
  112. {
  113.   DoCopy (source) ;
  114.   return *this ;
  115. }
  116. //
  117. //  Description:
  118. //
  119. //    Class copy function. This function gets called from the
  120. //    copy constructor and assignment operator.  The only thing
  121. //    we copy are the use settable parameters.
  122. //
  123. void JpegEncoder::DoCopy (const JpegEncoder &source)
  124. {
  125.   gray_scale = source.gray_scale ;
  126.   rows_per_restart = source.rows_per_restart ;
  127.   comment_string = source.comment_string ;
  128.   image_quality = source.image_quality ;
  129.  
  130.   for (unsigned int ii = 0 ; ii < MaxScans ; ++ ii)
  131.     image_scans [ii] = source.image_scans [ii] ;
  132.  
  133.   BitmapImageCoder::operator=(source) ;
  134.   return ;
  135. }
  136. //
  137. //  Description:
  138. //
  139. //    This function writes an image to the output stream.
  140. //
  141. //  Parameters:
  142. //    strm:   The output stream to write the image to. This most be opened in
  143. //            binary mode
  144. //    image:  The image to output.
  145. //
  146. void JpegEncoder::WriteImage (std::ostream &strm, BitmapImage &image)
  147. {
  148.   bit_count = 0 ;
  149.   current_image = &image ;
  150.  
  151.   output_stream = &strm ;
  152.  
  153.   CreateQuantizationTables (image_quality) ;
  154.  
  155.   frame_height = image.Height () ;
  156.   frame_width = image.Width () ;
  157.  
  158.   // Find the MCU size and maximum sampling frequencies.
  159.   CalculateMcuDimensions () ;
  160.  
  161.   // Validate Parameters. If there is an error this function will throw
  162.   // an exception.
  163.   ValidateParameters () ;
  164.  
  165.   CountPassesForProgressReporting () ;
  166.  
  167.   // Write the image header.
  168.   OutputMarker (SOI) ;
  169.   OutputMarker (APP0) ;
  170.   OutputJfifHeader () ;
  171.  
  172.   if (comment_string != "")
  173.     PrintComment (comment_string) ;
  174.  
  175.   PrintComment ("Created using the Colosseum Builders JPEG library") ;
  176.  
  177.   PrintSequentialFrame (image) ;
  178.  
  179.   OutputMarker (EOI) ;
  180.  
  181.   // Make sure that we are not holding on to any memory we do not
  182.   // need any more.
  183.   image_components [YComponent].FreeDynamicStorage () ;
  184.   image_components [CbComponent].FreeDynamicStorage () ;
  185.   image_components [CrComponent].FreeDynamicStorage () ;
  186.  
  187.   return ;
  188. }
  189. //
  190. //  Description:
  191. //
  192. //    Class Initialization function. This function is intended to be
  193. //    called from constructors.
  194. //
  195. void JpegEncoder::Initialize ()
  196. {
  197.   memset (image_scans, 0, sizeof (image_scans)) ;
  198.   image_scans [0].component_mask = (1<<YComponent)
  199.                                  |(1<<CbComponent)
  200.                                  |(1<<CrComponent) ;
  201.   image_quality = 75 ;
  202.   progress_function = NULL ;
  203.   progress_data = NULL ;
  204.   restart_interval = 0 ;
  205.   rows_per_restart = 4 ;
  206.   for (unsigned int ii = 0 ; ii < MaxComponents ; ++ ii)
  207.   {
  208.     image_components [ii].SetHorizontalFrequency (1) ;
  209.     image_components [ii].SetVerticalFrequency (1) ;
  210.   }
  211.  
  212.   ac_tables = new JpegEncoderHuffmanTable [2] ;
  213.   dc_tables = new JpegEncoderHuffmanTable [2] ;
  214.   chrominance_quanttbl = new JpegEncoderQuantizationTable ;
  215.   luminance_quanttbl = new JpegEncoderQuantizationTable ;
  216.  
  217.   image_components [YComponent].SetHuffmanTables (dc_tables [0],
  218.                                                   ac_tables [0]) ;
  219.   image_components [CbComponent].SetHuffmanTables (dc_tables [1],
  220.                                                    ac_tables [1]) ;
  221.   image_components [CrComponent].SetHuffmanTables (dc_tables [1],
  222.                                                    ac_tables [1]) ;
  223.  
  224.   image_components [YComponent].SetQuantizationTable (*luminance_quanttbl) ;
  225.   image_components [CbComponent].SetQuantizationTable (
  226.                                           *chrominance_quanttbl) ;
  227.   image_components [CrComponent].SetQuantizationTable (
  228.                                           *chrominance_quanttbl) ;
  229.  
  230.   return ;
  231. }
  232.  
  233.  
  234. //
  235. //  Description:
  236. //
  237. //    This function creates the quantization tables for writing the image.
  238. //
  239. //    Rather than have the user specify all 128 quantization table
  240. //    values we have the user specify a quality vale in the range
  241. //    1..100 then scale the sample quantization tables in the JPEG
  242. //    specification. A quality value of 50 uses the unmodified tables.
  243. //    At a quality value of 100 no quantization takes place (all 1s).
  244. //    A quality value of 1 will create a solid black image. Quality
  245. //    values below around 25 are pretty useless.
  246. //
  247. //  Parameters:
  248. //    quality:  The image quality (1-100)
  249. //
  250.  
  251. void JpegEncoder::CreateQuantizationTables (unsigned int quality)
  252. {
  253.   // We need this declaration because MSVC++ does not support
  254.   // standard scoping in for statements.
  255.   unsigned int ii ;
  256.  
  257.   if (quality < 1 || quality > 100)
  258.     throw EJpegValueOutOfRange () ;
  259.  
  260.   // Scale Factor
  261.   double scale = exp ((6 * (50 - (int) quality)/50.0) * log (2.0)) ;
  262.  
  263.   for (ii = 0 ; ii < JpegSampleSize ; ++ ii)
  264.   {
  265.     unsigned int value =
  266.          default_luminance_table [JpegZigZagInputOrder (ii)]
  267.          * scale ;
  268.     if (value < JpegMinQuantizationValue)
  269.       (*luminance_quanttbl) [ii] = JpegMinQuantizationValue ;
  270.     else if (value > JpegMax8BitQuantizationValue)
  271.       (*luminance_quanttbl) [ii] = JpegMax8BitQuantizationValue ;
  272.     else
  273.       (*luminance_quanttbl) [ii] = value ;
  274.   }
  275.  
  276.   for (ii = 0 ; ii < JpegSampleSize ; ++ ii)
  277.   {
  278.     unsigned int value =
  279.         default_chrominance_table [JpegZigZagInputOrder (ii)]
  280.         * scale ;
  281.     if (value < 1)
  282.       (*chrominance_quanttbl) [ii] = JpegMinQuantizationValue ;
  283.     else if (value > JpegMax8BitQuantizationValue)
  284.       (*chrominance_quanttbl) [ii] = JpegMax8BitQuantizationValue ;
  285.     else
  286.       (*chrominance_quanttbl) [ii] = value ;
  287.   }
  288.   return ;
  289.  
  290. }
  291.  
  292. //
  293. //  Description:
  294. //
  295. //    This function writes a single byte to the output stream.
  296. //
  297. //  Parameters:
  298. //    value: The byte to be written to the output stream.
  299. //
  300. void JpegEncoder::OutputByte (UBYTE1 value)
  301. {
  302.   if (bit_count != 0)
  303.     FlushBitBuffer () ;
  304.  
  305.   output_stream->write ((char *) &value, sizeof (value)) ;
  306.   return ;
  307. }
  308.  
  309. //
  310. //  Description:
  311. //
  312. //    This function writes a 2-byte integer in system format to the output
  313. //    stream in bit-endian order (most significant byte first).
  314. //
  315. //  Parameters:
  316. //    value: The 2-byte data to be written to the output stream
  317. //
  318. void JpegEncoder::OutputWord (UBYTE2 value)
  319. {
  320.   if (bit_count != 0)
  321.     FlushBitBuffer () ;
  322.  
  323.   UBYTE2 data = SystemToBigEndian (value) ;
  324.   output_stream->write ((char *) &data, sizeof (data)) ;
  325.   return ;
  326. }
  327.  
  328. //
  329. //  Description:
  330. //
  331. //    This function outputs a single bit to the output stream.
  332. //
  333. //    Individual its are buffered using the bit_buffer and bit_count member
  334. //    variables.
  335. //
  336. //    This function throws an exception if it is called with a zero bit count.
  337. //    We use this for error trapping since no place in the rest of the
  338. //    code should attempt to write zero bits.
  339. //
  340. //  Parameters:
  341. //    bits: The bit string to be output
  342. //    count: The number of bits to output
  343. //
  344. void JpegEncoder::OutputBits (int bits, unsigned int count)
  345. {
  346.   if (count == 0)
  347.     throw EJpegFatal ("Internal Error - Invalid Bit Count") ;
  348.  
  349.   for (unsigned int ii = 0 ; ii < count ; ++ ii)
  350.   {
  351.     bit_buffer <<= 1 ;
  352.     ++ bit_count ;
  353.     bit_buffer |= ((bits >> (count - ii - 1)) & 0x1) ;
  354.     if (bit_count == 8)
  355.     {
  356.       output_stream->write ((char *) &bit_buffer, 1) ;
  357.       // The Sequence FF00 in the files is used to represent the value FF
  358.       // in the stream to differentiate it from a marker.
  359.       if (bit_buffer == SOB)
  360.       {
  361.         bit_buffer = 0 ;
  362.         output_stream->write ((char *) &bit_buffer, 1) ;
  363.       }
  364.       bit_count = 0 ;
  365.     }
  366.   }
  367.   return ;
  368. }
  369.  
  370. //
  371. //  Description:
  372. //
  373. //    This function flushes the bit buffer. This causes buffered bit streams
  374. //    of less than the bit buffer size to be written out.
  375. //
  376. void JpegEncoder::FlushBitBuffer ()
  377. {
  378.   if (bit_count != 0)
  379.   {
  380.     bit_buffer <<= (8 - bit_count) ;
  381.     output_stream->write ((char *) &bit_buffer, 1) ;
  382.     bit_count = 0 ;
  383.   }
  384.   return ;
  385. }
  386.  
  387. //
  388. //  This function writes a marker to the output stream.
  389. //
  390. //  Parameters:
  391. //    marker: The marker to be written to the output stream
  392. //
  393. void JpegEncoder::OutputMarker (UBYTE1 marker)
  394. {
  395.   OutputByte (SOB) ;
  396.   OutputByte (marker) ;
  397.   return ;
  398. }
  399.  
  400. //
  401. //  Description:
  402. //
  403. //    This function validates the user-set output parameters. If an error is
  404. //    detected an EJpegBadOutputParameter exception is thrown.
  405. //
  406.  
  407. void JpegEncoder::ValidateParameters ()
  408. {
  409.   // Ensure we do not have fractional sampling of pixels.
  410.   if (! gray_scale)
  411.   {
  412.     if (image_components [YComponent].GetHorizontalFrequency () == 3
  413.         || image_components [CbComponent].GetHorizontalFrequency () == 3
  414.         || image_components [CrComponent].GetHorizontalFrequency () == 3)
  415.     {
  416.       if (image_components [YComponent].GetHorizontalFrequency () == 2
  417.           || image_components [YComponent].GetHorizontalFrequency () == 4
  418.           || image_components [CbComponent].GetHorizontalFrequency () == 2
  419.           || image_components [CbComponent].GetHorizontalFrequency () == 4
  420.           || image_components [CrComponent].GetHorizontalFrequency () == 2
  421.           || image_components [CrComponent].GetHorizontalFrequency () == 4)
  422.       {
  423.         throw EJpegError ("Fractional Horizontal Sampling") ;
  424.       }
  425.     }
  426.  
  427.     if (image_components [YComponent].GetVerticalFrequency () == 3
  428.         || image_components [CbComponent].GetVerticalFrequency () == 3
  429.         || image_components [CrComponent].GetVerticalFrequency () == 3)
  430.     {
  431.       if (image_components [YComponent].GetVerticalFrequency () == 2
  432.           || image_components [YComponent].GetVerticalFrequency () == 4
  433.           || image_components [CbComponent].GetVerticalFrequency () == 2
  434.           || image_components [CbComponent].GetVerticalFrequency () == 4
  435.           || image_components [CrComponent].GetVerticalFrequency () == 2
  436.           || image_components [CrComponent].GetVerticalFrequency () == 4)
  437.       {
  438.         throw EJpegError ("Fractional Vertical Sampling") ;
  439.       }
  440.     }
  441.   }
  442.  
  443.   if (! gray_scale)
  444.   {
  445.     if ((image_scans [0].component_mask
  446.         |image_scans [1].component_mask|image_scans [2].component_mask)
  447.         != ((1<<YComponent)|(1<<CbComponent)|(1<<CrComponent)))
  448.     {
  449.       throw EJpegError ("Not all components specified in scans") ;
  450.     }
  451.     if ((image_scans [0].component_mask
  452.          +image_scans [1].component_mask
  453.          +image_scans [2].component_mask)
  454.         != ((1<<YComponent)|(1<<CbComponent)|(1<<CrComponent)))
  455.     {
  456.       throw EJpegError ("Component in more than one scan") ;
  457.     }
  458.  
  459.     if (image_scans [2].component_mask != 0)
  460.       scan_count = 3 ;
  461.     else if (image_scans [1].component_mask != 0)
  462.       scan_count = 2 ;
  463.     else
  464.       scan_count = 1 ;
  465.   }
  466.   else
  467.   {
  468.     scan_count = 1 ;
  469.   }
  470.  
  471.   // Enforce the MCU size limitation in Section B.2.3
  472.   //
  473.   // I am not certain why this limitation of 10 data units per MCU even
  474.   // exists. It seems to be an silly arbitrary limit. Maybe its to set
  475.   // a maximum upper size for an MCU decoding buffer. In any event we
  476.   // must abide by it.
  477.   if (! gray_scale)
  478.   {
  479.     for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
  480.     {
  481.       unsigned int dataunits = 0 ;
  482.       unsigned int componentcount = 0 ;
  483.       if ((image_scans [ii].component_mask & (1<<YComponent)) != 0)
  484.       {
  485.         dataunits += image_components [YComponent].GetHorizontalFrequency ()
  486.                      * image_components [YComponent].GetVerticalFrequency () ;
  487.         ++ componentcount ;
  488.       }
  489.       if ((image_scans [ii].component_mask & (1<<CbComponent)) != 0)
  490.       {
  491.         dataunits += image_components [CbComponent].GetHorizontalFrequency ()
  492.                   * image_components [CbComponent].GetVerticalFrequency () ;
  493.         ++ componentcount ;
  494.       }
  495.       if ((image_scans [ii].component_mask & (1<<CrComponent)) != 0)
  496.       {
  497.         dataunits += image_components [CrComponent].GetHorizontalFrequency ()
  498.                   * image_components [CrComponent].GetVerticalFrequency () ;
  499.         ++ componentcount ;
  500.       }
  501.       if (dataunits > JpegMaxDataUnitsPerMCU && componentcount > 1)
  502.         throw EJpegBadOutputParameter ("Data units in MCU exceeds 10") ;
  503.     }
  504.   }
  505.   return ;
  506. }
  507. //
  508. //  Description:
  509. //
  510. //    This function writes a comment marker to the output stream.
  511. //
  512. //  Parameters:
  513. //    str:  The comment string
  514. //
  515. void JpegEncoder::PrintComment (const std::string &str)
  516. {
  517.   unsigned int length = sizeof (UBYTE2) + str.length () + 1 ;
  518.   OutputMarker (COM) ;
  519.   OutputWord (length) ;
  520.   for (unsigned int ii = 0 ; ii < str.length () ; ++ ii)
  521.     OutputByte (str.c_str ()[ii]) ;
  522.  
  523.   OutputByte (0) ;
  524.   return ;
  525. }
  526.  
  527.  
  528. //
  529. //  Description:
  530. //
  531. //    This function writes the quantization tables to the output stream.
  532. //
  533. void JpegEncoder::PrintQuantizationTables ()
  534. {
  535.   // We need this declaration here because MSVC++ does not conform
  536.   // to standard scoping in for statements.
  537.   unsigned int ii ;
  538.  
  539.   const int precision = 0 ; // Byte Precision
  540.   int index ;
  541.   UBYTE1 pqtq ;
  542.  
  543.   // Section B.2.4.1
  544.  
  545.   if (gray_scale)
  546.   {
  547.     OutputMarker (DQT) ;
  548.     OutputWord (sizeof(UBYTE2) + (sizeof (pqtq) + JpegSampleSize)) ;
  549.  
  550.     index = 0 ;
  551.     pqtq = (precision << 4) | index ;
  552.     OutputByte (pqtq) ;
  553.     for (ii = 0 ; ii < JpegSampleSize ; ++ ii)
  554.       OutputByte ((*luminance_quanttbl) [ii]) ;
  555.   }
  556.   else
  557.   {
  558.     OutputMarker (DQT) ;
  559.     OutputWord (sizeof(UBYTE2) + 2 * (sizeof (pqtq) + JpegSampleSize)) ;
  560.  
  561.     index = 0 ;
  562.     pqtq = (precision << 4) | index ;
  563.     OutputByte (pqtq) ;
  564.     for (ii = 0 ; ii < JpegSampleSize ; ++ ii)
  565.       OutputByte ((*luminance_quanttbl) [ii]) ;
  566.  
  567.     index = 1 ;
  568.     pqtq = (precision << 4) | index ;
  569.     OutputByte (pqtq) ;
  570.     for (ii = 0 ; ii < JpegSampleSize ; ++ ii)
  571.       OutputByte ((*chrominance_quanttbl) [ii]) ;
  572.   }
  573.   return ;
  574. }
  575.  
  576. //
  577. //  Description:
  578. //
  579. //    This function is called by a scan to write a restart interval to the
  580. //    output stream. We do not output a Define Restart Interval marker if
  581. //    the restart interval is not changing.
  582. //
  583. //  Parameters:
  584. //    restartinterval: The new restart interval
  585. //
  586. void JpegEncoder::OutputRestartInterval (unsigned int restartinterval)
  587. {
  588.   if (restartinterval == restart_interval)
  589.     return ;
  590.   restart_interval =  restartinterval ;
  591.  
  592.   // B.2.4.4
  593.   OutputMarker (DRI) ;
  594.   OutputWord (4) ;
  595.   OutputWord (restartinterval) ;
  596.   return ;
  597. }
  598.  
  599.  
  600. //
  601. //  Description:
  602. //
  603. //    This function writes a sequential frame to the output stream. We create
  604. //    frames with either one (black & white) or three (color) components.
  605. //
  606. //  Parameters:
  607. //    image: The image to be written in the frame
  608. //
  609. void JpegEncoder::PrintSequentialFrame (BitmapImage &image)
  610. {
  611.   // Sample the components
  612.   if (gray_scale)
  613.   {
  614.     ++ current_pass ;
  615.     image_components [YComponent].SampleYComponent (
  616.                                      *this,
  617.                                      image,
  618.                                      max_horizontal_frequency,
  619.                                      max_vertical_frequency) ;
  620.   }
  621.   else
  622.   {
  623.     ++ current_pass ;
  624.     image_components [YComponent].SampleYComponent (*this,
  625.                                                     image,
  626.                                                     max_horizontal_frequency,
  627.                                                     max_vertical_frequency) ;
  628.     ++ current_pass ;
  629.     image_components [CbComponent].SampleCbComponent (
  630.                                            *this,
  631.                                            image,
  632.                                            max_horizontal_frequency,
  633.                                            max_vertical_frequency) ;
  634.     ++ current_pass ;
  635.     image_components [CrComponent].SampleCrComponent (
  636.                                            *this,
  637.                                            image,
  638.                                            max_horizontal_frequency,
  639.                                            max_vertical_frequency) ;
  640.   }
  641.  
  642.   // Write the Frame Header
  643.   // Section B.2.2
  644.  
  645.   OutputMarker (SOF0) ;
  646.   if (gray_scale)  // Length
  647.     OutputWord (8 + 3) ;
  648.   else
  649.     OutputWord (8 + 3 * 3) ;
  650.  
  651.   OutputByte (8) ; // Precision
  652.   OutputWord (image.Height ()) ;
  653.   OutputWord (image.Width ()) ;
  654.  
  655.   if (gray_scale)
  656.   {
  657.     OutputByte (1) ;  // Component Count
  658.     OutputByte(YComponent) ;
  659.     OutputByte (
  660.         (image_components [YComponent].GetHorizontalFrequency () << 4)
  661.         | image_components [YComponent].GetVerticalFrequency ()) ;
  662.     OutputByte (0) ;  // Quantization Table
  663.  
  664.  
  665.     PrintQuantizationTables () ;
  666.     scan_component_count = 1 ;
  667.     scan_components [0] = &image_components [YComponent] ;
  668.     ++ current_pass ;
  669.     PrintSequentialScan (image_scans [0]) ;
  670.   }
  671.   else
  672.   {
  673.     OutputByte (3) ;  // Component Count
  674.     OutputByte(YComponent) ;
  675.     OutputByte (
  676.         (image_components [YComponent].GetHorizontalFrequency () << 4)
  677.         | image_components [YComponent].GetVerticalFrequency ()) ;
  678.     OutputByte (0) ;  // Quantization Table
  679.  
  680.     OutputByte(CbComponent) ;
  681.     OutputByte (
  682.         (image_components [CbComponent].GetHorizontalFrequency () << 4)
  683.         | image_components [CbComponent].GetVerticalFrequency ()) ;
  684.     OutputByte (1) ;  // Quantization Table
  685.  
  686.     OutputByte(CrComponent) ;
  687.     OutputByte (
  688.         (image_components [CrComponent].GetHorizontalFrequency () << 4)
  689.         | image_components [CrComponent].GetVerticalFrequency ()) ;
  690.     OutputByte (1) ;  // Quantization Table
  691.  
  692.     PrintQuantizationTables () ;
  693.  
  694.     // Print the scans that make up the frame.
  695.     for (unsigned int ii = 0 ; ii < scan_count ; ++ ii)
  696.     {
  697.       ++ current_pass ;
  698.       FindComponentsInScan (image_scans [ii]) ;
  699.       PrintSequentialScan (image_scans [ii]) ;
  700.     }
  701.   }
  702.  
  703.   return ;
  704. }
  705.  
  706. //
  707. //  Description:
  708. //
  709. //    This function writes a sequential scan to the output stream.
  710. //
  711. //  Parameters:
  712. //    scan:   The scan descriptor
  713. //
  714. void JpegEncoder::PrintSequentialScan (const Scan &scan)
  715. {
  716.   if (scan_component_count == 0)
  717.     throw EJpegFatal ("INTERNAL ERROR - No components defined for scan") ;
  718.  
  719.   // Output the restart interval and the Huffman tables. We must set the
  720.   // restart interval *BEFORE* gathering statistics.
  721.   if (scan_component_count != 1)
  722.   {
  723.     OutputRestartInterval (rows_per_restart * mcu_cols) ;
  724.   }
  725.   else
  726.   {
  727.     OutputRestartInterval (rows_per_restart
  728.       * scan_components [0]->DataUnitCols ()) ;
  729.   }
  730.  
  731.   // Gather Huffman Statistics
  732.   if ((scan.component_mask & (1<<YComponent)) != 0)
  733.   {
  734.     dc_tables [0].Reset () ;
  735.     ac_tables [0].Reset () ;
  736.   }
  737.   if ((scan.component_mask & (1<<YComponent)) == 0
  738.       || scan_component_count != 1)
  739.   {
  740.     ac_tables [1].Reset () ;
  741.     dc_tables [1].Reset () ;
  742.   }
  743.  
  744.  
  745.   if (scan_component_count != 1)
  746.   {
  747.     InterleavedPass (false,
  748.           JpegEncoderComponent::EncodeSequential,
  749.           JpegEncoderComponent::GatherDcData,
  750.           JpegEncoderComponent::GatherAcData,
  751.           0, JpegSampleSize - 1, 0) ;
  752.   }
  753.   else
  754.   {
  755.     NoninterleavedPass (false,
  756.           JpegEncoderComponent::EncodeSequential,
  757.           JpegEncoderComponent::GatherDcData,
  758.           JpegEncoderComponent::GatherAcData,
  759.           0, JpegSampleSize - 1, 0) ;
  760.   }
  761.  
  762.   // Create the Huffman Tables
  763.   if ((scan.component_mask & (1<<YComponent)) != 0)
  764.   {
  765.     dc_tables [0].BuildTable () ;
  766.     ac_tables [0].BuildTable () ;
  767.   }
  768.   if ((scan.component_mask & (1<<YComponent)) == 0
  769.        || scan_component_count != 1)
  770.   {
  771.     ac_tables [1].BuildTable () ;
  772.     dc_tables [1].BuildTable () ;
  773.   }
  774.  
  775.   // Output the Huffman tables
  776.   PrintHuffmanTables (scan, true, true) ; // Output DC and AC tables.
  777.  
  778.   // Create the scan marker.
  779.   // Section B.2.3
  780.   OutputMarker (SOS) ;
  781.   OutputWord (6 + 2 * scan_component_count) ;  // Length
  782.   OutputByte (scan_component_count) ;  // Component Count
  783.  
  784.   if ((scan.component_mask & (1<<YComponent)) != 0)
  785.   {
  786.     OutputByte (0x01) ; // YComponent
  787.     OutputByte (0x00) ; // Entropy Tables
  788.   }
  789.   if (! gray_scale)
  790.   {
  791.     if ((scan.component_mask & (1<<CbComponent)) != 0)
  792.     {
  793.       OutputByte (0x02) ; // CbComponent
  794.       OutputByte (0x11) ; // Entropy Tables
  795.     }
  796.     if ((scan.component_mask & (1<<CrComponent)) != 0)
  797.     {
  798.       OutputByte (0x03) ; // CrComponent
  799.       OutputByte (0x11) ; // Entropy Tables
  800.     }
  801.   }
  802.  
  803.   OutputByte (0) ; // Spectral Selection Start
  804.   OutputByte (JpegSampleSize - 1) ; // Spectral Selection End
  805.   OutputByte (0) ; // Successive Approximation
  806.  
  807.   // Output the Scan data.
  808.   if (scan_component_count != 1)
  809.   {
  810.     InterleavedPass (true,
  811.           JpegEncoderComponent::EncodeSequential,
  812.           JpegEncoderComponent::PrintDcData,
  813.           JpegEncoderComponent::PrintAcData,
  814.           0, JpegSampleSize - 1, 0) ;
  815.   }
  816.   else
  817.   {
  818.     NoninterleavedPass (true,
  819.           JpegEncoderComponent::EncodeSequential,
  820.           JpegEncoderComponent::PrintDcData,
  821.           JpegEncoderComponent::PrintAcData,
  822.           0, JpegSampleSize - 1, 0) ;
  823.   }
  824.  
  825.   return ;
  826. }
  827.  
  828. //
  829. //  Description:
  830. //
  831. //    This function makes a pass through the data units for a non-interleaved
  832. //    Scan.
  833. //
  834. //    The reason for having a generic function that uses pointers to member
  835. //    functions to do processing is that there are several places where the
  836. //    control processing has to be identical in multiple passes where the
  837. //    low level actions are different. For example, the processing here when
  838. //    gathering Huffman statistics has to be identical to the processing when
  839. //    writing values to the output file. Using separate functions turned out
  840. //    to be error prone due to the difficulty of keeping multiple functions
  841. //    exactly in synchronization.
  842. //
  843. //  Parameters:
  844. //    writerestarts: false => This is a statistics gathering pass
  845. //                   true => This pass is writing data to the output file.
  846. //    passfunctions: Pointer to EncoderComponent member function used
  847. //                   to process this pass.
  848. //    dcfunction:    Pointer to the EncoderComponent member function used
  849. //                   to process DC coefficient values.
  850. //    acfunction:    Pointer to the EncoderComponent member function used
  851. //                   to process AC coefficient values.
  852. //    sss:           Spectral Selection Start (0-63)
  853. //    sse:           Spectral Selection End (0-63)
  854. //    ssa:           Successive Approximation (0-13)
  855. //
  856. void JpegEncoder::NoninterleavedPass (
  857.                     bool writedata,
  858.                     JpegEncoderComponent::COMPONENTPASSFUNCTION passfunction,
  859.                     JpegEncoderComponent::DCOUTPUTFUNCTION dcfunction,
  860.                     JpegEncoderComponent::ACOUTPUTFUNCTION acfunction,
  861.                     unsigned int sss,
  862.                     unsigned int sse,
  863.                     unsigned int ssa)
  864. {
  865.   // We use a scale integer to keep trake of progress to lessen the
  866.   // change that the progress increment will be zero.
  867.   const int progressscale = 8 ;
  868.   unsigned int progress ;
  869.   unsigned int progressincrement ;
  870.   if (writedata)
  871.     progress = 50 << progressscale ;
  872.   else
  873.     progress = 0 ;
  874.   progressincrement = (100 << progressscale)
  875.                     / (2 * scan_components [0]->DataUnitRows ()) ;
  876.  
  877.   ResetDcValues () ;
  878.  
  879.   unsigned int intervalcount = 0 ;
  880.   unsigned int restartmarker = 0 ;
  881.   for (unsigned int row = 0 ;
  882.        row < scan_components [0]->DataUnitRows () ;
  883.        ++ row)
  884.   {
  885.     for (unsigned int col = 0 ;
  886.          col < scan_components [0]->DataUnitCols () ;
  887.          ++ col, ++ intervalcount)
  888.     {
  889.       if (restart_interval != 0)
  890.       {
  891.         if (intervalcount == restart_interval && restart_interval != 0)
  892.         {
  893.           // E.1.4
  894.           if (writedata)
  895.             OutputMarker (RST0 | restartmarker) ;
  896.           ResetDcValues () ;
  897.           ++ restartmarker ;
  898.           restartmarker %= 8 ;
  899.           intervalcount = 0 ;
  900.         }
  901.       }
  902.       (scan_components [0]->*passfunction) (
  903.                                 row,
  904.                                 col,
  905.                                 dcfunction,
  906.                                 acfunction,
  907.                                 sss, sse,
  908.                                 ssa) ;
  909.  
  910.     }
  911.     progress += progressincrement ;
  912.     CallProgressFunction (progress >> progressscale) ;
  913.   }
  914.   CallProgressFunction (100) ;
  915.   return ;
  916. }
  917.  
  918. //
  919. //  Description:
  920. //
  921. //    This function makes a pass through the data units for an interleaved
  922. //    Scan.
  923. //
  924. //    The reason for having a generic function that uses pointers to member
  925. //    functions to do processing is that there are several places where the
  926. //    control processing has to be identical in multiple passes where the
  927. //    low level actions are different. For example, the processing here when
  928. //    gathering Huffman statistics has to be identical to the processing when
  929. //    writing values to the output file. Using separate functions turned out
  930. //    to be error prone due to the difficulty of keeping multiple functions
  931. //    exactly in synchronization.
  932. //
  933. //  Parameters:
  934. //     writerestarts: false => This is a statistics gathering pass
  935. //                    true => This pass is writing data to the output file.
  936. //     passfunctions: Pointer to EncoderComponent member function used
  937. //                    to process this pass.
  938. //     dcfunction:    Pointer to the EncoderComponent member function used
  939. //                    to process DC coefficient values.
  940. //     acfunction:    Pointer to the EncoderComponent member function used
  941. //                    to process AC coefficient values.
  942. //     sss:           Spectral Selection Start (0-63)
  943. //     sse:           Spectral Selection End (0-63)
  944. //     ssa:           Successive Approximation (0-13)
  945. //
  946. void JpegEncoder::InterleavedPass (
  947.                     bool writedata,
  948.                     JpegEncoderComponent::COMPONENTPASSFUNCTION passfunction,
  949.                     JpegEncoderComponent::DCOUTPUTFUNCTION dcfunction,
  950.                     JpegEncoderComponent::ACOUTPUTFUNCTION acfunction,
  951.                     unsigned int sss,
  952.                     unsigned int sse,
  953.                     unsigned int ssa)
  954. {
  955.   const int progressscale = 8 ;
  956.   unsigned int progress ;
  957.   unsigned int progressincrement ;
  958.   if (writedata)
  959.     progress = 50 << progressscale ;
  960.   else
  961.     progress = 0 ;
  962.   progressincrement = (100 << progressscale) / (2 * mcu_rows) ;
  963.  
  964.   ResetDcValues () ;
  965.  
  966.   unsigned int intervalcount = 0 ;
  967.   unsigned int restartmarker = 0 ;
  968.   for (unsigned int mcurow = 0 ;
  969.        mcurow < mcu_rows ;
  970.        ++ mcurow)
  971.   {
  972.     for (unsigned int mcucol = 0 ;
  973.          mcucol < mcu_cols ;
  974.           ++ mcucol, ++ intervalcount)
  975.     {
  976.       // Handle Restart Markers
  977.       if (restart_interval != 0)
  978.       {
  979.         if (intervalcount == restart_interval && restart_interval != 0)
  980.         {
  981.           if (writedata)
  982.             OutputMarker (RST0 | restartmarker) ;
  983.           ResetDcValues () ;
  984.           ++ restartmarker ;
  985.           restartmarker %= 8 ;
  986.           intervalcount = 0 ;
  987.         }
  988.       }
  989.  
  990.       for (unsigned int cc = 0 ; cc < scan_component_count ; ++ cc)
  991.       {
  992.         for (unsigned int cy = 0 ;
  993.              cy < scan_components [cc]->GetVerticalFrequency () ;
  994.              ++ cy)
  995.         {
  996.           unsigned int durow = scan_components [cc]->GetVerticalFrequency ()
  997.                              * mcurow + cy ;
  998.           for (unsigned int cx = 0 ;
  999.                cx < scan_components [cc]->GetHorizontalFrequency () ;
  1000.                ++ cx)
  1001.           {
  1002.             unsigned int ducol
  1003.               = scan_components [cc]->GetHorizontalFrequency ()
  1004.               * mcucol + cx ;
  1005.             (scan_components [cc]->*passfunction) (durow, ducol,
  1006.                                               dcfunction, acfunction,
  1007.                                               sss, sse, ssa) ;
  1008.           }
  1009.         }
  1010.       }
  1011.     }
  1012.     progress += progressincrement ;
  1013.     CallProgressFunction (progress >> progressscale) ;
  1014.   }
  1015.   CallProgressFunction (100) ;
  1016.   return ;
  1017. }
  1018.  
  1019. //
  1020. //  Description:
  1021. //
  1022. //    This function writes the Huffman tables used by a scan to the output
  1023. //    stream.
  1024. //
  1025. //    We only use two DC and two AC tables to be compatible with baseline
  1026. //    JPEG.  In progressive JPEG there is really no reason for more than
  1027. //     two tables for RGB images. If we ever go to four colors then things
  1028. //    may need to change.
  1029. //
  1030. //    The Y component always uses table ID 0. The Cb and Cr components always
  1031. //    use table ID 1.
  1032. //
  1033. //  Parameters:
  1034. //    scan:     Here the scan structure is used to determine which components
  1035. //              are part of the scan (Y and/or Cb/Cr)
  1036. //    usedc:    Set to true if the scan includes DC components. (Sequential
  1037. //              Scan or Progressive Scan with the spectral selection 0)
  1038. //    useac:    Set to true if the scan includes AC components. (Sequential
  1039. //              Scan or Progressive Scan with the spectral selection start
  1040. //              not zero)
  1041. //
  1042. void JpegEncoder::PrintHuffmanTables (const Scan &scan,
  1043.                                       bool usedc,
  1044.                                       bool useac)
  1045. {
  1046.   // Section B.2.4.2
  1047.  
  1048.   if ((scan.component_mask & (1 << YComponent)) != 0)
  1049.   {
  1050.     // See if this is a color image.
  1051.     if (scan_component_count != 1)
  1052.     {
  1053.       // We have at least two components and the first is the Y component.
  1054.       // This means we need the both of the huffman tables.
  1055.       // B.2.4.2
  1056.       OutputMarker (DHT) ;
  1057.       unsigned int size = sizeof (UBYTE2) ;
  1058.       if (usedc)
  1059.       {
  1060.         size += dc_tables [0].OutputSize ()
  1061.                 + dc_tables [1].OutputSize () ;
  1062.       }
  1063.       if (useac)
  1064.       {
  1065.         size += ac_tables [0].OutputSize ()
  1066.                 + ac_tables [1].OutputSize () ;
  1067.       }
  1068.       OutputWord (size) ;
  1069.       if (usedc)
  1070.       {
  1071.         OutputByte (0x00) ;
  1072.         dc_tables [0].PrintTable (*this) ;
  1073.       }
  1074.       if (useac)
  1075.       {
  1076.         OutputByte (0x10) ;
  1077.         ac_tables [0].PrintTable (*this) ;
  1078.       }
  1079.       if (usedc)
  1080.       {
  1081.         OutputByte (0x01) ;
  1082.         dc_tables [1].PrintTable (*this) ;
  1083.       }
  1084.       if (useac)
  1085.       {
  1086.         OutputByte (0x11) ;
  1087.         ac_tables [1].PrintTable (*this) ;
  1088.       }
  1089.     }
  1090.     else
  1091.     {
  1092.       // The only component is Y
  1093.       unsigned int size = sizeof (UBYTE2) ;
  1094.       if (usedc)
  1095.       {
  1096.         size += dc_tables [0].OutputSize () ;
  1097.       }
  1098.       if (useac)
  1099.       {
  1100.         size += ac_tables [0].OutputSize () ;
  1101.       }
  1102.  
  1103.       OutputMarker (DHT) ;
  1104.       OutputWord (size) ;
  1105.       if (usedc)
  1106.       {
  1107.         OutputByte (0x00) ;
  1108.         dc_tables [0].PrintTable (*this) ;
  1109.       }
  1110.       if (useac)
  1111.       {
  1112.         OutputByte (0x10) ;
  1113.         ac_tables [0].PrintTable (*this) ;
  1114.       }
  1115.     }
  1116.   }
  1117.   else
  1118.   {
  1119.     // The Y component is not present. Output is the same for
  1120.     // Cb, Cr, or Cb & Cr.
  1121.     unsigned int size = sizeof (UBYTE2) ;
  1122.     if (usedc)
  1123.     {
  1124.       size += dc_tables [1].OutputSize () ;
  1125.     }
  1126.     if (useac)
  1127.     {
  1128.       size += ac_tables [1].OutputSize () ;
  1129.     }
  1130.  
  1131.     OutputMarker (DHT) ;
  1132.     OutputWord (size) ;
  1133.     if (usedc)
  1134.     {
  1135.       OutputByte (0x01) ;
  1136.       dc_tables [1].PrintTable (*this) ;
  1137.     }
  1138.     if (useac)
  1139.     {
  1140.       OutputByte (0x11) ;
  1141.       ac_tables [1].PrintTable (*this) ;
  1142.     }
  1143.   }
  1144.   return ;
  1145. }
  1146.  
  1147. //
  1148. //  Description:
  1149. //
  1150. //   This function resets the DC difference values for all
  1151. //   all the components in the scan.  We do this at the start of
  1152. //   each scan and whenever we output a restart marker.
  1153. //
  1154. void JpegEncoder::ResetDcValues ()
  1155. {
  1156.   for (unsigned int ii = 0 ; ii < scan_component_count ; ++ ii)
  1157.     scan_components [ii]->ResetDcDifference () ;
  1158.   return ;
  1159. }
  1160.  
  1161. //
  1162. //  Description:
  1163. //
  1164. //    This function determines the dimensions of an MCU using the maximum
  1165. //    sampling frequencies of the components.
  1166. //
  1167. void JpegEncoder::CalculateMcuDimensions ()
  1168. {
  1169.   max_horizontal_frequency = 1 ;
  1170.   max_vertical_frequency = 1 ;
  1171.  
  1172.   if (! gray_scale)
  1173.   {
  1174.     for (unsigned int ii = YComponent ; ii <= CrComponent ; ++ ii)
  1175.     {
  1176.       if (image_components [ii].GetHorizontalFrequency ()
  1177.           > max_horizontal_frequency)
  1178.       {
  1179.         max_horizontal_frequency
  1180.           = image_components [ii].GetHorizontalFrequency () ;
  1181.       }
  1182.  
  1183.       if (image_components [ii].GetVerticalFrequency ()
  1184.           > max_vertical_frequency)
  1185.       {
  1186.         max_vertical_frequency
  1187.           = image_components [ii].GetVerticalFrequency () ;
  1188.       }
  1189.     }
  1190.   }
  1191.   else
  1192.   {
  1193.     max_horizontal_frequency
  1194.       = image_components [YComponent].GetHorizontalFrequency () ;
  1195.     max_vertical_frequency
  1196.       = image_components [YComponent].GetVerticalFrequency () ;
  1197.   }
  1198.  
  1199.   unsigned int mcuheight = max_vertical_frequency * JpegSampleWidth ;
  1200.   unsigned int mcuwidth = max_horizontal_frequency * JpegSampleWidth ;
  1201.   mcu_rows = (frame_height + mcuheight - 1) / mcuheight ;
  1202.   mcu_cols = (frame_width + mcuwidth - 1) / mcuwidth ;
  1203.   return ;
  1204. }
  1205.  
  1206. //
  1207. //  Description:
  1208. //
  1209. //    This function determines which components is in a given scan.
  1210. //
  1211. //  Parameters:
  1212. //    scan:  The structure that contains the scan parameters.
  1213. //
  1214. //  Implicit Outputs:
  1215. //    scan_component_count: The number of components in the scan.
  1216. //    scan_components:      The list of components in the scan.
  1217. //
  1218.  
  1219. void JpegEncoder::FindComponentsInScan (Scan &scan)
  1220. {
  1221.   scan_component_count = 0 ;
  1222.   if ((scan.component_mask & (1 <<YComponent)) != 0)
  1223.   {
  1224.     scan_components [scan_component_count] = &image_components [YComponent] ;
  1225.     ++ scan_component_count ;
  1226.   }
  1227.   if (! gray_scale)
  1228.   {
  1229.     if ((scan.component_mask & (1 <<CbComponent)) != 0)
  1230.     {
  1231.       scan_components [scan_component_count]
  1232.         = &image_components [CbComponent] ;
  1233.       ++ scan_component_count ;
  1234.     }
  1235.     if ((scan.component_mask & (1 <<CrComponent)) != 0)
  1236.     {
  1237.       scan_components [scan_component_count]
  1238.         = &image_components [CrComponent] ;
  1239.       ++ scan_component_count ;
  1240.     }
  1241.   }
  1242.   return ;
  1243. }
  1244.  
  1245. //
  1246. //  Description:
  1247. //
  1248. //    This function sets the sampling frequencies for a component
  1249. //
  1250. //  Parameters:
  1251. //    component:  The component ID
  1252. //    hf:         Horizontal Frequency
  1253. //    vf:         Vertical Frequency
  1254. //
  1255. void JpegEncoder::SetSamplingFrequency (unsigned int component,   
  1256.                                         unsigned int hf,
  1257.                                         unsigned int vf)
  1258. {
  1259.   if (component >= MaxComponents)
  1260.     throw EJpegError ("Invalid Component ID") ;
  1261.  
  1262.   if (hf > JpegMaxSamplingFrequency || hf < JpegMinSamplingFrequency)
  1263.     throw EJpegError ("Invalid Horizontal Sampling Frequency") ;
  1264.  
  1265.   if (vf > JpegMaxSamplingFrequency || vf < JpegMinSamplingFrequency)
  1266.     throw EJpegError ("Invalid Vertical Sampling Frequency") ;
  1267.  
  1268.   image_components [component].SetHorizontalFrequency (hf) ;
  1269.   image_components [component].SetVerticalFrequency (vf) ;
  1270.   return ;
  1271. }
  1272.  
  1273. //
  1274. //  Description:
  1275. //
  1276. //    This function gets the sampling frequencies for a component
  1277. //
  1278. //  Parameters:
  1279. //    component:  The component ID
  1280. //    hf:         Horizontal Frequency
  1281. //    vf:         Vertical Frequency
  1282. //
  1283. void JpegEncoder::GetSamplingFrequency (unsigned int component,
  1284.                                         unsigned int &hf,
  1285.                                         unsigned int &vf)
  1286. {
  1287.   if (component >= MaxComponents)
  1288.     throw EJpegError ("Invalid Component ID") ;
  1289.  
  1290.   hf = image_components [component].GetHorizontalFrequency () ;
  1291.   vf = image_components [component].GetVerticalFrequency () ;
  1292.   return ;
  1293. }
  1294.  
  1295. #pragma comment (exestr, "Copyright 1998 Colosseum Builders Inc.")
  1296.  
  1297. //
  1298. //  Description:
  1299. //
  1300. //    This function writes the JFIF header for the image.
  1301. //
  1302. void JpegEncoder::OutputJfifHeader ()
  1303. {
  1304.   // Create the JFIF header.
  1305.   struct JfifHeader jfif ;
  1306.   jfif.length = SystemToBigEndian ((UBYTE2) sizeof (jfif)) ;
  1307.   jfif.identifier [0] = 'J' ;
  1308.   jfif.identifier [1] = 'F' ;
  1309.   jfif.identifier [2] = 'I' ;
  1310.   jfif.identifier [3] = 'F' ;
  1311.   jfif.version [0] = 1 ;
  1312.   jfif.version [1] = 1 ;
  1313.   jfif.units = 0 ;
  1314.   jfif.xdensity = SystemToBigEndian ((UBYTE2) 1) ;
  1315.   jfif.ydensity = SystemToBigEndian ((UBYTE2) 1) ;
  1316.   jfif.xthumbnail = 0 ;
  1317.   jfif.ythumbnail = 0 ;
  1318.   output_stream->write ((char *) &jfif, sizeof (jfif)) ;
  1319.   return ;
  1320. }
  1321.  
  1322. //
  1323. //  Description:
  1324. //
  1325. //    This function sets the attributes for a scan.
  1326. //
  1327. //  Parameters:
  1328. //    scan:  Scan number (0..MaxScan - 1)
  1329. //    components: Bit mask of components to include inthe scan
  1330. //    sse:  The spectral selection end for the scan.  The
  1331. //          spectral selection start is the sse+1 of the previous
  1332. //          scan
  1333. //    ssa:  Initial successive approximation value for the scan.
  1334. //
  1335. void JpegEncoder::SetScanAttributes (unsigned int scan,
  1336.                                      unsigned long components,
  1337.                                      unsigned int sse,
  1338.                                      unsigned int ssa)
  1339. {
  1340.   if (scan >= MaxScans)
  1341.     throw EJpegError ("Scan Index Out of Range") ;
  1342.  
  1343.   image_scans [scan].component_mask = components ;
  1344.   image_scans [scan].spectral_selection_end = sse ;
  1345.   image_scans [scan].successive_approximation = ssa ;
  1346.   return ;
  1347. }
  1348.  
  1349. //
  1350. //  Description:
  1351. //
  1352. //    This fnction returns the attributes that have been defined
  1353. //    for a scan (revsere of SetScanAttributes).
  1354. //
  1355. //  Parameters:
  1356. //    scan: (in) The scan to retrieve information about
  1357. //    components: (out) Bitmask of component IDs in the scan
  1358. //    sse: (out) Spectral selection end
  1359. //    ssa: (out) Successive Approximation
  1360. //
  1361. void JpegEncoder::GetScanAttributes (unsigned int scan,
  1362.                                      unsigned long &components,
  1363.                                      unsigned int &sse,
  1364.                                      unsigned int &ssa)
  1365. {
  1366.   if (scan >= MaxScans)
  1367.     throw EJpegError ("Scan Index Out of Range") ;
  1368.  
  1369.   components = image_scans [scan].component_mask ;
  1370.   sse = image_scans [scan].spectral_selection_end ;
  1371.   ssa = image_scans [scan].successive_approximation ;
  1372. }
  1373.  
  1374. //
  1375. //  Description:
  1376. //
  1377. //    This function counts the number of passes through the data required
  1378. //    to write the image. This value is passed t the progress function.
  1379. //
  1380. void JpegEncoder::CountPassesForProgressReporting ()
  1381. {
  1382.   current_pass = 0 ;
  1383.   if (gray_scale)
  1384.     total_passes = 2 ;
  1385.   else
  1386.     total_passes = 3 + scan_count ;
  1387.   return ;
  1388. }
  1389.  
  1390. //
  1391. //  Description:
  1392. //
  1393. //    This function returns the current quality value for the
  1394. //    encoder.
  1395. //
  1396. //  Return Value:
  1397. //    The quality value.
  1398. //
  1399. unsigned int JpegEncoder::GetQuality () const
  1400. {
  1401.   return image_quality ;
  1402. }
  1403.  
  1404. //
  1405. //  Description:
  1406. //
  1407. //    This function sets the image quality value.
  1408. //
  1409. //  Parameters:
  1410. //    value: The quality value (1..100)
  1411. //
  1412. void JpegEncoder::SetQuality (unsigned int value)
  1413. {
  1414.   if (value < 1 || value > 100)
  1415.     throw EJpegValueOutOfRange () ;
  1416.  
  1417.   image_quality = value ;
  1418.   return ;
  1419. }
  1420.