// PBDib.cpp: implementation of the PBDib class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "PBDib.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
PBDib::PBDib()
{
m_hPalette = NULL;
m_hDIB = NULL;
}
PBDib::~PBDib()
{
Free();
}
void PBDib::Free()
{
if(m_hDIB)
{
::GlobalFree(m_hDIB);
m_hDIB = NULL;
}
if(m_hPalette)
{
::GlobalFree(m_hPalette);
m_hPalette = NULL;
}
}
BOOL PBDib::ReadDIBFile(LPCTSTR szFile)
{
BITMAPFILEHEADER bmfHeader;
DWORD dwBitsSize;
LPSTR pDIB;
HANDLE hFile;
Free();
hFile = ::CreateFile(szFile,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if(hFile == INVALID_HANDLE_VALUE)
return FALSE;
/*
* 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.
*/
DWORD dwRead;
if(!ReadFile(hFile,&bmfHeader, sizeof(bmfHeader),&dwRead,NULL))
{
::CloseHandle(hFile);
return FALSE;
}
if ( dwRead != sizeof(bmfHeader))
{
::CloseHandle(hFile);
return FALSE;
}
if (bmfHeader.bfType != DIB_HEADER_MARKER)
{
::CloseHandle(hFile);
return FALSE;
}
/* Allocate memory for DIB*/
m_hDIB = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
if (m_hDIB == 0)
{
::CloseHandle(hFile);
return FALSE;
}
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
/*
* Go read the bits.
*/
if(!ReadFile(hFile,pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER),&dwRead,NULL))
{
::CloseHandle(hFile);
::GlobalUnlock((HGLOBAL) m_hDIB);
::GlobalFree((HGLOBAL) m_hDIB);
return FALSE;
}
if (dwRead != dwBitsSize - sizeof(BITMAPFILEHEADER) )
{
::CloseHandle(hFile);
::GlobalUnlock((HGLOBAL) m_hDIB);
::GlobalFree((HGLOBAL) m_hDIB);
return FALSE;
}
::GlobalUnlock((HGLOBAL) m_hDIB);
::CloseHandle(hFile);
BOOL bLoadPalette = CreatePalette();
if(!bLoadPalette)
Free();
return bLoadPalette;
}
BOOL PBDib::CreatePalette()
{
LPLOGPALETTE lpPal; // pointer to a logical palette
HANDLE hLogPal; // handle to a logical palette
int i; // loop index
WORD wNumColors; // number of colors in color table
LPSTR lpbi; // pointer to packed-DIB
LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
BOOL bResult = FALSE;
/* if handle to DIB is invalid, return FALSE */
if (m_hDIB == NULL)
return FALSE;
lpbi = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
/* get pointer to BITMAPINFO (Win 3.0) */
lpbmi = (LPBITMAPINFO)lpbi;
/* get pointer to BITMAPCOREINFO (old 1.x) */
lpbmc = (LPBITMAPCOREINFO)lpbi;
/* get the number of colors in the DIB */
wNumColors = GetNumColors(lpbi);
if (wNumColors != 0)
{
/* allocate memory block for logical palette */
hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
+ sizeof(PALETTEENTRY)
* wNumColors);
/* if not enough memory, clean up and return NULL */
if (hLogPal == 0)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
return FALSE;
}
lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
/* set version and number of palette entries */
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)wNumColors;
/* is this a Win 3.0 DIB? */
bWinStyleDIB = IS_WIN30_DIB(lpbi);
for (i = 0; i < (int)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 */
m_hPalette = ::CreatePalette(lpPal);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
}
::GlobalUnlock((HGLOBAL) m_hDIB);
return (m_hPalette != NULL) ? TRUE : FALSE;
}
WORD PBDib::GetNumColors(LPSTR lpbi)
{
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(lpbi))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
if (dwClrUsed != 0)
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(lpbi))
wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpbi)->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;
}
}
int PBDib::GetHeight()
{
if(!m_hDIB)
return 0;
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
int nHeight = 0;
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* point to the header (whether old or Win 3.0 */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB height if it is a Win 3.0 DIB */
if (IS_WIN30_DIB(lpDIB))
nHeight = lpbmi->biHeight;
else /* it is an other-style DIB, so return its height */
nHeight = lpbmc->bcHeight;
::GlobalUnlock(m_hDIB);
return nHeight;
}
int PBDib::GetWidth()
{
if(!m_hDIB)
return 0;
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
int nWidth = 0;
LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* point to the header (whether old or Win 3.0 */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB height if it is a Win 3.0 DIB */
if (IS_WIN30_DIB(lpDIB))
nWidth = lpbmi->biWidth;
else /* it is an other-style DIB, so return its height */
nWidth = lpbmc->bcWidth;
::GlobalUnlock(m_hDIB);
return nWidth;
}
HBITMAP PBDib::CreateBitmap()
{
LPBITMAPINFOHEADER lpbi;
HDC hdc;
HBITMAP hbm;
HPALETTE hpalT;
if (!m_hDIB)
return NULL;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(m_hDIB);
if (!lpbi)
return NULL;
hdc = GetDC(NULL);
if (m_hPalette)
{
hpalT = SelectPalette(hdc,m_hPalette,FALSE);
RealizePalette(hdc); // GDI Bug...????
}
hbm = CreateDIBitmap(hdc,
(LPBITMAPINFOHEADER)lpbi,
(LONG)CBM_INIT,
(LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS );
if (m_hPalette)
SelectPalette(hdc,hpalT,FALSE);
ReleaseDC(NULL,hdc);
GlobalUnlock(m_hDIB);
return hbm;
}
int PBDib::PaletteSize(VOID FAR * pv)
{
LPBITMAPINFOHEADER lpbi;
WORD NumColors;
lpbi = (LPBITMAPINFOHEADER)pv;
NumColors = GetNumColors((LPSTR)lpbi);
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
return (NumColors * sizeof(RGBTRIPLE));
else
return (NumColors * sizeof(RGBQUAD));
}
HPALETTE PBDib::ClonePalette()
{
LPLOGPALETTE lpPal; // pointer to a logical palette
HANDLE hLogPal; // handle to a logical palette
int i; // loop index
WORD wNumColors; // number of colors in color table
LPSTR lpbi; // pointer to packed-DIB
LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
HPALETTE hPal;
/* if handle to DIB is invalid, return FALSE */
if (m_hDIB == NULL)
return NULL;
lpbi = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
/* get pointer to BITMAPINFO (Win 3.0) */
lpbmi = (LPBITMAPINFO)lpbi;
/* get pointer to BITMAPCOREINFO (old 1.x) */
lpbmc = (LPBITMAPCOREINFO)lpbi;
/* get the number of colors in the DIB */
wNumColors = GetNumColors(lpbi);
if (wNumColors != 0)
{
/* allocate memory block for logical palette */
hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
+ sizeof(PALETTEENTRY)
* wNumColors);
/* if not enough memory, clean up and return NULL */
if (hLogPal == 0)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
return NULL;
}
lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
/* set version and number of palette entries */
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)wNumColors;
/* is this a Win 3.0 DIB? */
bWinStyleDIB = IS_WIN30_DIB(lpbi);
for (i = 0; i < (int)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);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
}
::GlobalUnlock((HGLOBAL) m_hDIB);
return hPal;
}
HBITMAP PBDib::CreateBitmapXY(SIZE szBmp)
{
LPBITMAPINFOHEADER lpbi;
HDC hdc;
HBITMAP hbm;
HPALETTE hpalT;
if(szBmp.cx == 0 || szBmp.cy == 0)
return NULL;
if (!m_hDIB)
return NULL;
int h = GetHeight();
int w = GetWidth();
lpbi = (LPBITMAPINFOHEADER)GlobalLock(m_hDIB);
hdc = CreateCompatibleDC(NULL);
hbm = ::CreateCompatibleBitmap(hdc,szBmp.cx,szBmp.cy);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hdc,hbm);
if (m_hPalette)
{
hpalT = SelectPalette(hdc,m_hPalette,FALSE);
RealizePalette(hdc); // GDI Bug...????
}
StretchDIBits(hdc, 0,0, szBmp.cx,szBmp.cy,
0,0,w,h,
(LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS,
SRCCOPY);
if (m_hPalette)
SelectPalette(hdc,hpalT,FALSE);
SelectObject(hdc,hOldBmp);
ReleaseDC(NULL,hdc);
GlobalUnlock(m_hDIB);
return hbm;
}