⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitimage.cpp

📁 超强jpeg解码程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  }

  for (ColorUsage *entry = color_usage->lists [red][RedOffset] ;
       entry != NULL ;
       entry = entry->next [RedOffset])
  {
    if (entry->colors [BlueOffset] == blue
        && entry->colors [GreenOffset] == green)
    {
      return entry ;
    }
  }
  return NULL ;
}

//
// Description:
//  This function adds a new color value to the color hash table.
//
//  Parameters:
//    red, green, blue:  The color value to search for.
//

void BitmapImage::AddColor (UBYTE1 red, UBYTE1 green, UBYTE1 blue)
{
  // Create the new color entry.
  ColorUsage *entry = new ColorUsage ;
  memset (entry, 0, sizeof (*entry)) ;
  entry->usage = 1 ;
  entry->colors [RedOffset] = red ;
  entry->colors [GreenOffset] = green ;
  entry->colors [BlueOffset] = blue ;

  // Add the new entry to each hash chain.
  if (color_usage->lists [red][RedOffset] == NULL)
  {
    color_usage->lists [red][RedOffset] = entry ;
  }
  else
  {
    entry->next [RedOffset] = color_usage->lists [red][RedOffset] ;
    color_usage->lists [red][RedOffset] = entry ;
  }
  if (color_usage->lists[green][GreenOffset] == NULL)
  {
    color_usage->lists [green][GreenOffset] = entry ;
  }
  else
  {
    entry->next [GreenOffset] = color_usage->lists [green][GreenOffset] ;
    color_usage->lists [green][GreenOffset] = entry ;
  }
  if (color_usage->lists [blue][BlueOffset] == NULL)
  {
    color_usage->lists [blue][BlueOffset] = entry ;
  }
  else
  {
    entry->next [BlueOffset] = color_usage->lists [blue][BlueOffset] ;
    color_usage->lists [blue][BlueOffset] = entry ;
  }

  ++ color_usage->color_count ;
  return ;
}

//
// Description:
//  This function converts a 24-bit image to 8-bit.
//
// Parameters:
//  image: The image to convert.
//
void BitmapImage::EightBitQuantization (const BitmapImage &image)
{
  // If this is not a 24-bit image then there is no need to quantize.
  // Instead, we make this a copy operation.
  if (image.bit_count != 24)
  {
    *this = image ;
    return ;
  }

  progress_function = image.progress_function ;
  progress_data = image.progress_function ;

  // Allocate space for the image.
  SetSize (256, 8, image.image_width, image.image_height) ;

  // Allocate temporary structures used for color quantization.
  color_usage = new ColorUsageTable ;
  memset (color_usage, 0, sizeof (*color_usage)) ;
  color_areas = new ColorArea [256] ;

  try
  {
    FindColorUsage (image) ;
  }
  catch (EGraphicsAbort &)
  {
    FreeColorQuantizationData () ;
    return ;
  }
  catch (...)
  {
    FreeColorQuantizationData () ;
    throw ;
  }

  // Set the first (zero'th) area to the entire color space.
  color_areas [0].color_values [RedOffset].low = 0 ;
  color_areas [0].color_values [RedOffset].high = 255 ;
  color_areas [0].color_values [GreenOffset].low = 0 ;
  color_areas [0].color_values [GreenOffset].high = 255 ;
  color_areas [0].color_values [BlueOffset].low = 0 ;
  color_areas [0].color_values [BlueOffset].high = 255 ;
  color_areas [0].pixel_count = image_height * image_width ;
  color_areas [0].color_count = color_usage->color_count ;
  color_area_count = 1 ;

  // Divide the color area in half.
  SplitAreaInHalf (7, // Depth
                  0, // Retry Count
                  0, // Area Number
                  RedOffset) ; // Split Color

  // It is possible that some of the areas could not be divided using the
  // previous process. If we have some remaining colors we try to assign them
  // to the blocks with the largest size in the colorspace.
  while (color_area_count < 256)
  {
    int cb = 0 ;
    // Search for the largest colorspace area.
    unsigned int value
                    = SQUARE (color_areas [cb].color_values [RedOffset].high -
                              color_areas [cb].color_values [RedOffset].low)
                    + SQUARE (color_areas [cb].color_values [GreenOffset].high -
                              color_areas [cb].color_values [GreenOffset].low)
                    + SQUARE (color_areas [cb].color_values [BlueOffset].high -
                              color_areas [cb].color_values [BlueOffset].low)
                    * color_areas [cb].color_count ;
    for (unsigned int ii = 1 ; ii < color_area_count ; ++ ii)
    {
      if (color_areas [ii].color_count > 1)
      {
        unsigned int newvalue
                    = SQUARE (color_areas [ii].color_values [RedOffset].high -
                              color_areas [ii].color_values [RedOffset].low)
                    + SQUARE (color_areas [ii].color_values [GreenOffset].high -
                              color_areas [ii].color_values [GreenOffset].low)
                    + SQUARE (color_areas [ii].color_values [BlueOffset].high -
                              color_areas [ii].color_values [BlueOffset].low)
                    * color_areas [ii].color_count ;
        if (newvalue > value)
        {
          value = newvalue ;
          cb = ii ;
        }
      }
    }
    // If we have not colors to divide then stop.
    if (color_areas [cb].color_count == 1)
      break ;

    // Split this color block in half.
    SplitAreaInHalf (0, // Depth
                    0, // Retry Count
                    cb, // Area Number
                    LargestColorRange (color_areas [cb])) ; // Split Color
  }

  for (unsigned int ii = 0 ; ii < color_area_count ; ++ ii)
  {
    CreateColor (ii) ;
  }
  // Assign colors to the image.
  try
  {
    QuantizeSourceImage (image) ;
  }
  catch (EGraphicsAbort &)
  {
    FreeColorQuantizationData () ;
    return ;
  }
  catch (...)
  {
    FreeColorQuantizationData () ;
    throw ;
  }

  FreeColorQuantizationData () ;
  return ;
}

