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

📄 colorconvert.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
字号:
//
// Windows CE Software Graphics Library
// colorconvert.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This source file contains the implementation of the software color format
// conversion routines. These routines can convert to/from any formats that
// are defined in swg.h. That's to say palettized and RGB formats defined
// with masks.

#include "pch.h"
#include "swg.h"

// Dumb little helper macro.

#define TwoToThe(a) (1 << (a))

// We assume that all palettes are stored in this format.

static const ULONG l_PaletteEntryFormatMasks[] = {
  0x000000FF,
  0x0000FF00,
  0x00FF0000,
  0xFF000000
};

static const FORMAT l_PaletteEntryFormat = {
  FOURCC_RGB,
  32,
  l_PaletteEntryFormatMasks
};

// These are filled out by InitColorConverter, used by ConvertColor, and
// cleaned up by CleanupColorConverter.

static ULONG l_SourceMasks[4];
static ULONG l_SourceShifts[4];

static ULONG l_DestMasks[4];
static ULONG l_DestShifts[4];

static ULONG l_NumSourcePalette = 0;
static ULONG * l_SourcePalette = NULL;

static ULONG l_NumDestPalette = 0;
static ULONG * l_DestPalette = NULL;

static ULONG l_BackgroundColor = 0;

static ULONG (*l_ConverterFunction)(ULONG) = NULL;

// Internal prototypes. This functions are not exported outside the module.

static ULONG
MaskedToMasked(
  ULONG SourceValue
  );

static ULONG
MaskedToPaletted(
  ULONG SourceValue
  );

static ULONG
PalettedToMasked(
  ULONG SourceValue
  );

static ULONG
PalettedToPaletted(
  ULONG SourceValue
  );

static ULONG
AnyToMono(
  ULONG SourceValue
  );

static LONG
RgbError(
  ULONG Color1,
  ULONG Color2
  );

static void
LoadMasksAndShifts(
  const FORMAT * Format,
  ULONG * Masks,
  ULONG * Shifts
  );

static ULONG
SearchPalette(
  ULONG SourceValueInPaletteFormat
  );

static ULONG *
LoadPalette(
  const ULONG * Palette,
  ULONG NumPalette
  );

BOOL
IsSameFormat(
  const FORMAT * Format1,
  const FORMAT * Format2
  )
{
  // IsSameFormat
  // This function will compare two pixel formats and return TRUE if they
  // are in fact the same format. Note that ALL fields of the FORMAT structure
  // must be the same for the formats to be the same. This function can be
  // called at any time.

  // Local variables.

  ULONG MaskEntries;
  BOOL FnRetVal = FALSE;   // Function return value.

  // Check parameters.

  // !TODO!

  if (Format1->FourCC == Format2->FourCC) {

    if (Format1->BitsPerPixel == Format2->BitsPerPixel) {

      // Because the Palette and Masks are a union, we can get away with
      // just refering to the Masks.

      MaskEntries = (Format1->FourCC == FOURCC_PAL) ?
	            TwoToThe(Format1->BitsPerPixel) :
	            4;

      if (memcmp(Format1->Masks, Format2->Masks,
                 sizeof(ULONG) * MaskEntries) == 0) {

        FnRetVal = TRUE;
      }
    }
  }

  return (FnRetVal);
}

