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