📄 colorconvert.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 + -