BOOL
InitColorConverter(
  const FORMAT * SourceFormat,
  const FORMAT * DestFormat
  )
{
  // InitColorConverter
  // This function will setup the module data structures so that each time
  // ColorConvert is called after, it will convert from the SourceFormat to
  // the DestFormat, until CleanupColorConverter is called.

  // Local variables.

  BOOL FnRetVal = FALSE;   // Return value for this function.  

  // Check parameters.

  // !TODO!

  if (DestFormat->FourCC == FOURCC_RGB) {

    // We are converting to a direct color format, defined with bit masks.

    LoadMasksAndShifts(DestFormat, 
                       l_DestMasks, 
                       l_DestShifts);

    if (SourceFormat->FourCC == FOURCC_RGB) {

      // We are converting from a direct color format as well, so we need
      // only save the masks, and compute the shift values for each mask.

      LoadMasksAndShifts(SourceFormat, 
                         l_SourceMasks, 
                         l_SourceShifts);

      l_ConverterFunction = &MaskedToMasked;

      FnRetVal = TRUE;
    }
    else if (SourceFormat->FourCC == FOURCC_PAL) {

      // We are converting from a lookup table. So, we will lookup the color,
      // then convert it to the given destination.

      LoadMasksAndShifts(&l_PaletteEntryFormat,
                         l_SourceMasks,
                         l_SourceShifts);

      l_NumSourcePalette = TwoToThe(SourceFormat->BitsPerPixel);
      
      l_SourcePalette = LoadPalette(SourceFormat->Palette,
                                    l_NumSourcePalette);

      l_ConverterFunction = &PalettedToMasked;

      FnRetVal = TRUE;
    }
  }
  else if (DestFormat->FourCC == FOURCC_PAL &&
           DestFormat->BitsPerPixel == 1) {

    // We are converting to a 1 Bpp surface. So instead, of doing the normal
    // color match, we will instead assume that there is a "background"
    // color. The background color causes the bit in the destination to be
    // set to 1, otherwise, the bit is 0.

    // Extract the background color. Assume that it is already in the same
    // format as the source.

    l_BackgroundColor = DestFormat->Palette[0];
    l_ConverterFunction = &AnyToMono;

    FnRetVal = TRUE;
  }
  else if (DestFormat->FourCC == FOURCC_PAL) {

    // We are converting to a lookup table based format.

    l_NumDestPalette = TwoToThe(DestFormat->BitsPerPixel);
      
    l_DestPalette = LoadPalette(DestFormat->Palette,
                                l_NumDestPalette);

    if (SourceFormat->FourCC == FOURCC_RGB) {

      // We need, for each given direct color, locate the best approximation
      // of that direct color in the color table.

      LoadMasksAndShifts(SourceFormat,
                         l_SourceMasks,
                         l_SourceShifts);

      LoadMasksAndShifts(&l_PaletteEntryFormat,
                         l_DestMasks,
                         l_DestShifts);

      l_ConverterFunction = &MaskedToPaletted;

      FnRetVal = TRUE;
    }
    else if (SourceFormat->FourCC == FOURCC_PAL) {

      // We need to lookup the color from the source palette, then approximate
      // it into the destination palette.

      l_NumSourcePalette = TwoToThe(SourceFormat->BitsPerPixel);
      
      l_SourcePalette = LoadPalette(SourceFormat->Palette,
                                    l_NumSourcePalette);

      l_ConverterFunction = &PalettedToPaletted;

      FnRetVal = TRUE;
    }
  }
  
  return (FnRetVal);
}

ULONG
ColorConvert(
  ULONG SourceValue
  )
{
  // ColorConverter
  // This function simply calls through the function pointer that we setup in
  // InitColorConverter.

  // Check parameters.

  // !TODO!

  return (*l_ConverterFunction)(SourceValue);
}

void
CleanupColorConverter()
{
  // CleanupColorConverter
  // This function cleans up any allocations we may have done as part of 
  // setting up the color conversion unit. It returns the module values to
  // a state where we can reinitialize them without leaking memory.

  l_ConverterFunction = NULL;

  if (l_SourcePalette) {

    LocalFree(l_SourcePalette);
    l_SourcePalette = NULL;
    l_NumSourcePalette = 0;
  }

  if (l_DestPalette) {

    LocalFree(l_DestPalette);
    l_DestPalette = NULL;
    l_NumDestPalette = 0;
  }
}

ULONG
MaskedToMasked(
  ULONG SourceValue
  )
{
  // MaskedToMasked
  // This function is called by ColorConvert, via function pointer, when we
  // need to convert colors between two RGB formats, defined by a set of
  // masks for where the color channels are packed.

  return ((((SourceValue & l_SourceMasks[0]) << l_SourceShifts[0]) >> l_DestShifts[0]) & l_DestMasks[0]) |
         ((((SourceValue & l_SourceMasks[1]) << l_SourceShifts[1]) >> l_DestShifts[1]) & l_DestMasks[1]) |
         ((((SourceValue & l_SourceMasks[2]) << l_SourceShifts[2]) >> l_DestShifts[2]) & l_DestMasks[2]) |
         ((((SourceValue & l_SourceMasks[3]) << l_SourceShifts[3]) >> l_DestShifts[3]) & l_DestMasks[3]);
}

ULONG
MaskedToPaletted(
  ULONG SourceValue
  )
{
  // MaskedToPaletted
  // This function does the grusome conversion from a direct color surface to
  // a paletted surface. It simply converts to the native palette format, then
  // finds the best fit in the destination palette.

  // Check parameters.

  // !TODO!

  return (SearchPalette(MaskedToMasked(SourceValue)));
}

ULONG
PalettedToMasked(
  ULONG SourceValue
  )
{
  // PalettedToMasked
  // This function converts from a paletted format to a maksed format. This is
  // a matter of looking the appropriate entry up in the color table, and
  // converting it to the appropriate masked value.

  // Check parameters.

  // !TODO!

  return (MaskedToMasked(l_SourcePalette[SourceValue]));
}

