BMP格式图片的读取与显示(MFC)
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;
}