You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
16 KiB
522 lines
16 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999-2000 Microsoft Corporation
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Object which maps one palette to another.
|
|
*
|
|
* It only maps colors which match exactly - its purpose is to deal
|
|
* with, e.g., the halftone palette which has identical colors on different
|
|
* platforms, but colors may be in different positions.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 12/09/1999 ericvan
|
|
* Created it.
|
|
* 01/20/2000 agodfrey
|
|
* Moved it from Imaging\Api. Renamed it to EpPaletteMap.
|
|
* Replaced the halftoning function pointer with 'isVGAOnly'.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
//#define GDIPLUS_WIN9X_HALFTONE_MAP
|
|
|
|
#if defined(GDIPLUS_WIN9X_HALFTONE_MAP)
|
|
|
|
// The first array maps from our halftone color palette to the Windows 9x
|
|
// halftone color palette, while the second array does the reverse. Negative
|
|
// values indicate an unmatched color:
|
|
//
|
|
// -1 no exact match (Win9x is missing 4 of our halftone colors)
|
|
// -2 magic color
|
|
|
|
INT HTToWin9xPaletteMap[256] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
-2, -2, -2, -2, 248, 249, 250, 251,
|
|
252, 253, 254, 255, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 60, 95, 133, 161, 252, 33, 66,
|
|
101, 166, 199, -1, 39, 72, 107, 138,
|
|
172, 205, 45, 78, 112, 129, 178, 211,
|
|
51, 84, 118, 149, 184, 217, 250, -1,
|
|
123, 155, 190, 254, 29, 61, 96, 162,
|
|
196, -1, 34, 67, 102, 134, 167, 200,
|
|
40, 73, 108, 139, 173, 206, 46, 79,
|
|
113, 144, 179, 212, 52, 85, 119, 150,
|
|
185, 218, -1, 90, 124, 156, 191, 223,
|
|
30, 62, 97, 135, 163, 197, 35, 68,
|
|
103, 140, 168, 201, 41, 74, 109, 174,
|
|
207, 230, 47, 80, 114, 145, 180, 213,
|
|
53, 86, 151, 157, 186, 219, 57, 91,
|
|
228, 192, 224, 232, 31, 63, 98, 131,
|
|
164, 198, 36, 69, 104, 130, 169, 202,
|
|
42, 75, 110, 141, 175, 208, 48, 81,
|
|
115, 146, 181, 214, 54, 87, 120, 152,
|
|
187, 220, 58, 92, 125, 158, 193, 225,
|
|
32, 64, 99, 132, 165, 128, 37, 70,
|
|
105, 136, 170, 203, 43, 76, 111, 142,
|
|
176, 209, 49, 82, 116, 147, 182, 215,
|
|
55, 88, 121, 153, 188, 221, 59, 93,
|
|
126, 159, 194, 226, 249, 65, 100, 137,
|
|
127, 253, 38, 71, 106, 143, 171, 204,
|
|
44, 77, 227, 177, 210, 231, 50, 83,
|
|
117, 148, 183, 216, 56, 89, 122, 154,
|
|
189, 222, 251, 94, 229, 160, 195, 255
|
|
};
|
|
|
|
INT HTFromWin9xPaletteMap[256] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
-2, -2, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, 76, 112, 148,
|
|
184, 46, 82, 118, 154, 190, 226, 52,
|
|
88, 124, 160, 196, 232, 58, 94, 130,
|
|
166, 202, 238, 64, 100, 136, 172, 208,
|
|
244, 142, 178, 214, 41, 77, 113, 149,
|
|
185, 221, 47, 83, 119, 155, 191, 227,
|
|
53, 89, 125, 161, 197, 233, 59, 95,
|
|
131, 167, 203, 239, 65, 101, 137, 173,
|
|
209, 245, 107, 143, 179, 215, 251, 42,
|
|
78, 114, 150, 186, 222, 48, 84, 120,
|
|
156, 192, 228, 54, 90, 126, 162, 198,
|
|
60, 96, 132, 168, 204, 240, 66, 102,
|
|
174, 210, 246, 72, 108, 180, 216, 224,
|
|
189, 61, 157, 151, 187, 43, 85, 115,
|
|
193, 223, 55, 91, 121, 163, 199, 229,
|
|
97, 133, 169, 205, 241, 67, 103, 138,
|
|
175, 211, 247, 73, 109, 139, 181, 217,
|
|
253, 44, 79, 116, 152, 188, 49, 86,
|
|
122, 158, 194, 230, 56, 92, 127, 164,
|
|
200, 235, 62, 98, 134, 170, 206, 242,
|
|
68, 104, 140, 176, 212, 248, 74, 110,
|
|
145, 182, 218, 254, 80, 117, 153, 50,
|
|
87, 123, 159, 195, 231, 57, 93, 128,
|
|
165, 201, 236, 63, 99, 135, 171, 207,
|
|
243, 69, 105, 141, 177, 213, 249, 111,
|
|
146, 183, 219, 234, 144, 252, 129, 237,
|
|
147, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -2, -2,
|
|
12, 13, 14, 15, 16, 17, 18, 19
|
|
};
|
|
|
|
#endif
|
|
|
|
BYTE
|
|
GetNearestColorIndex(
|
|
GpColor color,
|
|
ColorPalette *palette
|
|
)
|
|
{
|
|
INT i;
|
|
BYTE nearestIndex = 0;
|
|
INT nearestDistance = INT_MAX;
|
|
|
|
// Note: This does not optimize for the exact match case because it's
|
|
// assumed we already did this check first.
|
|
|
|
for (i = 0; i < (INT) palette->Count; i++)
|
|
{
|
|
// Compute the distance (squared) between colors:
|
|
|
|
GpColor palColor = GpColor(palette->Entries[i]);
|
|
|
|
INT r = (INT) color.GetRed() - (INT) palColor.GetRed();
|
|
INT g = (INT) color.GetGreen() - (INT) palColor.GetGreen();
|
|
INT b = (INT) color.GetBlue() - (INT) palColor.GetBlue();
|
|
|
|
INT distance = (r * r) + (g * g) + (b * b);
|
|
|
|
if (distance < nearestDistance)
|
|
{
|
|
nearestDistance = distance;
|
|
nearestIndex = static_cast<BYTE>(i);
|
|
|
|
if (nearestDistance == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearestIndex;
|
|
}
|
|
|
|
VOID
|
|
EpPaletteMap::CreateFromColorPalette(
|
|
ColorPalette *palette
|
|
)
|
|
{
|
|
INT i;
|
|
INT matchCount = 0;
|
|
|
|
#if defined(GDIPLUS_WIN9X_HALFTONE_MAP)
|
|
|
|
// Check for the Win9x halftone palette:
|
|
|
|
PALETTEENTRY *palEntry = Win9xHalftonePalette.palPalEntry;
|
|
|
|
for (i = 0; i < 256; i++, palEntry++)
|
|
{
|
|
// Ignore magic or unmatched colors:
|
|
|
|
if (HTFromWin9xPaletteMap[i] >= 0)
|
|
{
|
|
GpColor palColor(palette->Entries[i]);
|
|
|
|
if ((palColor.GetRed() != palEntry->peRed) ||
|
|
(palColor.GetGreen() != palEntry->peGreen) ||
|
|
(palColor.GetBlue() != palEntry->peBlue))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == 256) // --- Win9x halftone palette ---
|
|
{
|
|
matchCount = 212;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
INT win9xIndex = HTToWin9xPaletteMap[i];
|
|
|
|
if (win9xIndex >= 0)
|
|
{
|
|
translate[i] = static_cast<BYTE>(win9xIndex);
|
|
}
|
|
else
|
|
{
|
|
GpColor halftoneColor;
|
|
|
|
if (win9xIndex == -1)
|
|
{
|
|
halftoneColor =
|
|
GpColor(HTColorPalette.palPalEntry[i].peRed,
|
|
HTColorPalette.palPalEntry[i].peGreen,
|
|
HTColorPalette.palPalEntry[i].peBlue);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(win9xIndex == -2);
|
|
ASSERT((i >= 8) && (i <= 11));
|
|
|
|
COLORREF systemColor = Globals::SystemColors[i + 8];
|
|
|
|
halftoneColor = GpColor(GetRValue(systemColor),
|
|
GetGValue(systemColor),
|
|
GetBValue(systemColor));
|
|
}
|
|
|
|
translate[i] = GetNearestColorIndex(halftoneColor,
|
|
palette);
|
|
}
|
|
}
|
|
}
|
|
else // --- Any other palette ---
|
|
|
|
#endif
|
|
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
GpColor color;
|
|
|
|
if ((i > 11) || (i < 8))
|
|
{
|
|
color = GpColor(HTColorPalette.palPalEntry[i].peRed,
|
|
HTColorPalette.palPalEntry[i].peGreen,
|
|
HTColorPalette.palPalEntry[i].peBlue);
|
|
}
|
|
else
|
|
{
|
|
COLORREF systemColor = Globals::SystemColors[i + 8];
|
|
|
|
color = GpColor(GetRValue(systemColor),
|
|
GetGValue(systemColor),
|
|
GetBValue(systemColor));
|
|
}
|
|
|
|
// First look for exact matches:
|
|
|
|
INT j;
|
|
|
|
for (j = 0; j < (INT) palette->Count; j++)
|
|
{
|
|
if (GpColor(palette->Entries[j]).IsEqual(color))
|
|
{
|
|
// We found an exact match:
|
|
|
|
translate[i] = static_cast<BYTE>(j);
|
|
|
|
if (i >= 40)
|
|
{
|
|
matchCount++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we didn't find an exact match, look for the nearest:
|
|
|
|
if (j == (INT) palette->Count)
|
|
{
|
|
translate[i] = GetNearestColorIndex(color,
|
|
palette);
|
|
}
|
|
}
|
|
}
|
|
|
|
uniqueness = 0;
|
|
|
|
// See comments in UpdateTranslate to see why we look for 212 colors.
|
|
|
|
isVGAOnly = (matchCount >= 212) ? FALSE : TRUE;
|
|
}
|
|
|
|
EpPaletteMap::EpPaletteMap(HDC hdc, ColorPalette **palette, BOOL isDib8)
|
|
{
|
|
// isDib8 is TRUE when the caller has already determined that the HDC
|
|
// bitmap is an 8 bpp DIB section. If the caller hasn't determined, we
|
|
// check here:
|
|
|
|
if (!isDib8 && (GetDCType(hdc) == OBJ_MEMDC))
|
|
{
|
|
HBITMAP hbm = (HBITMAP) GetCurrentObject(hdc, OBJ_BITMAP);
|
|
|
|
if (hbm)
|
|
{
|
|
DIBSECTION dibInfo;
|
|
INT infoSize = GetObjectA(hbm, sizeof(dibInfo), &dibInfo);
|
|
|
|
// Comment below copied from GpGraphics::GetFromGdiBitmap:
|
|
//
|
|
// WinNT/Win95 differences in GetObject:
|
|
//
|
|
// WinNT always returns the number of bytes filled, either
|
|
// sizeof(BITMAP) or sizeof(DIBSECTION).
|
|
//
|
|
// Win95 always returns the original requested size (filling the
|
|
// remainder with NULLs). So if it is a DIBSECTION, we expect
|
|
// dibInfo.dsBmih.biSize != 0; otherwise it is a BITMAP.
|
|
|
|
if ((infoSize == sizeof(DIBSECTION)) &&
|
|
(Globals::IsNt || dibInfo.dsBmih.biSize))
|
|
{
|
|
if (dibInfo.dsBmih.biBitCount == 8)
|
|
{
|
|
isDib8 = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we've got an 8 bpp DIB section, extract its color table and create
|
|
// the palette map from this. Otherwise, call UpdateTranslate which will
|
|
// handle screen and compatible bitmaps.
|
|
|
|
if (isDib8)
|
|
{
|
|
// Get the color table from the DIBSection
|
|
|
|
RGBQUAD colorTable[256];
|
|
GetDIBColorTable(hdc, 0, 256, colorTable);
|
|
|
|
// Create a GDI+ ColorPalette object from it
|
|
// Note: the reason we use "255" here is because
|
|
// ColorPalette object already has 1 allocation for ARGB
|
|
|
|
ColorPalette *newPalette =
|
|
static_cast<ColorPalette *>(
|
|
GpMalloc(sizeof(ColorPalette) + 255 * sizeof(ARGB)));
|
|
|
|
if (newPalette)
|
|
{
|
|
newPalette->Flags = 0;
|
|
newPalette->Count = 256;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
newPalette->Entries[i] =
|
|
MAKEARGB(255,
|
|
colorTable[i].rgbRed,
|
|
colorTable[i].rgbGreen,
|
|
colorTable[i].rgbBlue);
|
|
}
|
|
|
|
CreateFromColorPalette(newPalette);
|
|
|
|
if (palette)
|
|
{
|
|
*palette = newPalette;
|
|
}
|
|
else
|
|
{
|
|
GpFree(newPalette);
|
|
}
|
|
|
|
SetValid(TRUE);
|
|
return;
|
|
}
|
|
|
|
SetValid(FALSE);
|
|
}
|
|
else
|
|
{
|
|
UpdateTranslate(hdc, palette);
|
|
}
|
|
}
|
|
|
|
EpPaletteMap::~EpPaletteMap()
|
|
{
|
|
SetValid(FALSE); // so we don't use a deleted object
|
|
}
|
|
|
|
VOID EpPaletteMap::UpdateTranslate(HDC hdc, ColorPalette **palette)
|
|
{
|
|
SetValid(FALSE);
|
|
|
|
HPALETTE hSysPal = NULL;
|
|
struct
|
|
{
|
|
LOGPALETTE logpalette;
|
|
PALETTEENTRY palEntries[256];
|
|
} pal;
|
|
|
|
pal.logpalette.palVersion = 0x0300;
|
|
|
|
// <SystemPalette>
|
|
|
|
// !!! [agodfrey] On Win9x, GetSystemPaletteEntries(hdc, 0, 256, NULL)
|
|
// doesn't do what MSDN says it does. It seems to return the number
|
|
// of entries in the logical palette of the DC instead. So we have
|
|
// to make it up ourselves.
|
|
|
|
pal.logpalette.palNumEntries = (1 << (GetDeviceCaps(hdc, BITSPIXEL) *
|
|
GetDeviceCaps(hdc, PLANES)));
|
|
|
|
GetSystemPaletteEntries(hdc, 0, 256, &pal.logpalette.palPalEntry[0]);
|
|
|
|
hSysPal = CreatePalette(&pal.logpalette);
|
|
|
|
if (hSysPal == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (palette)
|
|
{
|
|
// system palette is required for ScanDci case.
|
|
|
|
if (*palette == NULL)
|
|
{
|
|
*palette = (ColorPalette*)GpMalloc(sizeof(ColorPalette)+sizeof(ARGB)*256);
|
|
|
|
if (*palette == NULL)
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
(*palette)->Count = pal.logpalette.palNumEntries;
|
|
|
|
for (INT j=0; j<pal.logpalette.palNumEntries; j++)
|
|
{
|
|
(*palette)->Entries[j] = GpColor::MakeARGB(0xFF,
|
|
pal.logpalette.palPalEntry[j].peRed,
|
|
pal.logpalette.palPalEntry[j].peGreen,
|
|
pal.logpalette.palPalEntry[j].peBlue);
|
|
}
|
|
}
|
|
|
|
{
|
|
GpMemset(translate, 0, 256);
|
|
|
|
INT matchCount;
|
|
INT i;
|
|
PALETTEENTRY * halftonePalEntry = HTColorPalette.palPalEntry;
|
|
COLORREF halftoneColor;
|
|
COLORREF sysColor;
|
|
COLORREF matchedColor;
|
|
UINT matchingIndex;
|
|
|
|
// Create a translation table for the 216 halftone colors, and count
|
|
// how many exact matches we get.
|
|
|
|
for (i = 0, matchCount = 0; i < 256; i++, halftonePalEntry++)
|
|
{
|
|
if ((i > 11) || (i < 8))
|
|
{
|
|
halftoneColor = PALETTERGB(halftonePalEntry->peRed,
|
|
halftonePalEntry->peGreen,
|
|
halftonePalEntry->peBlue);
|
|
}
|
|
else // it is one of the magic 4 changeable system colors
|
|
{
|
|
halftoneColor = Globals::SystemColors[i + 8] | 0x02000000;
|
|
}
|
|
|
|
// See if the color is actually available in the system palette.
|
|
|
|
matchedColor = ::GetNearestColor(hdc, halftoneColor) | 0x02000000;
|
|
|
|
// Find the index of the matching color in the system palette
|
|
|
|
matchingIndex = ::GetNearestPaletteIndex(hSysPal, matchedColor);
|
|
|
|
if (matchingIndex == CLR_INVALID)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// We should never match to an entry outside of the device palette.
|
|
ASSERT(matchingIndex < pal.logpalette.palNumEntries);
|
|
|
|
translate[i] = static_cast<BYTE>(matchingIndex);
|
|
|
|
sysColor = PALETTERGB(pal.logpalette.palPalEntry[matchingIndex].peRed,
|
|
pal.logpalette.palPalEntry[matchingIndex].peGreen,
|
|
pal.logpalette.palPalEntry[matchingIndex].peBlue);
|
|
|
|
// see if we got an exact match
|
|
|
|
if ((i >= 40) && (sysColor == halftoneColor))
|
|
{
|
|
matchCount++;
|
|
}
|
|
}
|
|
|
|
// If we matched enough colors, we'll do 216-color halftoning.
|
|
// Otherwise, we'll have to halftone with the VGA colors.
|
|
// The palette returned from CreateHalftonePalette() on Win9x has
|
|
// only 212 of the required 216 halftone colors. (On NT it has all 216).
|
|
// The 4 colors missing from the Win9x halftone palette are:
|
|
// 0x00, 0x33, 0xFF
|
|
// 0x00, 0xFF, 0x33
|
|
// 0x33, 0x00, 0xFF
|
|
// 0x33, 0xFF, 0x00
|
|
// We require that all 212 colors be available because our GetNearestColor
|
|
// API assumes that all 216 colors are there if we're doing 216-color
|
|
// halftoning.
|
|
|
|
SetValid(TRUE);
|
|
|
|
if (matchCount >= 212)
|
|
{
|
|
isVGAOnly = FALSE;
|
|
}
|
|
else
|
|
{
|
|
isVGAOnly = TRUE;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
DeleteObject(hSysPal);
|
|
return;
|
|
}
|
|
|
|
|