ULONG
PalettedToPaletted(
  ULONG SourceValue
  )
{
  // PalettedToPaletted
  // This function will do the horrible work of trying to match a color
  // that is looked up from one palette to another.

  // Check parameters.

  // !TODO!

  return (SearchPalette(l_SourcePalette[SourceValue]));
}

ULONG
AnyToMono(
  ULONG SourceValue
  )
{
  // AnyToMono
  // This function will compare the given source value against the stored
  // background color (assumed to be in the source's pixel format,) and
  // return 1 if they are equal and 0 if they are not.

  // Check parameters.

  // !TODO!

  return ((SourceValue == l_BackgroundColor) ? 1 : 0);
}

LONG
RgbError(
  ULONG Color1,
  ULONG Color2
  )
{
  // RgbError
  // This function, given two 24 BPP colors, packed in the low bits of a 32
  // bit value, computes an error term that describes how "close" the colors
  // are to each other in the color space. (This only works for variants of
  // the RGB space.) This is NOT the actual distance between the colors in
  // the space, but this variant:
  //
  // Error = (r1 - r2)^2 + (g1 - g2)^2 + (b1 - b2)^2
  //
  // This works for all component ordering as long as both color values use
  // the same ordering, and in the low bits of the dword.

  // Local variables.

  BYTE * Color1Array;
  BYTE * Color2Array;
  LONG Accumulation;
  LONG ComponentDiff;
  LONG FnRetVal;

  // Check parameters.

  // No need to check Color1 and Color2: they can be anything.

  Color1Array = (BYTE *)&Color1;
  Color2Array = (BYTE *)&Color2;

  // Compute the (c1 - c2)^2 for the first components (lowest bits)

  Accumulation = *Color1Array++ - *Color2Array++;
  Accumulation *= Accumulation;

  // Next lowest bits...

  ComponentDiff = *Color1Array++ - *Color2Array++;
  Accumulation += (ComponentDiff * ComponentDiff);

  // Highest bits...

  ComponentDiff = *Color1Array++ - *Color2Array++;
  FnRetVal = Accumulation + (ComponentDiff * ComponentDiff);

  return (FnRetVal);
}

ULONG
SearchPalette(
  ULONG SourceValueInPaletteFormat
  )
{
  // SearchPalette
  // This function is used to search the destination palette for a best fit to
  // a given value, passed in the color format palette entries are stored in.

  // Local variables.

  LONG SmallestError = 0x7FFFFFFF;
  LONG ErrorTerm;
  ULONG PaletteIndex;
  ULONG FnRetVal;

  // Check parameters.

  // !TODO!

  for (PaletteIndex = 0;
       PaletteIndex < l_NumDestPalette;
       PaletteIndex++) {

    ErrorTerm = RgbError(SourceValueInPaletteFormat,
                         l_DestPalette[PaletteIndex]);

    if (ErrorTerm < SmallestError) {
      SmallestError = ErrorTerm;
      FnRetVal = PaletteIndex;
      if (ErrorTerm == 0) {  // Perfect match.
        break;
      }
    }
  }

  return (FnRetVal);
}

void
LoadMasksAndShifts(
  const FORMAT * Format,
  ULONG * Masks,
  ULONG * Shifts
  )
{
  // LoadMasksAndShifts
  // This function is used to load given mask and shift arrays from a given
  // color format. This shift values corespond to those useful for
  // MaskedToMasked.

  // Local variables.

  ULONG i;
  ULONG Mask;
  ULONG Shift;

  // Check parameters.

  // !TODO!

  for (i = 0; i < 4; i++) {

    Mask = Masks[i] = Format->Masks[i];
    
    for (Shift = 0; Mask; Shift++) {
      Mask >>= 1;
    }

    Shifts[i] = 32 - Shift;
  }
}

ULONG *
LoadPalette(
  const ULONG * Palette,
  ULONG NumPalette
  )
{
  // LoadPalette
  // This function copies the palette from the parameter stucture (which may
  // or may not be still be around after the InitColorConverter call returns)
  // to our local storage.

  // Local variables.

  ULONG   SizeofPalette;
  ULONG * LocalPalette;

  // Check parameters.

  // !TODO!

  SizeofPalette = NumPalette * sizeof(ULONG);
  LocalPalette = LocalAlloc(LMEM_FIXED, SizeofPalette);

  if (LocalPalette) {
    memcpy(LocalPalette, Palette, SizeofPalette);
  }

  return LocalPalette;
}

⌨️ 快捷键说明

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