572 lines
16 KiB
C
572 lines
16 KiB
C
/*---------------------------------------------------------------------------
|
|
**
|
|
**-------------------------------------------------------------------------*/
|
|
#include <pch.h>
|
|
#include "dibutil.h"
|
|
|
|
HANDLE ReadDIBFile(HANDLE hfile);
|
|
|
|
/*************************************************************************
|
|
*
|
|
* GetDeviceNumColors()
|
|
*
|
|
* Purpose: Determines how many colors the video device supports
|
|
*
|
|
* Returns: (int) Number of colors supported
|
|
*
|
|
* History: Date Author Reason
|
|
* 2/28/97 hanumany Created
|
|
*
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
UINT GetDeviceNumColors(HDC hdc)
|
|
{
|
|
static UINT iNumColors = 0;
|
|
|
|
if(!iNumColors)
|
|
iNumColors = GetDeviceCaps(hdc, NUMCOLORS);
|
|
|
|
return iNumColors;
|
|
}
|
|
|
|
|
|
HANDLE LoadDIB(LPTSTR lpFileName)
|
|
{
|
|
HANDLE hDIB = NULL;
|
|
HANDLE hFile;
|
|
|
|
/*
|
|
* Set the cursor to a hourglass, in case the loading operation
|
|
* takes more than a sec, the user will know what's going on.
|
|
*/
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
hDIB = ReadDIBFile(hFile);
|
|
CloseHandle(hFile);
|
|
}
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
return hDIB;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Dib Header Marker - used in writing DIBs to files
|
|
*/
|
|
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
|
|
|
|
HANDLE ReadDIBFile(HANDLE hFile)
|
|
{
|
|
BITMAPFILEHEADER bmfHeader;
|
|
DWORD dwBitsSize;
|
|
DWORD dwRead;
|
|
HANDLE hDIB;
|
|
|
|
/*
|
|
* get length of DIB in bytes for use when reading
|
|
*/
|
|
|
|
dwBitsSize = GetFileSize(hFile, NULL);
|
|
|
|
/*
|
|
* Go read the DIB file header and check if it's valid.
|
|
*/
|
|
if ((ReadFile(hFile, (LPVOID)&bmfHeader, sizeof(bmfHeader), &dwRead, NULL) == 0) ||
|
|
(sizeof (bmfHeader) != dwRead))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (bmfHeader.bfType != DIB_HEADER_MARKER)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Allocate memory for DIB
|
|
*/
|
|
hDIB = (HANDLE) HeapAlloc(GetProcessHeap(), 0, dwBitsSize);
|
|
if (hDIB == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Go read the bits.
|
|
*/
|
|
if ((ReadFile(hFile, (LPVOID)hDIB, dwBitsSize - sizeof(BITMAPFILEHEADER), &dwRead, NULL) == 0) ||
|
|
(dwBitsSize - sizeof(BITMAPFILEHEADER)!= dwRead))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, hDIB);
|
|
return NULL;
|
|
}
|
|
return hDIB;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DIBNumColors()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPBYTE lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* WORD - number of colors in the color table
|
|
*
|
|
* Description:
|
|
*
|
|
* This function calculates the number of colors in the DIB's color table
|
|
* by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
|
|
* DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
|
|
* if 24, no colors in color table.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
WORD DIBNumColors(LPBYTE lpDIB)
|
|
{
|
|
WORD wBitCount; // DIB bit count
|
|
|
|
/* If this is a Windows-style DIB, the number of colors in the
|
|
* color table can be less than the number of bits per pixel
|
|
* allows for (i.e. lpbi->biClrUsed can be set to some value).
|
|
* If this is the case, return the appropriate value.
|
|
*/
|
|
|
|
if (IS_WIN30_DIB(lpDIB))
|
|
{
|
|
DWORD dwClrUsed;
|
|
|
|
dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
|
|
if (dwClrUsed)
|
|
{
|
|
return (WORD)dwClrUsed;
|
|
}
|
|
}
|
|
|
|
/* Calculate the number of colors in the color table based on
|
|
* the number of bits per pixel for the DIB.
|
|
*/
|
|
if (IS_WIN30_DIB(lpDIB))
|
|
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
|
|
else
|
|
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
|
|
|
|
/* return number of colors based on bits per pixel */
|
|
switch (wBitCount)
|
|
{
|
|
case 1:
|
|
return 2;
|
|
|
|
case 4:
|
|
return 16;
|
|
|
|
case 8:
|
|
return 256;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// B U I L D P A L E T T E
|
|
//
|
|
// Creates an HPALETTE from a bitmap in a DC
|
|
//-------------------------------------------------------------------------
|
|
HPALETTE BuildPalette(HDC hdc)
|
|
{
|
|
DWORD adw[257];
|
|
int i,n;
|
|
|
|
n = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)&adw[1]);
|
|
if (n == 0)
|
|
return CreateHalftonePalette(hdc);
|
|
|
|
for (i=1; i<=n; i++)
|
|
{
|
|
adw[i] = RGB(GetBValue(adw[i]),GetGValue(adw[i]),GetRValue(adw[i]));
|
|
}
|
|
adw[0] = MAKELONG(0x300, n);
|
|
|
|
return CreatePalette((LPLOGPALETTE)&adw[0]);
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* CreateDIBPalette()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* HDIB hDIB - specifies the DIB
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HPALETTE - specifies the palette
|
|
*
|
|
* Description:
|
|
*
|
|
* This function creates a palette from a DIB by allocating memory for the
|
|
* logical palette, reading and storing the colors from the DIB's color table
|
|
* into the logical palette, creating a palette from this logical palette,
|
|
* and then returning the palette's handle. This allows the DIB to be
|
|
* displayed using the best possible colors (important for DIBs with 256 or
|
|
* more colors).
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
* 10/08/97 hanumany check GlobalLock return code
|
|
*
|
|
************************************************************************/
|
|
HPALETTE CreateDIBPalette(HDIB hDIB)
|
|
{
|
|
LPLOGPALETTE lpPal = NULL; // pointer to a logical palette
|
|
HANDLE hLogPal = NULL; // handle to a logical palette
|
|
HPALETTE hPal = NULL; // handle to a palette
|
|
int i = 0, wNumColors = 0; // loop index, number of colors in color table
|
|
LPBYTE lpbi = NULL; // pointer to packed-DIB
|
|
LPBITMAPINFO lpbmi = NULL; // pointer to BITMAPINFO structure (Win3.0)
|
|
LPBITMAPCOREINFO lpbmc = NULL; // pointer to BITMAPCOREINFO structure (OS/2)
|
|
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
|
|
|
|
/* if handle to DIB is invalid, return NULL */
|
|
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* get pointer to BITMAPINFO (Win 3.0) */
|
|
lpbmi = (LPBITMAPINFO)hDIB;
|
|
|
|
/* get pointer to BITMAPCOREINFO (OS/2 1.x) */
|
|
lpbmc = (LPBITMAPCOREINFO)hDIB;
|
|
|
|
/* get the number of colors in the DIB */
|
|
wNumColors = DIBNumColors(hDIB);
|
|
|
|
/* is this a Win 3.0 DIB? */
|
|
bWinStyleDIB = IS_WIN30_DIB(hDIB);
|
|
if (wNumColors)
|
|
{
|
|
/* allocate memory block for logical palette */
|
|
lpPal = (HANDLE) HeapAlloc(GetProcessHeap(), 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * wNumColors);
|
|
|
|
/* if not enough memory, clean up and return NULL */
|
|
if (!lpPal)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* set version and number of palette entries */
|
|
lpPal->palVersion = PALVERSION;
|
|
lpPal->palNumEntries = (WORD)wNumColors;
|
|
|
|
/* store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
|
|
* into palette
|
|
*/
|
|
for (i = 0; i < wNumColors; i++)
|
|
{
|
|
if (bWinStyleDIB)
|
|
{
|
|
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
|
|
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
|
|
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
|
|
lpPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
else
|
|
{
|
|
lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
|
|
lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
|
|
lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
|
|
lpPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
}
|
|
|
|
/* create the palette and get handle to it */
|
|
hPal = CreatePalette(lpPal);
|
|
}
|
|
|
|
/* clean up */
|
|
HeapFree(GetProcessHeap(), 0, lpPal);
|
|
|
|
/* return handle to DIB's palette */
|
|
return hPal;
|
|
}
|
|
|
|
|
|
WORD PaletteSize(LPBYTE lpDIB)
|
|
{
|
|
/* calculate the size required by the palette */
|
|
if (IS_WIN30_DIB (lpDIB))
|
|
return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
|
|
else
|
|
return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
|
|
}
|
|
/*************************************************************************
|
|
*
|
|
* FindDIBBits()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPBYTE lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* LPBYTE - pointer to the DIB bits
|
|
*
|
|
* Description:
|
|
*
|
|
* This function calculates the address of the DIB's bits and returns a
|
|
* pointer to the DIB bits.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
LPBYTE FindDIBBits(LPBYTE lpDIB)
|
|
{
|
|
return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
|
|
}
|
|
/*************************************************************************
|
|
*
|
|
* DIBToBitmap()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* HDIB hDIB - specifies the DIB to convert
|
|
*
|
|
* HPALETTE hPal - specifies the palette to use with the bitmap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HBITMAP - identifies the device-dependent bitmap
|
|
*
|
|
* Description:
|
|
*
|
|
* This function creates a bitmap from a DIB using the specified palette.
|
|
* If no palette is specified, default is used.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* The bitmap returned from this funciton is always a bitmap compatible
|
|
* with the screen (e.g. same bits/pixel and color planes) rather than
|
|
* a bitmap with the same attributes as the DIB. This behavior is by
|
|
* design, and occurs because this function calls CreateDIBitmap to
|
|
* do its work, and CreateDIBitmap always creates a bitmap compatible
|
|
* with the hDC parameter passed in (because it in turn calls
|
|
* CreateCompatibleBitmap).
|
|
*
|
|
* So for instance, if your DIB is a monochrome DIB and you call this
|
|
* function, you will not get back a monochrome HBITMAP -- you will
|
|
* get an HBITMAP compatible with the screen DC, but with only 2
|
|
* colors used in the bitmap.
|
|
*
|
|
* If your application requires a monochrome HBITMAP returned for a
|
|
* monochrome DIB, use the function SetDIBits().
|
|
*
|
|
* Also, the DIBpassed in to the function is not destroyed on exit. This
|
|
* must be done later, once it is no longer needed.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
* 3/27/92 Mark Bader Added comments about resulting
|
|
* bitmap format
|
|
* 10/08/97 hanumany check GlobalLock return code.
|
|
*
|
|
************************************************************************/
|
|
HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal)
|
|
{
|
|
LPBYTE lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits
|
|
HBITMAP hBitmap; // handle to device-dependent bitmap
|
|
HDC hDC; // handle to DC
|
|
HPALETTE hOldPal = NULL; // handle to a palette
|
|
|
|
/* if invalid handle, return NULL */
|
|
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* get a pointer to the DIB bits */
|
|
lpDIBBits = FindDIBBits(hDIB);
|
|
|
|
/* get a DC */
|
|
hDC = GetDC(NULL);
|
|
if (!hDC)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* select and realize palette */
|
|
if (hPal)
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
|
|
/* create bitmap from DIB info. and bits */
|
|
hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)hDIB, CBM_INIT,
|
|
(LPCVOID)lpDIBBits, (LPBITMAPINFO)hDIB, DIB_RGB_COLORS);
|
|
|
|
/* restore previous palette */
|
|
if (hOldPal)
|
|
SelectPalette(hDC, hOldPal, FALSE);
|
|
|
|
/* clean up */
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
/* return handle to the bitmap */
|
|
return hBitmap;
|
|
}
|
|
|
|
WORD DestroyDIB(HDIB hDib)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, hDib);
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************
|
|
*
|
|
* DrawBitmap()
|
|
*
|
|
* This function paints the given bitmap at the given coordinates.
|
|
*
|
|
******************************************************************/
|
|
void DrawBitmap (HDC hdc, HBITMAP hBitmap, int xStart, int yStart)
|
|
{
|
|
BITMAP bm;
|
|
HDC hdcMem;
|
|
POINT ptSize, ptOrg;
|
|
HBITMAP hBitmapOld = NULL;
|
|
|
|
if (hBitmap == NULL) {
|
|
return;
|
|
}
|
|
|
|
hdcMem = CreateCompatibleDC (hdc);
|
|
if (hdcMem == NULL)
|
|
{
|
|
return;
|
|
}
|
|
SetBkMode(hdcMem, TRANSPARENT);
|
|
hBitmapOld = SelectObject(hdcMem, hBitmap);
|
|
SetMapMode(hdcMem, GetMapMode(hdc));
|
|
|
|
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
|
|
ptSize.x = bm.bmWidth;
|
|
ptSize.y = bm.bmHeight;
|
|
DPtoLP(hdc, &ptSize, 1);
|
|
|
|
ptOrg.x = 0;
|
|
ptOrg.y = 0;
|
|
DPtoLP(hdcMem, &ptOrg, 1);
|
|
|
|
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY);
|
|
|
|
SelectObject(hdcMem, hBitmapOld);
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
/******************************************************************
|
|
*
|
|
* DrawTransparentBitmap()
|
|
*
|
|
* This function paints the given bitmap at the given coordinates.
|
|
* and allow for one transparent color
|
|
*
|
|
******************************************************************/
|
|
void DrawTransparentBitmap(
|
|
HDC hdc,
|
|
HBITMAP hBitmap,
|
|
int xStart,
|
|
int yStart,
|
|
COLORREF cTransparentColor )
|
|
{
|
|
BITMAP bm;
|
|
COLORREF cColor;
|
|
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
|
|
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
|
|
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
|
|
POINT ptSize;
|
|
COLORREF cTransparentColor2;
|
|
|
|
hdcTemp = CreateCompatibleDC(hdc);
|
|
SelectObject(hdcTemp, hBitmap);
|
|
|
|
cTransparentColor2 = GetPixel(hdcTemp, 0, 0);
|
|
if (cTransparentColor2 == CLR_INVALID)
|
|
{
|
|
cTransparentColor2 = cTransparentColor;
|
|
}
|
|
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
|
|
ptSize.x = bm.bmWidth;
|
|
ptSize.y = bm.bmHeight;
|
|
DPtoLP(hdcTemp, &ptSize, 1);
|
|
|
|
hdcBack = CreateCompatibleDC(hdc);
|
|
hdcObject = CreateCompatibleDC(hdc);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
hdcSave = CreateCompatibleDC(hdc);
|
|
|
|
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
|
|
|
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
|
|
|
bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
|
|
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
|
|
|
|
bmBackOld = SelectObject(hdcBack, bmAndBack);
|
|
bmObjectOld = SelectObject(hdcObject, bmAndObject);
|
|
bmMemOld = SelectObject(hdcMem, bmAndMem);
|
|
bmSaveOld = SelectObject(hdcSave, bmSave);
|
|
|
|
SetMapMode(hdcTemp, GetMapMode(hdc));
|
|
|
|
BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
|
|
|
|
cColor = SetBkColor(hdcTemp, cTransparentColor2);
|
|
|
|
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
|
|
SRCCOPY);
|
|
|
|
SetBkColor(hdcTemp, cColor);
|
|
|
|
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
|
|
NOTSRCCOPY);
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,
|
|
SRCCOPY);
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
|
|
|
|
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
|
|
|
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,
|
|
SRCCOPY);
|
|
|
|
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
|
|
|
|
DeleteObject(SelectObject(hdcBack, bmBackOld));
|
|
DeleteObject(SelectObject(hdcObject, bmObjectOld));
|
|
DeleteObject(SelectObject(hdcMem, bmMemOld));
|
|
DeleteObject(SelectObject(hdcSave, bmSaveOld));
|
|
|
|
DeleteDC(hdcMem);
|
|
DeleteDC(hdcBack);
|
|
DeleteDC(hdcObject);
|
|
DeleteDC(hdcSave);
|
|
DeleteDC(hdcTemp);
|
|
}
|
|
|