BMP格式图片的读取与显示(MFC)

该博客介绍了如何在MFC环境下读取和显示BMP格式的图片。通过定义CDib类,实现了从文件加载图片、保存图片、获取图片尺寸、颜色数、显示图片等关键功能。代码详细解析了位图文件头、信息头的读取,以及位图数据的处理。此外,还提供了位图颜色数的计算方法和显示图片的 StretchDIBits 函数使用。
摘要由CSDN通过智能技术生成

BMP格式图片的读取与显示(MFC)

BMP格式示意图

BMP格式简图(上述指针在读取图片会用到)

1.构造Dib类

class CDib : public CObject
{
public:
	CDib();
	~CDib();

	BOOL LoadFromFile(LPCTSTR path);//从文件加载图片
	BOOL SaveToFile(LPCTSTR path);//保存图片到文件
	LPCTSTR GetFileName();//获取文件名
	LONG GetWidth();//获取图片宽度
	LONG GetHeight();//获取图像高度
	CSize GetDimension();//获取图像的高度和宽度
	DWORD GetSize();//获取图片大小
	WORD GetBitCount();//获取单个比特的大小
	UINT GetLineByte();//获取每行像素所占字节数
	DWORD GetNumOfColor();//获取位图颜色数
	LPRGBQUAD GetRgbQuad();//获取图片颜色表
	LPBYTE GetData();//获取图片数据
	BOOL Draw(CDC* pDC, CRect rect);//显示图片
	BOOL RgbToGrade();//24位彩色转8位灰度

	BOOL IsVaild();//判断是否有效
	BOOL IsGrade();//判断是否灰度图
	BOOL HasRgbQuad();//判断是否有颜色表

protected:
	DWORD CalcRgbQuadLength();//计算颜色表长度
	void Empty(BOOL bFlag = TRUE);//清理空间
	
private:
	char m_fileName[255];//文件名
	LPBITMAPFILEHEADER m_lpBmpFileHeader;//位图文件头指针
	LPBITMAPINFOHEADER m_lpBmpInfoHeader;//位图信息头指针,需要动态分配和释放
	LPBYTE m_lpDib;//位图指针,包含除了文件头以外的所有部分。
	LPBITMAPINFO m_lpBmpInfo;//位图信息指针
	LPRGBQUAD m_lpRgbQuad;//位图颜色表指针
	LPBYTE m_lpData;//位图数据指针
	HPALETTE m_hpalette;//调色板句柄
	BOOL m_bHasRgbQuad;//颜色表判断
	BOOL m_bVaild;//位图有效性判断
};

读取与显示图片只需要实现以下方法即可:
BOOL LoadFromFile(LPCTSTR path);//从文件加载图片
BOOL SaveToFile(LPCTSTR path);//保存图片到文件
LONG GetWidth();//获取图片宽度
LONG GetHeight();//获取图像高度
DWORD GetNumOfColor();//获取位图颜色数
LPRGBQUAD GetRgbQuad();//获取图片颜色表
BOOL Draw(CDC* pDC, CRect rect);//显示图片

2.图片的读取

从路径中读取图片

