// 数据类型说明:
// 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;
	}
}

 

10-04 15:08