void FadeGrayScaleToColor(
CDC *pDC, HANDLE hDIB,
int xDest, int yDest,
int nLoops,int nDelay )
{
CPalette pal;
CPalette *pOldPalette;
PALETTEENTRY peAnimate[256];
PALETTEENTRY peGray[256];
PALETTEENTRY peOriginal[256];
Zunächst werden die Eckdaten bestimmt.
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB;
int nColors = bmInfo.bmiHeader.biClrUsed ?
bmInfo.bmiHeader.biClrUsed :
1 << bmInfo.bmiHeader.biBitCount;
int nReservedColors = nColors > 236 ? 236 : nReservedColors;
int nWidth = bmInfo.bmiHeader.biWidth;
int nHeight = bmInfo.bmiHeader.biHeight;
Falls benötigt, wird als nächstes eine logische Platte erzeugt.
if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE &&
nColors <= 256 )
{
HPALETTE hPal = CreateReservedPalette(hDIB);
pal.Attach( hPal );
Nach dem Speichern der Ausgangsfarben können nun die Grauwerte gesetzt werden.
pal.GetPaletteEntries(0, nReservedColors,
(LPPALETTEENTRY)&peGray);
for( int i=0; i < nReservedColors; i++)
{
peOriginal[i].peRed = peGray[i].peRed ;
peOriginal[i].peGreen = peGray[i].peGreen;
peOriginal[i].peBlue = peGray[i].peBlue ;
long lSquareSum = peGray[i].peRed * peGray[i].peRed +
peGray[i].peGreen * peGray[i].peGreen +
peGray[i].peBlue * peGray[i].peBlue;
int nGray = (int)sqrt(((double)lSquareSum)/3);
peGray[i].peRed = nGray;
peGray[i].peGreen = nGray;
peGray[i].peBlue = nGray;
}
Die so erzeugte Palette kann nun in den Ausgabekontext selektiert und realisiert werden.
pOldPalette = pDC->SelectPalette(&pal, FALSE);
pDC->RealizePalette();
Unter Zuhilfenahme eines Speicherkontextes wird die Bitmap ohne Farbumsetzung gezeichnet.
CDC memDC;
memDC.CreateCompatibleDC( pDC );
CBitmap bmp;
bmp.CreateCompatibleBitmap( pDC, nWidth, nHeight );
CBitmap *pOldBitmap = memDC.SelectObject( &bmp );
CPalette *pOldMemPalette = memDC.SelectPalette(&pal, FALSE);
memDC.RealizePalette();
Das Zeichnen der Bitmap in den Speicherkontext erfolgt über die Aufrufe:
LPVOID lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
::SetDIBitsToDevice(memDC.m_hDC, 0, 0, nWidth, nHeight, 0, 0, 0,
nHeight, lpDIBBits, (LPBITMAPINFO)hDIB,
DIB_RGB_COLORS);
Nach dem nachfolgenden Setzen der Farbe auf Grauwerte kann die Bitmap vom Speicherkontext in den Ausgabekontext kopiert werden. Hierbei findet kein Farbmapping statt, da in beiden Kontexten die Paletten identisch sind, so daß die Bitmap in der Startfarbe erscheint.
AnimatePalette(hPal, 0, nColors, (LPPALETTEENTRY)&peGray);
pDC->BitBlt(xDest, yDest, nWidth, nHeight, &memDC,0,0,SRCCOPY );
Es erfolgt nun die Übernahme der Grauwerteinträge in die Animationspalette sowie das Zurückselektieren der alten Objekte in den Speicherkontext.
pal.GetPaletteEntries(0, nColors, (LPPALETTEENTRY)&peAnimate);
memDC.SelectPalette(pOldMemPalette, FALSE);
memDC.SelectObject( pOldBitmap );
Jetzt kann die Palettenanimation erfolgen, um die Bitmap in Farben anzuzeigen.
for( i=1; i <= nLoops; i++ )
{
for (int j = 0; j< nColors; j++)
{
peAnimate[j].peRed = peGray[j].peRed -
((peGray[j].peRed -peOriginal[j].peRed)*i)/nLoops;
peAnimate[j].peGreen = peGray[j].peGreen -
((peGray[j].peGreen-peOriginal[j].peGreen)*i)
peAnimate[j].peBlue = peGray[j].peBlue -
((peGray[j].peBlue -peOriginal[j].peBlue)*i)/nLoops;
peAnimate[j].peFlags = peGray[j].peFlags;
}
pal.AnimatePalette(0, nColors, (LPPALETTEENTRY)&peAnimate);
Sleep(nDelay);
}
pDC->SelectPalette(pOldPalette, FALSE);
}
Unterstützt das Ausgabegerät keine Paletten, aber besitzt die Bitmap eine Farbtabelle, kann die Farbtabelle direkt modifiziert werden. Hierzu werden in einer Schleife zunächst die Ausgabewerte gesichert, dann die Werte berechnet und zuletzt die Referenzfarbtabelle erzeugt.
else if( (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) == 0 &&
nColors <= 256 )
{
for( int i=0; i < nColors; i++)
{
peOriginal[i].peRed = bmInfo.bmiColors[i].rgbRed ;
peOriginal[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
peOriginal[i].peBlue = bmInfo.bmiColors[i].rgbBlue ;
long lSquareSum = bmInfo.bmiColors[i].rgbRed *
bmInfo.bmiColors[i].rgbRed +
bmInfo.bmiColors[i].rgbGreen *
bmInfo.bmiColors[i].rgbGreen +
bmInfo.bmiColors[i].rgbBlue *
bmInfo.bmiColors[i].rgbBlue;
int nGray = (int)sqrt(((double)lSquareSum)/3);
bmInfo.bmiColors[i].rgbRed = nGray;
bmInfo.bmiColors[i].rgbGreen = nGray;
bmInfo.bmiColors[i].rgbBlue = nGray;
peGray[i].peRed = nGray;
peGray[i].peGreen = nGray;
peGray[i].peBlue = nGray;
}
Jetzt kann die Grauwertbitmap ausgegeben werden...
LPVOID lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight,
0, 0, 0, nHeight, lpDIBBits,
(LPBITMAPINFO)hDIB, DIB_RGB_COLORS);
...und anschließend die Farbbitmap:
for( i=1; i <= nLoops; i++ )
{
for (int j = 0; j< nColors; j++)
{
bmInfo.bmiColors[j].rgbRed = peGray[j].peRed -
((peGray[j].peRed -peOriginal[j].peRed)*i)/nLoops;
bmInfo.bmiColors[j].rgbGreen = peGray[j].peGreen -
((peGray[j].peGreen-peOriginal[j].peGreen)*i)/nLoops;
bmInfo.bmiColors[j].rgbBlue = peGray[j].peBlue -
((peGray[j].peBlue -peOriginal[j].peBlue)*i)/nLoops;
}
Abschließend wird die Bitmap noch einmal ausgegeben.
::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight,
0, 0, 0, nHeight, lpDIBBits,
(LPBITMAPINFO)hDIB, DIB_RGB_COLORS);
Sleep(nDelay);
}
}
Für alle übrigen Situationen wird die Bitmap einfach so ausgegeben, wie sie ist.
else
{
LPVOID lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight,
0, 0, 0, nHeight, lpDIBBits,
(LPBITMAPINFO)hDIB, DIB_RGB_COLORS);
}
}
|