MFC图像处理-DIB位图之CDib类
2013-07-03 09:41
225 查看
位图处理是图像处理中很重要的一个知识点,本章是编写一个基本的DIB位图信息处理的类CDib类,在此之前必须了解DIB位图的文件结构,建议大家先找资料学一下。
首先在你要编写CDib类的工程的ClassView中右击工程名称,然后点击New Class,记住,我用的是MFC
AppWizard项目。
然后在弹出的New Class对话框中的Class type下拉列表中选中Generic Class,在Name中输入该类的名称,我这里是CDib。在Base
class中Derived From中输入CObject,As保持public,点击OK就成功在你的工程中添加了CDib类了。
创建好新类后我们就可以开始编写了。
首先必须明确我们编写这个类要实现哪些基本的功能,下面是我写的类中包含的功能,如果有需要,可以从这个CDib类中派生其他类以实现其他功能:
在这个类中我加入了以下成员变量:
然后就是方法的实现部分:
首先在你要编写CDib类的工程的ClassView中右击工程名称,然后点击New Class,记住,我用的是MFC
AppWizard项目。
然后在弹出的New Class对话框中的Class type下拉列表中选中Generic Class,在Name中输入该类的名称,我这里是CDib。在Base
class中Derived From中输入CObject,As保持public,点击OK就成功在你的工程中添加了CDib类了。
创建好新类后我们就可以开始编写了。
首先必须明确我们编写这个类要实现哪些基本的功能,下面是我写的类中包含的功能,如果有需要,可以从这个CDib类中派生其他类以实现其他功能:
void LoadFile(const TCHAR * dibFileName); // 载入BMP位图文件 BOOL SaveFile(const TCHAR * pszFileName); // 保存BMP位图文件 TCHAR * GetFileName(); // 获取BMP位图文件名 DWORD GetSize(); // 获取位图文件的大小 UINT GetWidth(); // 获取位图宽度像素数 UINT GetHeight(); // 获取位图高度像素数 UINT GetNumberOfColors(); // 获取位图颜色数目 RGBQUAD * GetRGB(); // 获取颜色表指针 DIBINFO * GetDibInfo(); // 获取位图信息结构的指针 BYTE * GetDibData(); // 获取位图数据指针 BOOL IsValid(); // 判断是否载入了位图文件,对象是否可用 DWORD GetDibWidthBytes(); // 获取位图的宽度字节数 DWORD PaletteSize(LPBYTE lpDib); // 获取位图指针指向的位图的调色板的字节大小 WORD DibNumberColors(LPBYTE lpDib); // 获取位图指针指向的位图的颜色数目
在这个类中我加入了以下成员变量:
RGBQUAD * m_pRGB; // 位图颜色表指针 BYTE * m_pData; // 位图数据指针 UINT m_numberOfColors; // 位图颜色数目 BOOL m_bValid; // 记录是否载入了位图文件 DIBFILEHEADER m_dibFileHeader; // 位图文件头 DIBINFOHEADER * m_pDibInfoHeader; // 位图信息头指针 DIBINFO * m_pDibInfo; // 位图信息指针 UINT m_byBitCount; DWORD m_dwWidthBytes; BYTE * m_pDib; // 文件中位图总数据指针 DWORD m_dwDib; // 位图总数据的长度 TCHAR m_fileName[256]; // 记录文件名称
然后就是方法的实现部分:
CDib::CDib() { m_pDibInfo = NULL; m_pDibInfoHeader = NULL; m_pData = NULL; m_pDib = NULL; m_pRGB = NULL; } CDib::~CDib() { if(m_pDibInfo != NULL) GlobalFreePtr(m_pDibInfo); // 释放在LoadFile中分配给m_pDib的内存资源 } void CDib::LoadFile(const TCHAR * dibFileName) { // 判断是否传入文件名字符串,否则直接跳出函数 if(dibFileName == NULL) return; if(m_bValid) { GlobalFreePtr(m_pDibInfo); m_pDibInfo = NULL; m_pDibInfoHeader = NULL; m_pData = NULL; m_pDib = NULL; m_pRGB = NULL; } _tcscpy(m_fileName, dibFileName); // 复制文件名字符串 CFile dibFile(m_fileName, CFile::modeRead); // 只读打开文件 dibFile.Read((void *) &m_dibFileHeader, sizeof(DIBFILEHEADER)); // 读取文件信息头数据 // 判断文件是否为位图文件 if(m_dibFileHeader.bfType == 0x4d42) { m_bValid = TRUE; DWORD fileLength = dibFile.GetLength(); // 获取文件数据总长度 m_dwDib = fileLength - sizeof(DIBFILEHEADER); // 计算位图文件位图总数据长度 BYTE * m_pDib = (BYTE *) GlobalAllocPtr(GMEM_MOVEABLE, m_dwDib); // 分配相应的内存资源 dibFile.Read((void *) m_pDib, m_dwDib); // 读取文件中位图总数据 dibFile.Close(); // 关闭位图文件 m_pDibInfo = (DIBINFO *) m_pDib; // 指向位图信息,位图信息包括信息头和颜色表 m_pDibInfoHeader = (DIBINFOHEADER *) m_pDib; // 指向位图信息头 m_pRGB = (RGBQUAD *)(m_pDib + m_pDibInfoHeader->biSize); // 指向位图颜色表,指针沿数据向后移动m_pDibInfoHeader->biSize个字节 int m_numberOfColors = GetNumberOfColors(); // 获取颜色数目 if(m_pDibInfoHeader->biClrUsed == 0) m_pDibInfoHeader->biClrUsed = m_numberOfColors; // 如果信息头没有记录使用的颜色数目,重新设置 DWORD colorTableSize = m_numberOfColors * sizeof(RGBQUAD); // 计算颜色表大小 if(colorTableSize == 0) // 没有颜色表 m_pRGB = NULL; m_pData = m_pDib + m_pDibInfoHeader->biSize + colorTableSize; // 指向位图数据 m_pDibInfoHeader->biSizeImage = GetSize(); // 在信息头中设置文件大小值 } else {// 打开的文件不是位图文件 m_bValid = FALSE; AfxMessageBox("这不是一个位图文件!"); } } BOOL CDib::IsValid() {// 判断是否打开了文件 return m_bValid; } TCHAR * CDib::GetFileName() {// 文件已打开就可以获取文件名 if(IsValid()) return m_fileName; return NULL; } UINT CDib::GetWidth() {// 如果信息头不为NULL,可以获取位图宽度像素数 if(m_pDibInfoHeader != NULL) return (UINT) m_pDibInfoHeader->biWidth; return NULL; } UINT CDib::GetHeight() {// 如果信息头不为NULL,可以获取位图高度像素数 if(m_pDibInfoHeader != NULL) return (UINT) m_pDibInfoHeader->biHeight; return NULL; } DWORD CDib::GetSize() { if(IsValid()) // 位图文件没有打开,返回0 return 0; else if(m_pDibInfoHeader->biSizeImage != 0) {// 位图文件打开了,并且信息头的位图数据大小不为0就直接返回biSizeImage return m_pDibInfoHeader->biSizeImage; } else {// 文件已打开,但是信息头记录的位图大小为0,重新计算并返回位图数据大小 DWORD height = (DWORD)GetHeight(); DWORD width = (DWORD)GetWidth(); return height * width; } } DWORD CDib::GetDibWidthBytes() {// 返回位图的宽度字节数 if(!m_bValid) return 0; // 位图对象无效直接返回0 // 获取位图像素位数和位图宽度像素数 m_byBitCount = m_pDibInfoHeader->biBitCount; LONG nWidth = m_pDibInfoHeader->biWidth; m_dwWidthBytes = (DWORD)m_pDibInfoHeader->biWidth; // 如果位图的每个像素的位数是8,那么位图的字节数等于像素数 if(m_byBitCount == 1) m_dwWidthBytes = (nWidth + 7) / 8; // 如果位图的每个像素的位数是1,那么一个字节包含8个像素 else if(m_byBitCount == 4) m_dwWidthBytes = (nWidth + 1) / 2; // 如果位图的每个像素的位数是4,那么一个字节包含2个像素 else if(m_byBitCount == 24) m_dwWidthBytes = 3 * nWidth; // 如果位图的每个像素的位数是24,那么3个字节为一个像素 while((m_dwWidthBytes & 3) != 0) m_dwWidthBytes++; // 位图的宽度字节数总是4的倍数 return m_dwWidthBytes; } UINT CDib::GetNumberOfColors() { if(!m_bValid) return 0; // 位图对象无效直接返回0 int numberOfColors; if((m_pDibInfoHeader->biClrUsed == 0) && (m_pDibInfoHeader->biBitCount < 9)) {// 位图信息头的颜色数目为零,并且颜色位数小于9, // 从颜色位数判断颜色数目 switch(m_pDibInfoHeader->biBitCount) { case 1: numberOfColors = 2; break; case 4: numberOfColors = 16; break; case 8: numberOfColors = 256; } } else {// 位图信息头的颜色数目不为零,直接获取颜色数目 numberOfColors = (int)m_pDibInfoHeader->biClrUsed; } return numberOfColors; } BYTE * CDib::GetDibData() {// 返回位图数据 return m_pData; } RGBQUAD * CDib::GetRGB() {// 返回位图颜色表 return m_pRGB; } DIBINFO * CDib::GetDibInfo() {// 返回位图信息 return m_pDibInfo; } BOOL CDib::SaveFile(const TCHAR *pszFileName) { if(pszFileName == NULL) return FALSE; // 如果文件名为空,直接返回FALSE DIBFILEHEADER dibFileHeader; // 位图文件头 LPDIBINFOHEADER lpDibInfoHeader; // 位图信息头指针 DWORD dwDibSize; // 位图数据大小 dibFileHeader.bfType = 0x4d42; // 0x4d42编码指定文件是位图格式 lpDibInfoHeader = (LPDIBINFOHEADER) m_pDibInfoHeader; // 取得位图信息头指针 dwDibSize = *(LPWORD) lpDibInfoHeader + PaletteSize((LPBYTE) lpDibInfoHeader); // 计算位图信息头数据的大小 if((lpDibInfoHeader->biCompression == BI_RLE8) || (lpDibInfoHeader->biCompression == BI_RLE4)) {// 若位图是经过RLE压缩的,直接加上biSizeImage储存的位图空间量 dwDibSize += lpDibInfoHeader->biSizeImage; } else {// 若位图不是经过RLE压缩的,通过算法(biWidth*biBitCount+31) / 32 * 4 * biHeight算出biSizeImage的值 DWORD dwDibBitsSize; dwDibBitsSize = WIDTHBYTES((lpDibInfoHeader->biWidth) * ((DWORD) lpDibInfoHeader->biBitCount)) * lpDibInfoHeader->biHeight; dwDibSize += dwDibBitsSize; } dibFileHeader.bfSize = dwDibSize + sizeof(DIBFILEHEADER); // 加上文件头大小就为位图文件的大小 dibFileHeader.bfReserved1 = 0; dibFileHeader.bfReserved2 = 0; dibFileHeader.bfOffBits = (DWORD)sizeof(DIBFILEHEADER) + // 计算位图数据距文件头的偏移量 lpDibInfoHeader->biSize + PaletteSize((LPBYTE) lpDibInfoHeader); // 创建新位图文件,并写入位图文件信息和数据 CFile dibFile(pszFileName, CFile::modeWrite | CFile::modeCreate); dibFile.Write(&dibFileHeader, sizeof(DIBFILEHEADER)); dibFile.WriteHuge(lpDibInfoHeader, dwDibSize); dibFile.Close(); return TRUE; } DWORD CDib::PaletteSize(LPBYTE lpDib) {// 如果位图指针有效,返回位图调色板的字节大小, // 否则返回0 if(lpDib != NULL) return (DibNumberColors(lpDib) * sizeof(COLORREF)); // 这里书中是用sizeof(RGBTRIPLE),但是好像用sizeof(COLORREF)才是准确的,何解??? return 0; } WORD CDib::DibNumberColors(LPBYTE lpDib) {// 如果位图指针有效,返回根据bcBitCount的值返回位图的颜色数目 if(lpDib == NULL) return 0; WORD wBitCount; wBitCount = ((LPDIBINFOHEADER)lpDib)->biBitCount; // 书中这里是用LPBITMAPCOREHEADER指针,但经过我的验证,好像不行,原本lpDib传进来的就是LPBITMAPINFOHEADER指针,直接用LPBITMAPINFOHEADER不是更准确吗? switch(wBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; } }
相关文章推荐
- MFC数字图像处理24位图转8位图 等四种图像色彩转换方式
- MFC基础知识(三)——用DIB位图显示图像
- mfc 图像处理 图像缩小
- IOS中图形图像处理第一部分:位图图像原图修改
- HalconMFC(三)之打开图像_简单处理
- 利用MFC的Picture控件显示和处理图像
- 基于MFC和OpenCV的图像处理小软件
- 使用OpenCV和MFC做图像处理(自己的毕设论文,现公布出来)
- 基于mfc数字图像处理的小软件pdd-改变图片的大小
- MFC—PictureControl控件使用,显示和处理图像
- 利用MFC的Picture控件显示和处理图像
- 位图(图像处理入门)
- 基于MFC和OpenCV的图像处理小软件(续)
- 位图图像处理控件ImageCapture Suite更新至v9.1
- IOS中图形图像处理第一部分:位图图像原图修改
- 【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
- 关于MFC中OpenCV图像处理使用cvFindContours引起的中断错误
- VC6使用GDI+进行图像的特效处理和MFC学习笔记-1
- iOS中图形图像处理第一部分:位图图像原图修改
- Opencv (Opencv2)结合MFC学习数字图像处理【1】---建立工程