/**************************************************************************\ * * 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(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(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(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( 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; // // !!! [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; jEntries[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(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; }