绘制BMP位图文件

时间:2020-11-29 11:49:09
绘制BMP位图文件
 
    BMP文件由三部分组成:有关文件信息的BITMAPFILEHEADER,有关位图
信息的BITMAPINFO以及位图的图象数据。其中BITMAPINFO又由位图信息头
BITMAPINFOHEADER和颜色表组成,颜色表不是
必须的。
几个结构的定义可查看联机帮助。一旦把BMP位图读入内存后,只要用上一
篇介绍的显示位图的
方法就可以显示了。
函数1:装载位图文件,生成位图GDI对象,用DDB方法显示。
// LoadBMPImage - 装载BMP位图,创建位图GDI对象同时创建位图调色板
// Returns - 返回TRUE成功
// sBMPFile - 全路经BMP文件
// bitmap - 将被初始化的位图对象
// pPal         - 将被初始化的位图调色板,可为NULL
BOOL LoadBMPImage( LPCTSTR sBMPFile, CBitmap& bitmap, CPalette *pPal )
{
CFile file;
if( !file.Open( sBMPFile, CFile::modeRead) )
return FALSE;

BITMAPFILEHEADER bmfHeader;

//读文件头
if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
return FALSE;

// 文件类型标志是否为‘BM’
if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
return FALSE;

//获得文件将需的内存数
DWORD nPackedDIBLen = file.GetLength() - sizeof(BITMAPFILEHEADER);
HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nPackedDIBLen);
if (hDIB == 0)
return FALSE;

// 读余下的位图文件
if (file.ReadHuge((LPSTR)hDIB, nPackedDIBLen) != nPackedDIBLen )
{
::GlobalFree(hDIB);
return FALSE;
}


BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

// 位图颜色数
int nColors = bmiHeader.biClrUsed ? bmiHeader.biClrUsed :
1 << bmiHeader.biBitCount;

LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors + bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);

// 创建逻辑调色板
if( pPal != NULL )
{
if( nColors <= 256 )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];

pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;

for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}

pPal->CreatePalette( pLP );

delete[] pLP;
}
}

CClientDC dc(NULL);
CPalette* pOldPalette = NULL;
if( pPal )
{
pOldPalette = dc.SelectPalette( pPal, FALSE );
dc.RealizePalette();
}

HBITMAP hBmp = CreateDIBitmap( dc.m_hDC, // 设备句柄
&bmiHeader, // pointer to bitmap size and format data
CBM_INIT, // initialization flag
lpDIBBits, // pointer to initialization data
&bmInfo, // pointer to bitmap color-format data
DIB_RGB_COLORS); // color-data usage
bitmap.Attach( hBmp );

if( pOldPalette )
dc.SelectPalette( pOldPalette, FALSE );

::GlobalFree(hDIB);
return TRUE;
}

函数2:装载位图文件,生成位图设备句柄,用DIB方法显示。
// LoadBMP - 装载位图文件,获得位图句柄与位图调色板
// Returns - 返回TRUE成功
// sBMPFile - 全路径BMP文件
// phDIB - 指向一个巳分配的HGLOBAL句柄
// pPal - 指向位图调色板
BOOL LoadBMP( LPCTSTR sBMPFile, HGLOBAL *phDIB, CPalette *pPal )
{
CFile file;
if( !file.Open( sBMPFile, CFile::modeRead) )
return FALSE;

BITMAPFILEHEADER bmfHeader;
long nFileLen;

nFileLen = file.GetLength();


// Read file header
if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
return FALSE;

// File type should be 'BM'
if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
return FALSE;

HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nFileLen);
if (hDIB == 0)
return FALSE;

// Read the remainder of the bitmap file.
if (file.ReadHuge((LPSTR)hDIB, nFileLen - sizeof(BITMAPFILEHEADER)) !=
nFileLen - sizeof(BITMAPFILEHEADER) )
{
::GlobalFree(hDIB);
return FALSE;
}



BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
1 << bmInfo.bmiHeader.biBitCount;

// Create the palette
if( nColors <= 256 )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];

pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;

for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}

pPal->CreatePalette( pLP );

delete[] pLP;
}

*phDIB = hDIB;
return TRUE;
}