home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Examples / c01 / src / bitimage.cpp
Encoding:
C/C++ Source or Header  |  1998-12-17  |  27.4 KB  |  1,006 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. //  Title:  Bitmap Image Class Implementation
  15. //
  16. //  Author:  John M. Miano miano@colosseumbuilders.com
  17. //
  18. #include "bitimage.h"
  19. #include "grexcept.h"
  20.  
  21. // Function to round a row width up to the nearest multiple of
  22. // RowRounding. Windows expects rows to be a length that is a multiple of
  23. // four.
  24.  
  25. static inline int SQUARE (int xx)
  26. {
  27.   return xx * xx ;
  28. }
  29.  
  30. static inline unsigned int RoundRow (unsigned int width)
  31. {
  32.   unsigned int result = (width + BitmapImage::RowRounding - 1)
  33.                       & ~(BitmapImage::RowRounding - 1) ;
  34.   return result ;
  35. }
  36.  
  37. //
  38. //  Description:
  39. //
  40. //    Default Constructor
  41. //
  42. BitmapImage::BitmapImage ()
  43. {
  44.   Initialize () ;
  45.   return ;
  46. }
  47.  
  48. //
  49. //  Description:
  50. //
  51. //    Copy Constructor
  52. //
  53. BitmapImage::BitmapImage (const BitmapImage &source)
  54. {
  55.   Initialize () ;
  56.   DoCopy (source) ;
  57.   return ;
  58. }
  59.  
  60. //
  61. //  Description:
  62. //
  63. //    Assignment Operator
  64. //
  65. //  Parameters:
  66. //    source:  The object to copy
  67. //
  68. BitmapImage &BitmapImage::operator=(const BitmapImage &source)
  69. {
  70.   delete [] color_map ;
  71.   delete [] image_data ;
  72.   DoCopy (source) ;
  73.   return *this ;
  74. }
  75.  
  76. //
  77. //  Description:
  78. //
  79. //    Common initialization function.
  80. //
  81. void BitmapImage::Initialize ()
  82. {
  83.   ClearData () ;
  84.   progress_function = NULL ;
  85.   progress_data = NULL ;
  86.   return ;
  87. }
  88.  
  89. //
  90. //  Description:
  91. //
  92. //    Class Destructor
  93. //
  94. BitmapImage::~BitmapImage ()
  95. {
  96.   delete [] color_map ;
  97.   delete [] image_data ;
  98.   return ;
  99. }
  100.  
  101. //
  102. //  Description:
  103. //
  104. //    Common function for resetting an object to a known state.
  105. //
  106. void BitmapImage::ClearData ()
  107. {
  108.   bit_count = 0 ;
  109.   image_width = 0 ;
  110.   image_height = 0 ;
  111.   color_count = 0 ;
  112.   color_map = NULL ;
  113.   image_data = NULL ;
  114.   color_usage = NULL ;
  115.   color_areas = NULL ;
  116.   color_area_count = 0 ;
  117.  
  118.   return ;
  119. }
  120.  
  121. //
  122. //  Description:
  123. //
  124. //    Common copy function for use by the copy constructor and assignment
  125. //    operator.
  126. //
  127. //  Parameters:
  128. //    source:  The object to copy
  129. //
  130. void BitmapImage::DoCopy (const BitmapImage &source)
  131. {
  132.   progress_function = source.progress_function ;
  133.   progress_data = source.progress_function ;
  134.  
  135.   bit_count = source.bit_count ;
  136.   image_width = source.image_width ;
  137.   image_height = source.image_height ;
  138.   color_count = source.color_count ;
  139.   color_map = NULL ;
  140.   image_data = NULL ;
  141.  
  142.   color_usage = NULL ;
  143.   color_areas = NULL ;
  144.   color_area_count = 0 ;
  145.  
  146.   // Only copy the image data if the size values are valid.
  147.   if (image_width > 0 && image_height > 0 && bit_count > 0
  148.       && (bit_count == 24 || color_count != 0))
  149.   {
  150.     unsigned int bitwidth ;
  151.     unsigned int bytecount ;
  152.     switch (bit_count)
  153.     {
  154.     case 1:
  155.     case 2:
  156.     case 4:
  157.     case 8:
  158.       color_map = new ColorMapEntry [color_count] ;
  159.       memcpy (color_map,
  160.               source.color_map,
  161.               sizeof (ColorMapEntry) * color_count) ;
  162.       bitwidth = bit_count * image_width ;
  163.       row_width = RoundRow ((bitwidth + 7)/8) ;
  164.  
  165.       bytecount = row_width * image_height ;
  166.       image_data = new UBYTE1 [bytecount] ;
  167.       memcpy (image_data, source.image_data, bytecount) ;
  168.       break ;
  169.  
  170.     case 24:
  171.       row_width = RoundRow (3 * image_width) ;
  172.       image_data = new UBYTE1 [row_width * image_height] ;
  173.       memcpy (image_data, source.image_data, row_width * image_height) ;
  174.       break ;
  175.     default:
  176.       if (image_width != 0 ||image_height != 0)
  177.         throw EInvalidBitCount () ;
  178.     }
  179.   }
  180.   return ;
  181. }
  182.  
  183. #if defined (CHECK_RANGE)
  184. //
  185. //  Description:
  186. //
  187. //    Row Class Constructor.  The row class represents a single
  188. //    row of image data.
  189. //
  190. //  Parameters:
  191. //    data: A pointer to the row's data.
  192. //    length: The row length
  193. //
  194. BitmapImage::Row::Row (UBYTE1 *data, unsigned int length)
  195. {
  196.   row_data = data ;
  197.   row_length = length ;
  198.   return ;
  199. }
  200.  
  201. //
  202. //  Description:
  203. //
  204. //    Row class [] operator. This operator returns the data
  205. //    value at a given point offset in the row.
  206. //
  207. //  Parameters:
  208. //    index:  The row offset
  209. //
  210. //  Return Value:
  211. //    The data value in the row at the specified offset
  212. //
  213. UBYTE1 &BitmapImage::Row::operator[](unsigned int index)
  214. {
  215.   if (index >= row_length)
  216.     throw ESubscriptOutOfRange () ;
  217.  
  218.   return row_data [index] ;
  219. }
  220.  
  221. //
  222. //  Description:
  223. //
  224. //    This function returns a pointer to the Nth row of the image's data.
  225. //    It is set up to return the rows in reverse order as Windows expects
  226. //    them so that other software does not have to deal with such wierdness.
  227. //
  228. //  Parameters:
  229. //    xx: The row index
  230. //
  231. //  Return Value:
  232. //    A Row object that describes the image row.
  233. //
  234. BitmapImage::Row BitmapImage::operator[](unsigned int xx)const
  235. {
  236.   // In Windows bitmaps are stored bass ackwards.
  237.   if (xx >= image_height)
  238.     throw ESubscriptOutOfRange () ;
  239.   return Row (&image_data [(image_height - xx - 1) * row_width],
  240.               row_width) ;
  241. }
  242. #endif
  243.  
  244. //
  245. //  Description:
  246. //
  247. //    This function allocates space to hold an image of the specified size.
  248. //    The colormap (if used) and the image data are all set to zeros.
  249. //
  250. //  Parameters:
  251. //    cc: Number of colors. Ignored for 24-bit bitmaps
  252. //    bits: Number of bits per pixel.
  253. //    ww, hh: Bitmap size
  254. //
  255. void BitmapImage::SetSize (unsigned int cc,     // Color Count
  256.                            unsigned int bits,   // Data Size in Bits
  257.                            unsigned int ww,     // Width
  258.                            unsigned int hh)     // Height
  259. {
  260.   // Get rid of any existing image.
  261.   delete [] color_map ;
  262.   delete [] image_data ;
  263.   ClearData () ;
  264.  
  265.   switch (bits)
  266.   {
  267.   case 1:
  268.   case 2:
  269.   case 4:
  270.   case 8:
  271.     {
  272.       bit_count = bits ;
  273.       color_count = cc ;
  274.       image_width = ww ;
  275.       image_height = hh ;
  276.  
  277.       color_map = new ColorMapEntry [color_count] ;
  278.       memset (color_map, 0, sizeof (ColorMapEntry) * color_count) ;
  279.       unsigned int bitsize = bit_count * image_width ;
  280.       row_width = RoundRow ((bitsize + 7)/8) ;
  281.       unsigned int bytecount = row_width * image_height ;
  282.       image_data = new UBYTE1 [bytecount] ;
  283.       memset (image_data, 0, bytecount) ;
  284.     }
  285.     break ;
  286.  
  287.   case 24:
  288.     {
  289.       bit_count = bits ;
  290.       color_count = cc ;
  291.       image_width = ww ;
  292.       image_height = hh ;
  293.       row_width = RoundRow (3 * image_width) ;
  294.       image_data = new UBYTE1 [row_width * image_height] ;
  295.       memset (image_data, 0, row_width * image_height) ;
  296.     }
  297.     break ;
  298.   default:
  299.     throw EInvalidBitCount () ;
  300.   }
  301.   return ;
  302. }
  303.  
  304. //
  305. //  Description:
  306. //
  307. //    This function returns a reference to the Nth colormap entry.
  308. //
  309. //  Parameters:
  310. //    index:  The index of the color map entry 0..ColorCount () -1.
  311. //
  312. //  Return Value:
  313. //    The color map entry.
  314. //
  315. BitmapImage::ColorMapEntry &BitmapImage::ColorMap (unsigned int index)
  316. {
  317.   if (index >= color_count)
  318.     throw ESubscriptOutOfRange () ;
  319.  
  320.   return color_map [index] ;
  321. }
  322.  
  323. //
  324. //  Description:
  325. //
  326. //    This function returns a reference to the Nth colormap entry.
  327. //
  328. //    This is a const version of the previous function.
  329. //
  330. //  Parameters:
  331. //    index:  The index of the color map entry 0..ColorCount () -1.
  332. //
  333. //  Return Value:
  334. //    The color map entry.
  335. //
  336. BitmapImage::ColorMapEntry BitmapImage::ColorMap (unsigned int index) const
  337. {
  338.   if (index >= color_count)
  339.     throw ESubscriptOutOfRange () ;
  340.  
  341.   return color_map [index] ;
  342. }
  343.  
  344. //
  345. //  Description:
  346. //
  347. //    This function clears out the image.
  348. //
  349. void BitmapImage::Clear ()
  350. {
  351.   delete [] color_map ;
  352.   delete [] image_data ;
  353.   ClearData () ;
  354.   return ;
  355. }
  356.  
  357. //
  358. //  Description:
  359. //
  360. //   This function returns the RGB values for a pixel in the bitmap at the
  361. //   point [row,col] where row=[0..height-1] and col=[0..width-1].
  362. //
  363. //   This function allows a caller to get the RGB values for 1, 2, 4, 6,
  364. //   and 24-bit bitmaps using the same method.
  365. //
  366. //  Parameters:
  367. //    row, col: The position in the image to return data from
  368. //    red, green, blue:  The color value at the specified position
  369. //
  370. void BitmapImage::GetRGB (unsigned int row, unsigned int col,
  371.                           UBYTE1 &red, UBYTE1 &green, UBYTE1 &blue) const
  372. {
  373.   if (row >= image_height && col >= image_width)
  374.     throw ESubscriptOutOfRange () ;
  375.  
  376.   switch (bit_count)
  377.   {
  378.     unsigned int index ;
  379.     unsigned int offset ;
  380.   case 1:
  381.     offset = col / 8  ;
  382.     index = (((*this)[row][offset] >> (7 - (col % 8))) & 0x1) ;
  383.     red = color_map [index].red ;
  384.     green = color_map [index].green ;
  385.     blue = color_map [index].blue ;
  386.     break ;
  387.  
  388.   case 2:
  389.     offset = col / 4 ;
  390.     index = (((*this)[row][offset] >> (2 * (3 - (col % 4)))) & 0x3) ;
  391.     red = color_map [index].red ;
  392.     green = color_map [index].green ;
  393.     blue = color_map [index].blue ;
  394.     break ;
  395.  
  396.   case 4:
  397.     offset = col / 2 ;
  398.     if (col % 2 == 0)
  399.       index = ((*this)[row][offset] & 0xF0) >> 4 ;
  400.     else
  401.       index = ((*this)[row][offset] & 0x0F) ;
  402.  
  403.     red = color_map [index].red ;
  404.     green = color_map [index].green ;
  405.     blue = color_map [index].blue ;
  406.     break ;
  407.  
  408.   case 8:
  409.     red = color_map [(*this)[row][col]].red ;
  410.     green = color_map [(*this)[row][col]].green ;
  411.     blue = color_map [(*this)[row][col]].blue ;
  412.     break ;
  413.  
  414.   case 24:
  415.     red = (*this)[row][3 * col + RedOffset] ;
  416.     green = (*this)[row][3 * col + GreenOffset] ;
  417.     blue = (*this)[row][3 * col + BlueOffset] ;
  418.     break ;
  419.   default:
  420.     throw EInvalidBitCount () ;
  421.   }
  422.   return ;
  423. }
  424.  
  425. //
  426. // Description:
  427. //    This sets the progress function for the image.
  428. //
  429. // Parameters:
  430. //    function:   The progress function
  431. //    data:       The call progress data
  432. //
  433. void BitmapImage::SetProgressFunction (
  434.                               IMAGEPROGRESSFUNCTION function,
  435.                               void *data)
  436. {
  437.   progress_function = function ;
  438.   progress_data = data ;
  439.   return ;
  440. }
  441.  
  442. //
  443. // Description:
  444. //    This function calls the progression function.
  445. //
  446. // Parameters:
  447. //    percent:    % complete
  448. //    pass:       Current Pass
  449. //    passcount:  Number of passes
  450. //
  451. void BitmapImage::CallProgressFunction (unsigned int percent,
  452.                                         unsigned int pass,
  453.                                         unsigned int passcount)
  454. {
  455.   if (progress_function == NULL)
  456.     return ;
  457.   if (percent > 100)
  458.     percent = 100 ;
  459.  
  460.   bool cancel = false ;
  461.   progress_function (*this, progress_data, pass, passcount, percent, cancel) ;
  462.   if (cancel)
  463.     throw EGraphicsAbort () ;
  464.   return ;
  465. }
  466.  
  467. //
  468. // Color Quantization Routines
  469. //
  470. //  Since I have received many requests for color quantization I have
  471. //  whipped this up. I have to admit to knowing nothing about color
  472. //  quantization (I have always had systems that did not need it). The
  473. //  only techniques for quantization that I had been familiar with are
  474. //  scaling color values and having a fixed color space. However, I thought
  475. //  1-pass methods such as those would be too cude for someone of my
  476. //  programming skill.
  477. //
  478. //  What I have tried instead is to use two passes. What we do is create
  479. //  a 3-dimensional hash table of color values. The we keep dividing the
  480. //  colorspace in half until we have set of color ranges.
  481. //
  482. //  Hey, it's probably not all that efficient but it's the best I could come
  483. //  up with in an evening.
  484. //
  485. //
  486.  
  487. //
  488. //  Description:
  489. //    This function looks up the color entry in the color hash table
  490. //    for a specified color value.
  491. //
  492. //  Parameters:
  493. //    red, green, blue:  The color value to search for.
  494. //
  495. BitmapImage::ColorUsage *BitmapImage::FindColor (UBYTE1 red,
  496.                                                  UBYTE1 green,
  497.                                                  UBYTE1 blue)
  498. {
  499.   if (color_usage->lists [red][RedOffset] == NULL
  500.       || color_usage->lists [green][GreenOffset] == NULL
  501.       || color_usage->lists [blue][BlueOffset] == NULL)
  502.   {
  503.     return NULL ;
  504.   }
  505.  
  506.   for (ColorUsage *entry = color_usage->lists [red][RedOffset] ;
  507.        entry != NULL ;
  508.        entry = entry->next [RedOffset])
  509.   {
  510.     if (entry->colors [BlueOffset] == blue
  511.         && entry->colors [GreenOffset] == green)
  512.     {
  513.       return entry ;
  514.     }
  515.   }
  516.   return NULL ;
  517. }
  518.  
  519. //
  520. // Description:
  521. //  This function adds a new color value to the color hash table.
  522. //
  523. //  Parameters:
  524. //    red, green, blue:  The color value to search for.
  525. //
  526.  
  527. void BitmapImage::AddColor (UBYTE1 red, UBYTE1 green, UBYTE1 blue)
  528. {
  529.   // Create the new color entry.
  530.   ColorUsage *entry = new ColorUsage ;
  531.   memset (entry, 0, sizeof (*entry)) ;
  532.   entry->usage = 1 ;
  533.   entry->colors [RedOffset] = red ;
  534.   entry->colors [GreenOffset] = green ;
  535.   entry->colors [BlueOffset] = blue ;
  536.  
  537.   // Add the new entry to each hash chain.
  538.   if (color_usage->lists [red][RedOffset] == NULL)
  539.   {
  540.     color_usage->lists [red][RedOffset] = entry ;
  541.   }
  542.   else
  543.   {
  544.     entry->next [RedOffset] = color_usage->lists [red][RedOffset] ;
  545.     color_usage->lists [red][RedOffset] = entry ;
  546.   }
  547.   if (color_usage->lists[green][GreenOffset] == NULL)
  548.   {
  549.     color_usage->lists [green][GreenOffset] = entry ;
  550.   }
  551.   else
  552.   {
  553.     entry->next [GreenOffset] = color_usage->lists [green][GreenOffset] ;
  554.     color_usage->lists [green][GreenOffset] = entry ;
  555.   }
  556.   if (color_usage->lists [blue][BlueOffset] == NULL)
  557.   {
  558.     color_usage->lists [blue][BlueOffset] = entry ;
  559.   }
  560.   else
  561.   {
  562.     entry->next [BlueOffset] = color_usage->lists [blue][BlueOffset] ;
  563.     color_usage->lists [blue][BlueOffset] = entry ;
  564.   }
  565.  
  566.   ++ color_usage->color_count ;
  567.   return ;
  568. }
  569.  
  570. //
  571. // Description:
  572. //  This function converts a 24-bit image to 8-bit.
  573. //
  574. // Parameters:
  575. //  image: The image to convert.
  576. //
  577. void BitmapImage::EightBitQuantization (const BitmapImage &image)
  578. {
  579.   // If this is not a 24-bit image then there is no need to quantize.
  580.   // Instead, we make this a copy operation.
  581.   if (image.bit_count != 24)
  582.   {
  583.     *this = image ;
  584.     return ;
  585.   }
  586.  
  587.   progress_function = image.progress_function ;
  588.   progress_data = image.progress_function ;
  589.  
  590.   // Allocate space for the image.
  591.   SetSize (256, 8, image.image_width, image.image_height) ;
  592.  
  593.   // Allocate temporary structures used for color quantization.
  594.   color_usage = new ColorUsageTable ;
  595.   memset (color_usage, 0, sizeof (*color_usage)) ;
  596.   color_areas = new ColorArea [256] ;
  597.  
  598.   try
  599.   {
  600.     FindColorUsage (image) ;
  601.   }
  602.   catch (EGraphicsAbort &)
  603.   {
  604.     FreeColorQuantizationData () ;
  605.     return ;
  606.   }
  607.   catch (...)
  608.   {
  609.     FreeColorQuantizationData () ;
  610.     throw ;
  611.   }
  612.  
  613.   // Set the first (zero'th) area to the entire color space.
  614.   color_areas [0].color_values [RedOffset].low = 0 ;
  615.   color_areas [0].color_values [RedOffset].high = 255 ;
  616.   color_areas [0].color_values [GreenOffset].low = 0 ;
  617.   color_areas [0].color_values [GreenOffset].high = 255 ;
  618.   color_areas [0].color_values [BlueOffset].low = 0 ;
  619.   color_areas [0].color_values [BlueOffset].high = 255 ;
  620.   color_areas [0].pixel_count = image_height * image_width ;
  621.   color_areas [0].color_count = color_usage->color_count ;
  622.   color_area_count = 1 ;
  623.  
  624.   // Divide the color area in half.
  625.   SplitAreaInHalf (7, // Depth
  626.                   0, // Retry Count
  627.                   0, // Area Number
  628.                   RedOffset) ; // Split Color
  629.  
  630.   // It is possible that some of the areas could not be divided using the
  631.   // previous process. If we have some remaining colors we try to assign them
  632.   // to the blocks with the largest size in the colorspace.
  633.   while (color_area_count < 256)
  634.   {
  635.     int cb = 0 ;
  636.     // Search for the largest colorspace area.
  637.     unsigned int value
  638.                     = SQUARE (color_areas [cb].color_values [RedOffset].high -
  639.                               color_areas [cb].color_values [RedOffset].low)
  640.                     + SQUARE (color_areas [cb].color_values [GreenOffset].high -
  641.                               color_areas [cb].color_values [GreenOffset].low)
  642.                     + SQUARE (color_areas [cb].color_values [BlueOffset].high -
  643.                               color_areas [cb].color_values [BlueOffset].low)
  644.                     * color_areas [cb].color_count ;
  645.     for (unsigned int ii = 1 ; ii < color_area_count ; ++ ii)
  646.     {
  647.       if (color_areas [ii].color_count > 1)
  648.       {
  649.         unsigned int newvalue
  650.                     = SQUARE (color_areas [ii].color_values [RedOffset].high -
  651.                               color_areas [ii].color_values [RedOffset].low)
  652.                     + SQUARE (color_areas [ii].color_values [GreenOffset].high -
  653.                               color_areas [ii].color_values [GreenOffset].low)
  654.                     + SQUARE (color_areas [ii].color_values [BlueOffset].high -
  655.                               color_areas [ii].color_values [BlueOffset].low)
  656.                     * color_areas [ii].color_count ;
  657.         if (newvalue > value)
  658.         {
  659.           value = newvalue ;
  660.           cb = ii ;
  661.         }
  662.       }
  663.     }
  664.     // If we have not colors to divide then stop.
  665.     if (color_areas [cb].color_count == 1)
  666.       break ;
  667.  
  668.     // Split this color block in half.
  669.     SplitAreaInHalf (0, // Depth
  670.                     0, // Retry Count
  671.                     cb, // Area Number
  672.                     LargestColorRange (color_areas [cb])) ; // Split Color
  673.   }
  674.  
  675.   for (unsigned int ii = 0 ; ii < color_area_count ; ++ ii)
  676.   {
  677.     CreateColor (ii) ;
  678.   }
  679.   // Assign colors to the image.
  680.   try
  681.   {
  682.     QuantizeSourceImage (image) ;
  683.   }
  684.   catch (EGraphicsAbort &)
  685.   {
  686.     FreeColorQuantizationData () ;
  687.     return ;
  688.   }
  689.   catch (...)
  690.   {
  691.     FreeColorQuantizationData () ;
  692.     throw ;
  693.   }
  694.  
  695.   FreeColorQuantizationData () ;
  696.   return ;
  697. }
  698.  
  699. //
  700. // Description:
  701. //    This function finds the colors that are used and their frequency
  702. //    within a source image.
  703. //
  704. // Parameters:
  705. //    image:   The source image.
  706. //
  707. void BitmapImage::FindColorUsage (const BitmapImage &image)
  708. {
  709.   // Create a color entry for each distinct color.
  710.   const unsigned int climit = image_width * 3 ;
  711.   for (unsigned int rr = 0 ; rr < image_height ; ++ rr)
  712.   {
  713.     UBYTE1 *rowdata = &image.image_data [rr * image.row_width] ;
  714.     for (unsigned int cc = 0 ; cc < climit ; cc += 3 )
  715.     {
  716.       UBYTE1 red, green, blue ;
  717.       red = rowdata [cc + RedOffset] ;
  718.       green = rowdata [cc + GreenOffset]  ;
  719.       blue = rowdata [cc + BlueOffset] ;
  720.  
  721.       // If the color already exists in the table just increment
  722.       // its usage count. Otherwise add a new color entry for it.
  723.       ColorUsage *entry = FindColor (red, green, blue) ;
  724.       if (entry == NULL)
  725.       {
  726.         AddColor (red, green, blue) ;
  727.       }
  728.       else
  729.       {
  730.         ++ entry->usage ;
  731.       }
  732.     }
  733.     CallProgressFunction (100 * rr/image_height, 1, 2) ;
  734.   }
  735.   CallProgressFunction (100, 1, 2) ;
  736.  
  737.   return ;
  738. }
  739.  
  740. //
  741. //  Description:
  742. //
  743. //    This function frees all the dynamic data allocated during
  744. //    color quantization.
  745. //
  746. void BitmapImage::FreeColorQuantizationData ()
  747. {
  748.   // Get rid of al the temporary storage.
  749.   for (unsigned int ii = 0 ; ii < 256 ; ++ ii)
  750.   {
  751.     ColorUsage *next ;
  752.     for (ColorUsage *entry = color_usage->lists [ii][RedOffset] ;
  753.          entry != NULL ;
  754.          entry = next)
  755.     {
  756.        next = entry->next [RedOffset] ;
  757.        delete entry ;
  758.     }
  759.   }
  760.  
  761.   delete color_usage ; color_usage = NULL ;
  762.   delete [] color_areas ;
  763.   return ;
  764. }
  765.  
  766. //
  767. //  Description:
  768. //
  769. //    This function divides an area of the colorspace in half.
  770. //
  771. //  Parameters:
  772. //    depth:        The search depth
  773. //    retrydepth:   The number of retries
  774. //    areaid:       The area to split
  775. //    splitcolor:   The color to split on.
  776. //
  777. void BitmapImage::SplitAreaInHalf (unsigned int depth,
  778.                                    unsigned int retrydepth,
  779.                                    unsigned int areaid,
  780.                                    unsigned int splitcolor)
  781. {
  782.  
  783.   if (color_areas [areaid].color_count == 1)
  784.   {
  785.     return ;
  786.   }
  787.   else if (color_areas [areaid].color_values [splitcolor].high
  788.       == color_areas [areaid].color_values [splitcolor].low)
  789.   {
  790.     if (retrydepth < 2)
  791.     {
  792.       SplitAreaInHalf (depth, retrydepth + 1, areaid, (splitcolor + 1) % 3) ;
  793.     }
  794.     return ;
  795.   }
  796.  
  797.   unsigned int c1 = (splitcolor + 1) % 3 ;
  798.   unsigned int c2 = (splitcolor + 2) % 3 ;
  799.  
  800.   unsigned int splitsize = color_areas [areaid].pixel_count / 2 ;
  801.   unsigned int splitpixelcount = 0 ;
  802.   unsigned int splitcolorcount = 0 ;
  803.   unsigned int newlimit ;
  804.   unsigned int newpixelcount ;
  805.   unsigned int newcolorcount ;
  806.  
  807.   for (newlimit = color_areas [areaid].color_values [splitcolor].low ;
  808.        newlimit <= color_areas [areaid].color_values [splitcolor].high ;
  809.        ++ newlimit)
  810.   {
  811.     newpixelcount = 0 ;
  812.     newcolorcount = 0 ;
  813.     for (ColorUsage *entry = color_usage->lists [newlimit][splitcolor] ;
  814.          entry != NULL ;
  815.          entry = entry->next [splitcolor])
  816.     {
  817.       if (entry->colors [c1] >= color_areas [areaid].color_values [c1].low
  818.           && entry->colors [c1] <= color_areas [areaid].color_values [c1].high
  819.           && entry->colors [c2] >= color_areas [areaid].color_values [c2].low
  820.           && entry->colors [c2] <= color_areas [areaid].color_values [c2].high)
  821.       {
  822.         newpixelcount += entry->usage ;
  823.         ++ newcolorcount ;
  824.       }
  825.     }
  826.  
  827.     if (newcolorcount == color_areas [areaid].color_count)
  828.     {
  829.       // There is no way to split using this color.
  830.       if (retrydepth < 2)
  831.       {
  832.         SplitAreaInHalf (depth, retrydepth + 1, areaid, (splitcolor + 1) % 3) ;
  833.       }
  834.       return ;
  835.     }
  836.     else if (newcolorcount > color_areas [areaid].color_count)
  837.     {
  838.       throw EGraphicsException ("INTERNAL ERROR - Quantization area color count invalid") ;
  839.     }
  840.  
  841.     if (splitpixelcount + newpixelcount >= splitsize)
  842.     {
  843.       if (splitpixelcount + newpixelcount != color_areas [areaid].pixel_count)
  844.       {
  845.         splitpixelcount += newpixelcount ;
  846.         splitcolorcount += newcolorcount ;
  847.       }
  848.       else
  849.       {
  850.         -- newlimit ;
  851.       }
  852.       color_areas [color_area_count] = color_areas [areaid] ;
  853.       color_areas [color_area_count].pixel_count = color_areas [areaid].pixel_count - splitpixelcount ;
  854.       color_areas [color_area_count].color_count = color_areas [areaid].color_count - splitcolorcount ;
  855.       color_areas [color_area_count].color_values [splitcolor].low = newlimit + 1 ;
  856.       ++ color_area_count ;
  857.  
  858.       color_areas [areaid].color_values [splitcolor].high = newlimit ;
  859.       color_areas [areaid].pixel_count = splitpixelcount ;
  860.       color_areas [areaid].color_count = splitcolorcount ;
  861.  
  862.       if (depth > 0)
  863.       {
  864.         SplitAreaInHalf (depth - 1, 0, color_area_count - 1, LargestColorRange (color_areas [color_area_count-1])) ;
  865.         SplitAreaInHalf (depth - 1, 0, areaid, LargestColorRange (color_areas [areaid])) ;
  866.       }
  867.       return ;
  868.     }
  869.     else
  870.     {
  871.       splitpixelcount += newpixelcount ;
  872.       splitcolorcount += newcolorcount ;
  873.     }
  874.   }
  875.   throw EGraphicsException ("INTERNAL ERROR - Quantization area pixel count invalid") ;
  876. }
  877.  
  878. //
  879. // Description:
  880. //    This function creates a color from a color area then maps the colors
  881. //    in the source image to the new color map.
  882. //
  883. // Parameters:
  884. //    color:   The new color index value
  885. //
  886. void BitmapImage::CreateColor (unsigned int color)
  887. {
  888.   unsigned int red = 0 ;
  889.   unsigned int green = 0 ;
  890.   unsigned int blue = 0 ;
  891.  
  892.   const int c0 = RedOffset ;
  893.   const int c1 = GreenOffset ;
  894.   const int c2 = BlueOffset ;
  895.  
  896.   unsigned int itemcount = 0 ;
  897.   for (unsigned int cc = color_areas [color].color_values [c0].low ;
  898.        cc <= color_areas [color].color_values [c0].high ;
  899.        ++ cc)
  900.   {
  901.     for (ColorUsage *entry = color_usage->lists [cc][c0] ;
  902.          entry != NULL ;
  903.          entry = entry->next [c0])
  904.     {
  905.       if (entry->colors [c1] >= color_areas [color].color_values [c1].low
  906.           && entry->colors [c1] <= color_areas [color].color_values [c1].high
  907.           && entry->colors [c2] >= color_areas [color].color_values [c2].low
  908.           && entry->colors [c2] <= color_areas [color].color_values [c2].high)
  909.       {
  910.         red += entry->colors [RedOffset] * entry->usage ;
  911.         green += entry->colors [GreenOffset] * entry->usage ;
  912.         blue += entry->colors [BlueOffset] * entry->usage ;
  913.         itemcount += entry->usage ;
  914.       }
  915.     }
  916.   }
  917.  
  918.   if (itemcount == 0)
  919.     return ;
  920.  
  921.   color_map [color].red = (red + itemcount/2) / itemcount ;
  922.   color_map [color].green = (green + itemcount/2) / itemcount ;
  923.   color_map [color].blue = (blue + itemcount/2) / itemcount ;
  924.  
  925.   return ;
  926. }
  927.  
  928. //
  929. // Description:
  930. //    This function finds the largest dimension of a color area.
  931. //
  932. // Parameters:
  933. //    area:    The color area to use
  934. //
  935. int BitmapImage::LargestColorRange (ColorArea &area)
  936. {
  937.   unsigned int deltared = area.color_values [RedOffset].high
  938.                         - area.color_values [RedOffset].low ;
  939.   unsigned int deltagreen = area.color_values [GreenOffset].high
  940.                         - area.color_values [GreenOffset].low ;
  941.   unsigned int deltablue = area.color_values [BlueOffset].high
  942.                         - area.color_values [BlueOffset].low ;
  943.  
  944.   if (deltared >= deltagreen && deltared >= deltablue)
  945.     return RedOffset ;
  946.  
  947.   if (deltablue >= deltagreen && deltablue >= deltared)
  948.     return BlueOffset ;
  949.  
  950.   return GreenOffset ;
  951. }
  952.  
  953. //
  954. // Description:
  955. //    This function returns the 8-bit quantized color value for and RGB color.
  956. //
  957. // Parameters:
  958. //    red, green, blue: The RGB value to convert
  959. //
  960. unsigned int BitmapImage::QuantizedColor (UBYTE1 red, UBYTE1 green, UBYTE1 blue)
  961. {
  962.   for (unsigned int color = 0 ; color < color_area_count ; ++ color)
  963.   {
  964.     if (red >= color_areas [color].color_values [RedOffset].low
  965.         && red <= color_areas [color].color_values [RedOffset].high
  966.         && green >= color_areas [color].color_values [GreenOffset].low
  967.         && green <= color_areas [color].color_values [GreenOffset].high
  968.         && blue >= color_areas [color].color_values [BlueOffset].low
  969.         && blue <= color_areas [color].color_values [BlueOffset].high)
  970.     {
  971.       return color ;
  972.     }
  973.   }
  974.   throw EGraphicsException ("INTERNAL ERROR - color not quantized") ;
  975.  
  976.   DUMMY_RETURN // MSVC++ is too stupid to realize we can't get here.
  977. }
  978.  
  979. //
  980. // Description:
  981. //    This function converts the RGB color values in the source image
  982. //    to 8-bit quantized color values.
  983. //
  984. // Parameters:
  985. //    src:  The source image
  986. //
  987. void BitmapImage::QuantizeSourceImage (const BitmapImage &src)
  988. {
  989.   for (unsigned int rr = 0 ; rr < image_height ; ++ rr)
  990.   {
  991.     CallProgressFunction (rr * 100 / image_height, 2, 2) ;
  992.  
  993.     UBYTE1 *srcdata = &src.image_data [rr * src.row_width] ;
  994.     UBYTE1 *dstdata = &image_data [rr * row_width] ;
  995.     for (unsigned int cc = 0 ; cc < image_width ; ++ cc)
  996.     {
  997.       UBYTE1 red = srcdata [3 * cc + RedOffset] ;
  998.       UBYTE1 green = srcdata [3 * cc + GreenOffset]  ;
  999.       UBYTE1 blue = srcdata [3 * cc + BlueOffset] ;
  1000.       dstdata [cc] = QuantizedColor (red, green, blue) ;
  1001.     }
  1002.   }
  1003.   CallProgressFunction (100, 2, 2) ;
  1004.   return ;
  1005. }
  1006.