Reading and displaying pictures in BMP format (MFC)

Reading and displaying pictures in BMP format (MFC)

Schematic diagram of BMP format

BMP format sketch (the above pointer will be used when reading the picture)

1. Construct the Dib class

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;//位图有效性判断
};

To read and display pictures, you only need to implement the following methods:
BOOL LoadFromFile(LPCTSTR path);//Load pictures from files
BOOL SaveToFile(LPCTSTR path);//Save pictures to files
LONG GetWidth();//Get picture width
LONG GetHeight();//Get image height
DWORD GetNumOfColor();//Get bitmap color number
LPRGBQUAD GetRgbQuad();//Get image color table
BOOL Draw(CDC* pDC, CRect rect);//Display image

2. Reading of pictures

read image from path

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;
	}
	
}

Bitmap color number acquisition

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;
}

Compute color table length

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

Get bitmap size and size

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. Display of pictures

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;
}

Finally, some judgment statements

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

BOOL CDib::HasRgbQuad()
{
    
    
	return m_bHasRgbQuad;
}

Guess you like

Origin blog.csdn.net/Dec1steee/article/details/127000098