|
|
//+----------------------------------------------------------------------------
//
// File: image.cpp
//
// Module: CMDIAL and CMAK
//
// Synopsis: CMDIAL/CMAK specific imaging support routines
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// Author: nickball Created Header 03/30/98
// quintinb moved to common\source 08/06/98
//
//+----------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Function: CmGetBitmapInfo
//
// Synopsis: Helper function to retrieve the contents of a bitmap from an HBITMAP
//
// Arguments: hbm - Hanhdle of the target bitmap
//
// Returns: A pointer to a LPBITMAPINFO that contains the INFOHEADER,
// ColorTable and bits for the bitmap.
//
// Note: When accessing this value, or passing it on to other BITMAP APIs
// it is recommended that the value be cast as an (LPBYTE).
//
// History: a-nichb - Cleaned-up and commented - 3/21/97
//
//----------------------------------------------------------------------------
LPBITMAPINFO CmGetBitmapInfo(HBITMAP hbm) { LPBITMAPINFO pbmi = NULL; HDC hDC = NULL; int nNumColors = 0; int iRes; LPBITMAPINFO lpbmih = NULL; DWORD dwInfoSize = 0; WORD wbiBits = 0;
if (!hbm) { return NULL; } // Get the basic bmp object info
BITMAP BitMap; if (!GetObjectA(hbm, sizeof(BITMAP), &BitMap)) { goto Cleanup; }
// Calc the color bits and num colors
wbiBits = BitMap.bmPlanes * BitMap.bmBitsPixel;
if (wbiBits <= 8) { nNumColors = 1 << wbiBits; } // Allocate a BITMAPINFO structure large enough to hold header + color palette
dwInfoSize = sizeof(BITMAPINFOHEADER) + (nNumColors * sizeof(RGBQUAD)); lpbmih = (LPBITMAPINFO) CmMalloc(dwInfoSize);
if (!lpbmih) { goto Cleanup; } // Pre-fill the info that we have about the bmp
lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbmih->bmiHeader.biWidth = BitMap.bmWidth; lpbmih->bmiHeader.biHeight = BitMap.bmHeight; lpbmih->bmiHeader.biPlanes = 1; lpbmih->bmiHeader.biBitCount = wbiBits; // Call GetDiBits() w/ 5th Param to NULL, this is treated by the system as
// a query in which case it validates the lpbmih contents and fills in the
// biSizeImage member of the structure
hDC = GetDC(NULL); if (!hDC) { goto Cleanup; }
iRes = GetDIBits(hDC,hbm,0,BitMap.bmHeight,NULL,(LPBITMAPINFO) lpbmih,DIB_RGB_COLORS);
#ifdef DEBUG
if (!iRes) { CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() failed.")); } #endif
if (iRes) { DWORD dwFullSize = dwInfoSize; // Create a complete DIB structure with room for bits and fill it
if (lpbmih->bmiHeader.biSizeImage) { dwFullSize += lpbmih->bmiHeader.biSizeImage; } else { dwFullSize += (((WORD) (lpbmih->bmiHeader.biWidth * lpbmih->bmiHeader.biBitCount) / 8) * (WORD) BitMap.bmHeight); } pbmi = (LPBITMAPINFO) CmMalloc(dwFullSize + sizeof(DWORD));
#ifdef DEBUG
*((DWORD *) (((PBYTE) pbmi)+dwFullSize)) = 0x12345678; *((DWORD *) (((PBYTE) pbmi)+dwFullSize-sizeof(DWORD))) = 0x23456789; #endif
if (pbmi) { // Load the new larger LPBITMAPINFO struct with existing info,
// and get the data bits. Release the existing LPBITMAPINFO.
CopyMemory(pbmi, lpbmih, dwInfoSize); //
// We have a handle, we want the exact bits.
//
iRes = GetDIBits(hDC, hbm, 0, BitMap.bmHeight, ((LPBYTE) pbmi) + dwInfoSize, pbmi, DIB_RGB_COLORS);
#ifdef DEBUG
if (*((DWORD *) (((PBYTE) pbmi) + dwFullSize)) != 0x12345678) { CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() copied too much.")); }
if (*((DWORD *) (((PBYTE) pbmi) + dwFullSize - sizeof(DWORD))) == 0x23456789) { CMTRACE(TEXT("CmGetBitmapInfo() GetDIBits() didn't copy enough.")); } #endif
// If GetDiBits() failed, free the BITMAPINFO buffer
if (!iRes) { CmFree(pbmi); pbmi = NULL; } } } // Cleanup
Cleanup: if (lpbmih) { CmFree(lpbmih); } if (hDC) { ReleaseDC(NULL, hDC); } return pbmi; }
static HPALETTE CmCreateDIBPalette(LPBITMAPINFO pbmi) { WORD wNumColors = 0; HPALETTE hRes = NULL;
if (!pbmi) { return (NULL); } // Get num colors according to color depth
// Note: 24-bit bitmaps have no color table
if (pbmi->bmiHeader.biBitCount <= 8) { wNumColors = 1 << pbmi->bmiHeader.biBitCount; }
// Fill logical palette based upon color table
if (wNumColors) { LPLOGPALETTE pLogPal; int idx;
pLogPal = (LPLOGPALETTE) CmMalloc(sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*wNumColors); if (pLogPal) { pLogPal->palVersion = 0x300; pLogPal->palNumEntries = wNumColors; for (idx=0;idx<wNumColors;idx++) { pLogPal->palPalEntry[idx].peRed = pbmi->bmiColors[idx].rgbRed; pLogPal->palPalEntry[idx].peGreen = pbmi->bmiColors[idx].rgbGreen; pLogPal->palPalEntry[idx].peBlue = pbmi->bmiColors[idx].rgbBlue; pLogPal->palPalEntry[idx].peFlags = 0; } // Create a new palette
hRes = CreatePalette(pLogPal);
#ifdef DEBUG
if (!hRes) { CMTRACE1(TEXT("CmCreateDIBPalette() CreatePalette() failed, GLE=%u."), GetLastError()); } #endif
CmFree(pLogPal); } } return hRes; }
HBITMAP CmLoadBitmap(HINSTANCE hInst, LPCTSTR pszSpec) { return ((HBITMAP) CmLoadImage(hInst, pszSpec, IMAGE_BITMAP, 0, 0)); }
//+----------------------------------------------------------------------------
//
// Function: ReleaseBitmapData
//
// Synopsis: Releases resources and memory acquired during CreateBitmapData. Note
// that if you are using this with the BmpWndProc function below, that you
// should call an STM_SETIMAGE with a NULL image pointer param in order to
// clear out the window procedures window long. Otherwise, it could get
// a WM_PAINT message and try to use the freed memory before you can
// clear it out or have the window destroyed by the dialog manager.
//
// Arguments: LPBMPDATA pBmpData - Ptr to the BmpData to be released
//
// Returns: Nothing
//
// History: nickball Created 3/27/98
//
//+----------------------------------------------------------------------------
void ReleaseBitmapData(LPBMPDATA pBmpData) { MYDBGASSERT(pBmpData);
if (NULL == pBmpData) { return; }
if (pBmpData->hDIBitmap) { DeleteObject(pBmpData->hDIBitmap); pBmpData->hDIBitmap = NULL; } if (pBmpData->hDDBitmap) { DeleteObject(pBmpData->hDDBitmap); pBmpData->hDDBitmap = NULL; }
if (pBmpData->pBmi) { CmFree(pBmpData->pBmi); pBmpData->pBmi = NULL; } }
//+----------------------------------------------------------------------------
//
// Function: CreateBitmapData
//
// Synopsis: Fills a BMPDATA struct with all data necessary to display a bitmap.
//
// Arguments: HBITMAP hBmp - Handle of the source bitmap
// LPBMPDATA lpBmpData - Ptr to the BmpData struct to be filled
// HWND hwnd - The hwnd that the bitmap will be displayed in.
// BOOL fCustomPalette - Indicates that the DDB should be created with a palette specific to the bitmap.
//
// Returns: BOOL - TRUE on succes
//
// History: nickball Created 3/27/98
//
//+----------------------------------------------------------------------------
BOOL CreateBitmapData(HBITMAP hDIBmp, LPBMPDATA lpBmpData, HWND hwnd, BOOL fCustomPalette) { MYDBGASSERT(hDIBmp); MYDBGASSERT(lpBmpData); MYDBGASSERT(lpBmpData->phMasterPalette);
if (NULL == hDIBmp || NULL == lpBmpData) { return NULL; }
//
// Params look good, get busy
//
HPALETTE hPaletteNew = NULL; LPBITMAPINFO pBmi = NULL; HBITMAP hDDBmp = NULL; HDC hDC; int iRes = 0;
//
// If we already have a pBmi value, we will assume it is up to date, as
// both it and the DIB do not change throughout the life of the BMP.
// Note: If BmpData is not zero initialized, you will have problems.
//
if (lpBmpData->pBmi) { pBmi = lpBmpData->pBmi; } else { //
// Use the bitmap handle to retrieve a BITMAPINFO ptr complete w/ data
//
pBmi = CmGetBitmapInfo(lpBmpData->hDIBitmap); if (NULL == pBmi) { return FALSE; } } //
// we need a DC
//
hDC = GetDC(hwnd);
if (!hDC) { CMTRACE(TEXT("MyCreateDDBitmap() GetDC() failed.")); return FALSE; }
//
// If CM is localized so that it is RTL (Right to Left => arabic and Hebrew),
// then we need to call SetLayout on the hDC from above. If we don't
// set the layout back to LTR, the bitmap will show up as all black instead of as
// an image.
//
HMODULE hLib = LoadLibrary(TEXT("gdi32.dll")); if (hLib) { #ifndef LAYOUT_RTL
#define LAYOUT_RTL 0x00000001 // Right to left
#endif
typedef DWORD (WINAPI* pfnSetLayoutType)(HDC, DWORD); typedef DWORD (WINAPI* pfnGetLayoutType)(HDC);
pfnSetLayoutType pfnSetLayout = (pfnSetLayoutType)GetProcAddress(hLib, "SetLayout"); pfnGetLayoutType pfnGetLayout = (pfnGetLayoutType)GetProcAddress(hLib, "GetLayout");
if (pfnSetLayout && pfnGetLayout) { DWORD dwLayout = pfnGetLayout(hDC); if (LAYOUT_RTL & dwLayout) { dwLayout ^= LAYOUT_RTL; // toggle LAYOUT_RTL off
pfnSetLayout(hDC, dwLayout); CMTRACE(TEXT("CreateBitmapData -- Toggling off LAYOUT_RTL on the device context")); } }
FreeLibrary(hLib); }
//
// If fCustomPalette is set then create a palette based on our bits
// and realize it in the current DC.
//
if (fCustomPalette) { hPaletteNew = CmCreateDIBPalette(pBmi); if (hPaletteNew) { //
// Select and realize the new palette so that the DDB is created with it below
//
HPALETTE hPalettePrev = SelectPalette(hDC, hPaletteNew, lpBmpData->bForceBackground); // FALSE == Foreground app behavior);
// TRUE == Background app behavior);
if (hPalettePrev) { iRes = RealizePalette(hDC); #ifdef DEBUG
if (GDI_ERROR == iRes) { CMTRACE1(TEXT("MyCreateDDBitmap() RealizePalette() failed, GLE=%u."), GetLastError()); } } else { CMTRACE1(TEXT("MyCreateDDBitmap() SelectPalette() failed, GLE=%u."), GetLastError()); #endif
}
} }
//
// Determine number of color entries based upon color depth
//
int nNumColors = 0; if (pBmi->bmiHeader.biBitCount <= 8) { nNumColors = (1 << pBmi->bmiHeader.biBitCount); }
//
// Create the DDB from the bits
//
hDDBmp = CreateDIBitmap(hDC, &pBmi->bmiHeader, CBM_INIT, ((LPBYTE) pBmi) + sizeof(BITMAPINFOHEADER) + (nNumColors * sizeof(RGBQUAD)), //dib.dsBm.bmBits,
pBmi, DIB_RGB_COLORS);
#ifdef DEBUG
if (!hDDBmp) { CMTRACE(TEXT("MyCreateDDBitmap() CreateDIBitmap() failed.")); } #endif
ReleaseDC(NULL, hDC);
//
// Fill in the bitmap data
//
if (hDDBmp) { lpBmpData->hDIBitmap = hDIBmp; lpBmpData->pBmi = pBmi;
//
// Delete existing DDB, if any
//
if (lpBmpData->hDDBitmap) { DeleteObject(lpBmpData->hDDBitmap); }
lpBmpData->hDDBitmap = hDDBmp;
if (hPaletteNew) { //
// Delete existing Palette, if any
//
if (*lpBmpData->phMasterPalette) { DeleteObject(*lpBmpData->phMasterPalette); }
*lpBmpData->phMasterPalette = hPaletteNew; }
return TRUE; }
//
// Something went wrong, cleanup
//
CmFree(pBmi);
return FALSE; }
//
// Bitmap window procedure
//
LRESULT CALLBACK BmpWndProc(HWND hwndBmp, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPBMPDATA pBmpData = (LPBMPDATA) GetWindowLongU(hwndBmp,0); BOOL bRes;
switch (uMsg) { case WM_CREATE: { return FALSE; }
case WM_DESTROY: SetWindowLongU(hwndBmp,sizeof(LPBMPDATA),(LONG_PTR) NULL); break;
case WM_PAINT: if (pBmpData && pBmpData->pBmi) { LPBITMAPINFO pBmi = pBmpData->pBmi;
RECT rWnd; RECT rSrc = {0,0,(int)pBmpData->pBmi->bmiHeader.biWidth, (int)pBmpData->pBmi->bmiHeader.biHeight}; PAINTSTRUCT ps; HDC hdcBmp; HBITMAP hbmpPrev; int iPrevStretchMode; //
// Start painting
//
HDC hdc = BeginPaint(hwndBmp,&ps);
if (hdc) { //
// Select and realize our current palette in the current DC
//
//UnrealizeObject(*pBmpData->phMasterPalette);
SelectPalette(hdc, *pBmpData->phMasterPalette, pBmpData->bForceBackground); RealizePalette(hdc);
//
// Create a compatible DC, we'll create the BMP here then BLT it to the real DC
//
hdcBmp = CreateCompatibleDC(hdc);
if (hdcBmp) { //
// Select and realize our current palette in the compatible DC
//
SelectPalette(hdcBmp, *pBmpData->phMasterPalette, pBmpData->bForceBackground); RealizePalette(hdcBmp);
if (!hdcBmp) { CMTRACE(TEXT("BmpWndProc() CreateCompatibleDC() failed.")); }
if (!pBmpData->hDDBitmap) { CMTRACE(TEXT("BmpWndProc() - WM_PAINT - hDDBitmap is NULL.")); }
//
// Select the bitmap into the compatible DC
//
hbmpPrev = (HBITMAP) SelectObject(hdcBmp,pBmpData->hDDBitmap); bRes = GetWindowRect(hwndBmp,&rWnd);
if (!bRes) { CMTRACE1(TEXT("BmpWndProc() GetWindowRect() failed, GLE=%u."), GetLastError()); }
//
// Now set the mode, and StretchBlt the bitmap from the compatible DC to the active DC
//
CMTRACE(TEXT("BmpWndProc() : Changing stretch mode")); iPrevStretchMode = SetStretchBltMode(hdc, STRETCH_DELETESCANS);
bRes = StretchBlt(hdc, rWnd.left-rWnd.left, rWnd.top-rWnd.top, rWnd.right-rWnd.left, rWnd.bottom-rWnd.top, hdcBmp, rSrc.left-rSrc.left, rSrc.top-rSrc.top, rSrc.right-rSrc.left, rSrc.bottom-rSrc.top, SRCCOPY); if (!bRes) { CMTRACE1(TEXT("BmpWndProc() StretchBlt() failed, GLE=%u."), GetLastError()); }
//
// Restore the mode in the active DC
//
CMTRACE(TEXT("BmpWndProc() Restoring stretch mode")); iPrevStretchMode = SetStretchBltMode(hdc, iPrevStretchMode);
//
// Restore the compatible DC and release it
//
SelectObject(hdcBmp,hbmpPrev); DeleteDC(hdcBmp);
} else { CMTRACE1(TEXT("BmpWndProc() CreateCompatibleDC() failed, GLE=%u."), GetLastError()); }
bRes = EndPaint(hwndBmp,&ps);
if (!bRes) { CMTRACE(TEXT("BmpWndProc() EndPaint() failed.")); } } else { CMTRACE1(TEXT("BmpWndProc() BeginPaint() failed, GLE=%u."), GetLastError()); }
} break;
case STM_SETIMAGE: if (wParam == IMAGE_BITMAP) { CMTRACE2(TEXT("STM_SETIMAGE: wParam=%u, lParam=%u"), wParam, lParam);
//
// lParam contains a handle to the bitmap data, store it in extra bytes
//
SetWindowLongU(hwndBmp,0, lParam); // pBmpData
CMTRACE2(TEXT("SetWindowLongU called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
//
// Force a repaint
//
bRes = InvalidateRect(hwndBmp,NULL,TRUE);
CMTRACE2(TEXT("InvalidateRect called with hwndBmp = %u, lParam=%u"), hwndBmp, lParam);
#ifdef DEBUG
if (!bRes) { CMTRACE(TEXT("BmpWndProc() InvalidateRect() failed.")); } #endif
if (pBmpData && pBmpData->hDDBitmap) { return ((LRESULT) pBmpData->hDDBitmap); } else { return NULL; } } break; } return (DefWindowProcU(hwndBmp,uMsg,wParam,lParam)); }
//+---------------------------------------------------------------------------
//
// Function: QueryNewPalette
//
// Synopsis: Helper function to encapsulate handling of WM_QUERYNEWPALETTE
//
// Arguments: hwndDlg - Handle of the dialog receiving the message
// lpBmpData - Struct containing handles for bmp to display
// iBmpCtrl - Bitmap control ID
//
// Returns: Nothing
//
// History: a-nichb - Created - 7/14/97
//
//----------------------------------------------------------------------------
void QueryNewPalette(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl) { MYDBGASSERT(lpBmpData);
if (lpBmpData) { //
// We just handle this as a standard palette change because we
// want to ensure that we create a new DDB using a palette based
// upon our bitmap.
//
PaletteChanged(lpBmpData, hwndDlg, iBmpCtrl); } }
//+---------------------------------------------------------------------------
//
// Function: PaletteChanged
//
// Synopsis: Helper function to encapsulate handling of WM_PALETTECHANGED
//
// Arguments: hwndDlg - Handle of the dialog receiving the message
// lpBmpData - Struct containing handles for bmp to display
// iBmpCtrl - Bitmap control ID
//
// Returns: Nothing
//
// History: a-nichb - Created - 7/14/97
//
//----------------------------------------------------------------------------
void PaletteChanged(LPBMPDATA lpBmpData, HWND hwndDlg, int iBmpCtrl) { MYDBGASSERT(lpBmpData);
if (NULL == lpBmpData || NULL == lpBmpData->phMasterPalette) { return; }
//
// Unrealize the master palette if it exists
//
if (*lpBmpData->phMasterPalette) { UnrealizeObject(*lpBmpData->phMasterPalette); }
//
// Create a device dependent bitmap and appropriate palette
//
if (CreateBitmapData(lpBmpData->hDIBitmap, lpBmpData, hwndDlg, TRUE)) { //
// SetImage to update handles for painting and force draw
//
HBITMAP hbmpTmp = (HBITMAP) SendDlgItemMessageA(hwndDlg, iBmpCtrl, STM_SETIMAGE, IMAGE_BITMAP,(LPARAM) lpBmpData); #ifdef DEBUUG
if (!hbmpTmp) { CMTRACE(TEXT("PaletteChanged().WM_PALETTECHANGED - STM_SETIMAGE returned NULL.")); } #endif
} }
|