BOOL CDib::LoadFromFile(LPCTSTR lpszPath)
{
	strcpy(m_fileName, lpszPath);//文件名记录
	//LPCTSTR(m_fileName);//强制转换,为了迎合下面的.open方法
	CFile dibFile;//实例化一个DC
	//以只读模式打开文件
	if (!dibFile.Open(m_fileName, CFile::modeRead | CFile::shareDenyWrite))
	{
		return FALSE;
	}
	
	//为位图头文件分配空间
	m_lpBmpFileHeader = (LPBITMAPFILEHEADER)new BYTE[sizeof(BITMAPFILEHEADER)];//分配bmp头文件大小的数组,BYTE是控制头文件最小单位是8bit
	memset(m_lpBmpFileHeader, 0, sizeof(BITMAPFILEHEADER));//初始化为0
	//读取文件头
	int nCount = dibFile.Read((void*)m_lpBmpFileHeader, sizeof(BITMAPFILEHEADER));//强制转换为 void*
	if (nCount != sizeof(BITMAPFILEHEADER)) return FALSE;
	if (m_lpBmpFileHeader->bfType == 0x4d42)//判断是否位图,0x4d42代表BMP格式
	{
		//若是位图文件,计算除了位图文件头的空间大小,分配空间并初始化为0
		DWORD dwDibSize = dibFile.GetLength() - sizeof(BITMAPFILEHEADER);//除了bmfh的大小
		m_lpDib = new BYTE[dwDibSize];
		memset(m_lpDib, 0, dwDibSize);//初始化位图数据除了bmfh的部分
		dibFile.Read(m_lpDib, dwDibSize);//读取除了bmfh的所有部分
		dibFile.Close();//关闭位图文件
		m_lpBmpInfo = (LPBITMAPINFO)m_lpDib;//设置位图信息指针
		m_lpBmpInfoHeader = (LPBITMAPINFOHEADER)m_lpDib;//设置位图信息头指针

		m_lpRgbQuad = (LPRGBQUAD)(m_lpDib + m_lpBmpInfoHeader->biSize);//	颜色表指针
		if (m_lpBmpInfoHeader->biClrUsed == 0)//当没有设置使用的颜色数时使用
		{
			m_lpBmpInfoHeader->biClrUsed = GetNumOfColor();
		}
		DWORD dwRgbQuadLength = CalcRgbQuadLength();//计算颜色表长度

		m_lpData = m_lpDib + m_lpBmpInfoHeader->biSize + dwRgbQuadLength;//数据指针,指向图片数据头

		if (m_lpRgbQuad == ((LPRGBQUAD)m_lpData))//如果不存在颜色表
		{
			m_lpRgbQuad = nullptr;//置空指针
			m_bHasRgbQuad = FALSE;//无颜色表
		}
		else
		{
			m_bHasRgbQuad = TRUE;
			//生成调色板略
		}
		//设置颜色表略
		m_lpBmpInfoHeader->biSizeImage = GetSize();//设置位图大小
		m_bVaild = TRUE;
		return TRUE;
	}
	else
 {
		m_bVaild = FALSE;
		return FALSE;
	}
	
}

位图颜色数获取

DWORD CDib::GetNumOfColor()//获取位图颜色数,DWORD表示颜色数
{
	UINT dwNumOfColor;//颜色数量
	if ((m_lpBmpInfoHeader->biClrUsed == 0) && (m_lpBmpInfoHeader->biBitCount < 9))//不超过256的图片biClrUsed都为0
	{                                                                                           //biClrUsed 是指使用的颜色数量,256以下的都没颜色
		switch (m_lpBmpInfoHeader->biBitCount)
		{
		case 1: dwNumOfColor = 2; break;//2位位图
		case 4: dwNumOfColor = 16; break;//4位位图
		case 8: dwNumOfColor = 256; //8位灰度图
		}
	}
	else
	{
		dwNumOfColor = m_lpBmpInfoHeader->biClrUsed;
	}
	return dwNumOfColor;
}

计算颜色表长度

DWORD CDib::CalcRgbQuadLength()//计算位图颜色表长度
{
	DWORD dwNumOfColor = GetNumOfColor();
	if (dwNumOfColor > 256)
	{
		dwNumOfColor = 0;//24位真彩色图无调色板
	}
		return dwNumOfColor * sizeof(RGBQUAD);
}

获取位图尺寸与大小

LONG CDib::GetWidth()
{
	return m_lpBmpInfoHeader->biWidth;
}

LONG CDib::GetHeight()
{
	return m_lpBmpInfoHeader->biHeight;
}

DWORD CDib::GetSize()//获取位图大小
{
	if (m_lpBmpInfoHeader->biSizeImage != 0)
	{
		return m_lpBmpInfoHeader->biSizeImage;
	}
	else
	{
		return GetWidth() * GetHeight();
	}
}

3.图片的显示

BOOL CDib::Draw(CDC* pDC, CRect rect )
{
	if (!IsVaild()) return FALSE; // 位图无效
	HPALETTE hOldPalette = NULL;//旧的调色板句柄
	if (m_lpDib == NULL) return FALSE;//判断是否有数据
	if (m_hpalette != NULL)//如果有调色板,则选进设备环境里
	{
		hOldPalette = SelectPalette(pDC->GetSafeHdc(), m_hpalette, TRUE);
	}
	pDC->SetStretchBltMode(COLORONCOLOR);//设置位图伸缩模式
	将位图在设备上显示//
	StretchDIBits(pDC->GetSafeHdc(), rect.left, rect.top, rect.right-rect.left, 
		rect.bottom-rect.top, 0, 0, GetWidth(), GetHeight(), m_lpData, m_lpBmpInfo,
		DIB_RGB_COLORS, SRCCOPY);

	if (hOldPalette != nullptr)
	{
		SelectPalette(pDC->GetSafeHdc(), hOldPalette, TRUE);//恢复旧的调色板
	}
	return TRUE;
}

最后是一些判断语句

BOOL CDib::IsVaild()
{
	return m_bVaild;
}

BOOL CDib::HasRgbQuad()
{
	return m_bHasRgbQuad;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值