// 数据类型说明:
// WORD:16位无符号短整形,占2个字节
// DWORD:32位无符号短整形,占4个字节
// LONG:有符号32位整形,占4个字节
// RGBQUAD:用于定义调色板数组元素的类型
// LPBITMAPINFOHEADER:位图信息头(BITMAPINFOHEADER)的指针
// LOGPALETTE:定义了一个逻辑调色板
// LPRGBQUAD:指向RGBQUAD结构的指针
// HPALETTE:调色板句柄
// HDC:设备句柄
// HLOCAL:局部内存句柄
// HWND:窗口句柄
// HFILE:文件句柄
// HBITMAP:位图句柄
// HGLOBAL:表示一个内存块句柄,GlobalAlloc分配,GlobalLock读取
// LPSTR:一种字符串数据类型,指向以‘\0’结尾的32位ANSI字符数组指针
// LPCWSTR:一个纸箱unicode编码字符串的32位指针,指向字符串是wchar型,而不是char型
// BITMAPFILEHEADER:位图文件头结构体
// BITMAPINFOHEADER:位图信息头结构体
//************ 关于文件的操作:https://blog.csdn.net/virtualdesk/article/details/4379704 ************
// _lopen:以二进制形式打开指定的文件
// lread: 将文件中的数据读入内存缓冲区
// lwrite:将数据从内存缓冲区写入一个文件
// lcreat:创建一个文件
#include <stdio.h>
#include <Windows.h>
#define WIDTHBYTES(i) ((i+31)/32*4)
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
HBITMAP hBitmap;
HPALETTE hPalette;
HGLOBAL hImgData;
DWORD NumColors;
DWORD LineBytes; // 每行的字节数
int xOffset = 0, yOffset = 0;
BOOL LoadBmpFile(HWND hWnd, char *BmpFileName)
{
HFILE hf; // 文件句柄
LPBITMAPINFOHEADER lpImgData; // 信息头指针
LOGPALETTE *pPal; // 指向调色版的指针
LPRGBQUAD lpRGB; // 指向RGBQUAD结构的指针
HPALETTE hPrePalette; // 保存设备中调色板
HDC hDc; // 设备句柄
HLOCAL hPal; // 存储调色板的局部内存句柄
DWORD ImgSize; // 实际的图像数据占用的字节数
DWORD i;
BmpFileName = "G:\c语言图像处理\T102\T102\0.bmp";
if ((hf = _lopen(BmpFileName, OF_READ)) == HFILE_ERROR)
{
MessageBox(hWnd, (LPCWSTR)"File not found", (LPCWSTR)"ERROR Message", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
_lread(hf, (LPSTR)&bf, sizeof(BITMAPFILEHEADER)); // 将BITMAPFILEHEADER结构从文件中读出,写到bf中
_lread(hf, (LPSTR)&bi, sizeof(BITMAPINFOHEADER)); // 将BITMAPINFOHEADER结构从文件中读出,写到bf中
LineBytes = (DWORD)GDI_WIDTHBYTES(bi.biWidth*bi.biBitCount); // 每行的字节数
ImgSize = (DWORD)LineBytes*bi.biHeight; // 实际的图像数据占用的字节数
if (bi.biClrUsed != 0) // 调色板数组中实际的颜色数
NumColors = (DWORD)bi.biClrUsed;
else
{
switch (bi.biBitCount)
{
case 1:
NumColors = 2;
break;
case 4:
NumColors = 16;
break;
case 8:
NumColors = 256;
break;
case 24:
NumColors = 0;
break;
default:
MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE;
}
if (bf.bfOffBits != (DWORD)(NumColors*sizeof(RGBQUAD) // 计算出的偏移量与实际的偏移量不符,则颜色数出错
+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)))
{
MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE;
}
bf.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)
+NumColors*sizeof(RGBQUAD)+ImgSize; // 分配内存,大小为BITMAPINFOHEADER结构长度+调色板+实际位图
hImgData = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD)+ImgSize));
if (hImgData == NULL)
{
_lclose(hf);
return FALSE;
}
lpImgData = (LPBITMAPINFOHEADER)GlobalLock(hImgData); // lpImgData指向该内存区
_llseek(hf, sizeof(BITMAPFILEHEADER), SEEK_SET); // 文件指针重新定位到LPBITMAPINFOHEADER开始处
_hread(hf, (char*)lpImgData,
(long)sizeof(BITMAPINFOHEADER)+(long)NumColors*sizeof(RGBQUAD)+ImgSize); // 将文件内容读入lpImgData
_lclose(hf);
if (NumColors != 0) // 颜色数不为0,说明用到了调色板
{
hPal = LocalAlloc(LHND, sizeof(LOGPALETTE)+NumColors*sizeof(PALETTEENTRY)); // 为逻辑调色板分配内存
pPal = (LOGPALETTE*)LocalLock(hPal); // 指针pPal指向内存区
pPal->palNumEntries = NumColors; // 逻辑调色板结构头
pPal->palVersion = 0x300;
lpRGB = (LPRGBQUAD)((LPSTR)lpImgData + (DWORD)sizeof(BITMAPINFOHEADER)); // lpRGB指向调色板开始的位置
for (i = 0; i < NumColors; ++i) // 填写数据
{
pPal->palPalEntry[i].peRed = lpRGB->rgbRed;
pPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
pPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
pPal->palPalEntry[i].peFlags = (BYTE)0;
lpRGB++;
}
hPalette = CreatePalette(pPal); // 产生逻辑调色板
LocalUnlock(hPal); // 释放局部内存
LocalFree(hPal); // 释放局部内存
}
hDc = GetDC(hWnd); // 获取上下文句柄
if (hPalette)
{
hPrePalette = SelectPalette(hDc, hPalette, FALSE);//将新的逻辑调色板选入 DC,将旧的逻辑调色板句柄保存在//hPrevPalette
RealizePalette(hDc);
}
// 产生位图句柄
hBitmap = CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData, (LONG)CBM_INIT,
(LPSTR)lpImgData + sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpImgData, DIB_RGB_COLORS);
// 将原来的调色板(如果有的话)选入设备上下文句柄
if (hPalette && hPrePalette)
{
SelectPalette(hDc, hPrePalette, FALSE);
RealizePalette(hDc);
}
ReleaseDC(hWnd, hDc); // 释放设备上下文
GlobalUnlock(hImgData); // 解锁内存区
return TRUE;
}
}