//
// Description:
//    This function finds the colors that are used and their frequency
//    within a source image.
//
// Parameters:
//    image:   The source image.
//
void BitmapImage::FindColorUsage (const BitmapImage &image)
{
  // Create a color entry for each distinct color.
  const unsigned int climit = image_width * 3 ;
  for (unsigned int rr = 0 ; rr < image_height ; ++ rr)
  {
    UBYTE1 *rowdata = &image.image_data [rr * image.row_width] ;
    for (unsigned int cc = 0 ; cc < climit ; cc += 3 )
    {
      UBYTE1 red, green, blue ;
      red = rowdata [cc + RedOffset] ;
      green = rowdata [cc + GreenOffset]  ;
      blue = rowdata [cc + BlueOffset] ;

      // If the color already exists in the table just increment
      // its usage count. Otherwise add a new color entry for it.
      ColorUsage *entry = FindColor (red, green, blue) ;
      if (entry == NULL)
      {
        AddColor (red, green, blue) ;
      }
      else
      {
        ++ entry->usage ;
      }
    }
    CallProgressFunction (100 * rr/image_height, 1, 2) ;
  }
  CallProgressFunction (100, 1, 2) ;

  return ;
}

//
//  Description:
//
//    This function frees all the dynamic data allocated during
//    color quantization.
//
void BitmapImage::FreeColorQuantizationData ()
{
  // Get rid of al the temporary storage.
  for (unsigned int ii = 0 ; ii < 256 ; ++ ii)
  {
    ColorUsage *next ;
    for (ColorUsage *entry = color_usage->lists [ii][RedOffset] ;
         entry != NULL ;
         entry = next)
    {
       next = entry->next [RedOffset] ;
       delete entry ;
    }
  }

  delete color_usage ; color_usage = NULL ;
  delete [] color_areas ;
  return ;
}

//
//  Description:
//
//    This function divides an area of the colorspace in half.
//
//  Parameters:
//    depth:        The search depth
//    retrydepth:   The number of retries
//    areaid:       The area to split
//    splitcolor:   The color to split on.
//
void BitmapImage::SplitAreaInHalf (unsigned int depth,
                                   unsigned int retrydepth,
                                   unsigned int areaid,
                                   unsigned int splitcolor)
{

  if (color_areas [areaid].color_count == 1)
  {
    return ;
  }
  else if (color_areas [areaid].color_values [splitcolor].high
      == color_areas [areaid].color_values [splitcolor].low)
  {
    if (retrydepth < 2)
    {
      SplitAreaInHalf (depth, retrydepth + 1, areaid, (splitcolor + 1) % 3) ;
    }
    return ;
  }

  unsigned int c1 = (splitcolor + 1) % 3 ;
  unsigned int c2 = (splitcolor + 2) % 3 ;

  unsigned int splitsize = color_areas [areaid].pixel_count / 2 ;
  unsigned int splitpixelcount = 0 ;
  unsigned int splitcolorcount = 0 ;
  unsigned int newlimit ;
  unsigned int newpixelcount ;
  unsigned int newcolorcount ;

  for (newlimit = color_areas [areaid].color_values [splitcolor].low ;
       newlimit <= color_areas [areaid].color_values [splitcolor].high ;
       ++ newlimit)
  {
    newpixelcount = 0 ;
    newcolorcount = 0 ;
    for (ColorUsage *entry = color_usage->lists [newlimit][splitcolor] ;
         entry != NULL ;
         entry = entry->next [splitcolor])
    {
      if (entry->colors [c1] >= color_areas [areaid].color_values [c1].low
          && entry->colors [c1] <= color_areas [areaid].color_values [c1].high
          && entry->colors [c2] >= color_areas [areaid].color_values [c2].low
          && entry->colors [c2] <= color_areas [areaid].color_values [c2].high)
      {
        newpixelcount += entry->usage ;
        ++ newcolorcount ;
      }
    }

    if (newcolorcount == color_areas [areaid].color_count)
    {
      // There is no way to split using this color.
      if (retrydepth < 2)
      {
        SplitAreaInHalf (depth, retrydepth + 1, areaid, (splitcolor + 1) % 3) ;
      }
      return ;
    }
    else if (newcolorcount > color_areas [areaid].color_count)
    {
      throw EGraphicsException ("INTERNAL ERROR - Quantization area color count invalid") ;
    }

    if (splitpixelcount + newpixelcount >= splitsize)
    {
      if (splitpixelcount + newpixelcount != color_areas [areaid].pixel_count)
      {
        splitpixelcount += newpixelcount ;
        splitcolorcount += newcolorcount ;
      }
      else
      {
        -- newlimit ;
      }
      color_areas [color_area_count] = color_areas [areaid] ;
      color_areas [color_area_count].pixel_count = color_areas [areaid].pixel_count - splitpixelcount ;
      color_areas [color_area_count].color_count = color_areas [areaid].color_count - splitcolorcount ;
      color_areas [color_area_count].color_values [splitcolor].low = newlimit + 1 ;
      ++ color_area_count ;

      color_areas [areaid].color_values [splitcolor].high = newlimit ;
      color_areas [areaid].pixel_count = splitpixelcount ;
      color_areas [areaid].color_count = splitcolorcount ;

      if (depth > 0)
      {
        SplitAreaInHalf (depth - 1, 0, color_area_count - 1, LargestColorRange (color_areas [color_area_count-1])) ;
        SplitAreaInHalf (depth - 1, 0, areaid, LargestColorRange (color_areas [areaid])) ;
      }
      return ;
    }
    else
    {
      splitpixelcount += newpixelcount ;
      splitcolorcount += newcolorcount ;
    }
  }
  throw EGraphicsException ("INTERNAL ERROR - Quantization area pixel count invalid") ;
}

//
// Description:
//    This function creates a color from a color area then maps the colors
//    in the source image to the new color map.
//
// Parameters:
//    color:   The new color index value
//
void BitmapImage::CreateColor (unsigned int color)
{
  unsigned int red = 0 ;
  unsigned int green = 0 ;
  unsigned int blue = 0 ;

  const int c0 = RedOffset ;
  const int c1 = GreenOffset ;
  const int c2 = BlueOffset ;

  unsigned int itemcount = 0 ;
  for (unsigned int cc = color_areas [color].color_values [c0].low ;
       cc <= color_areas [color].color_values [c0].high ;
       ++ cc)
  {
    for (ColorUsage *entry = color_usage->lists [cc][c0] ;
         entry != NULL ;
         entry = entry->next [c0])
    {
      if (entry->colors [c1] >= color_areas [color].color_values [c1].low
          && entry->colors [c1] <= color_areas [color].color_values [c1].high
          && entry->colors [c2] >= color_areas [color].color_values [c2].low
          && entry->colors [c2] <= color_areas [color].color_values [c2].high)
      {
        red += entry->colors [RedOffset] * entry->usage ;
        green += entry->colors [GreenOffset] * entry->usage ;
        blue += entry->colors [BlueOffset] * entry->usage ;
        itemcount += entry->usage ;
      }
    }
  }

  if (itemcount == 0)
    return ;

  color_map [color].red = (red + itemcount/2) / itemcount ;
  color_map [color].green = (green + itemcount/2) / itemcount ;
  color_map [color].blue = (blue + itemcount/2) / itemcount ;

  return ;
}

//
// Description:
//    This function finds the largest dimension of a color area.
//
// Parameters:
//    area:    The color area to use
//
int BitmapImage::LargestColorRange (ColorArea &area)
{
  unsigned int deltared = area.color_values [RedOffset].high
                        - area.color_values [RedOffset].low ;
  unsigned int deltagreen = area.color_values [GreenOffset].high
                        - area.color_values [GreenOffset].low ;
  unsigned int deltablue = area.color_values [BlueOffset].high
                        - area.color_values [BlueOffset].low ;

  if (deltared >= deltagreen && deltared >= deltablue)
    return RedOffset ;

  if (deltablue >= deltagreen && deltablue >= deltared)
    return BlueOffset ;

  return GreenOffset ;
}

//
// Description:
//    This function returns the 8-bit quantized color value for and RGB color.
//
// Parameters:
//    red, green, blue: The RGB value to convert
//
unsigned int BitmapImage::QuantizedColor (UBYTE1 red, UBYTE1 green, UBYTE1 blue)
{
  for (unsigned int color = 0 ; color < color_area_count ; ++ color)
  {
    if (red >= color_areas [color].color_values [RedOffset].low
        && red <= color_areas [color].color_values [RedOffset].high
        && green >= color_areas [color].color_values [GreenOffset].low
        && green <= color_areas [color].color_values [GreenOffset].high
        && blue >= color_areas [color].color_values [BlueOffset].low
        && blue <= color_areas [color].color_values [BlueOffset].high)
    {
      return color ;
    }
  }
  throw EGraphicsException ("INTERNAL ERROR - color not quantized") ;

  DUMMY_RETURN // MSVC++ is too stupid to realize we can't get here.
}

//
// Description:
//    This function converts the RGB color values in the source image
//    to 8-bit quantized color values.
//
// Parameters:
//    src:  The source image
//
void BitmapImage::QuantizeSourceImage (const BitmapImage &src)
{
  for (unsigned int rr = 0 ; rr < image_height ; ++ rr)
  {
    CallProgressFunction (rr * 100 / image_height, 2, 2) ;

    UBYTE1 *srcdata = &src.image_data [rr * src.row_width] ;
    UBYTE1 *dstdata = &image_data [rr * row_width] ;
    for (unsigned int cc = 0 ; cc < image_width ; ++ cc)
    {
      UBYTE1 red = srcdata [3 * cc + RedOffset] ;
      UBYTE1 green = srcdata [3 * cc + GreenOffset]  ;
      UBYTE1 blue = srcdata [3 * cc + BlueOffset] ;
      dstdata [cc] = QuantizedColor (red, green, blue) ;
    }
  }
  CallProgressFunction (100, 2, 2) ;
  return ;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -