第二章 BMP位图类的创建与MFC单文档视图类的显示_mfc单文档视图分割
第二章 BMP位图类的创建与MFC单文档视图类的显示由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“mfc单文档视图分割”。
BMP位图文件的4个组成部分
bmp文件大体上分成四个部分。
位图文件头BITMAPFILEHEADER、位图信息头BITMAPINFOHEADER、调色板Palette、实际的位图数据ImageDate 第1部分为位图文件头BITMAPFILEHEADER,是一个结构体类型,该结构的长度是固定的,为14个字节。其定义如下: typedef struct tagBITMAPFILEHEADER { WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;1.文件头信息块
0000-0001 :文件标识,为字母ASCII码“BM”。0002-0005 :文件大小。
0006-0009 :保留,每字节以“00”填写。
000A-000D :记录图像数据区的起始位置。各字节的信息含义依次为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)。
第2部分为位图信息头BITMAPINFOHEADER,也是一个结构体类型的数据结构,该结构的长度也是固定的,为40个字节(WORD为无符号16位整数,DWORD为无符号32位整数,LONG为32位整数)。其定义如下: typedef struct tagBITMAPINFOHEADER { DWORD biSize;图像描述信息块的大小,常为28H。
LONG biWidth;
LONG biHeight;
WORD biPlanes;=1
WORD biBitCount;记录像素的位数
DWORD biCompreion;数据压缩方式
DWORD biSizeImage;图像区数据的大小
LONG biXPelsPerMeter;指定目标设备的水平分辨率,单位是像素/米
LONG biYPelsPerMeter;
DWORD biClrUsed;位图实际用到的颜色数
DWORD biClrImportant;位图显示过程中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;2.图像描述信息块
000E-0011:图像描述信息块的大小,常为28H。0012-0015:图像宽度。0016-0019:图像高度。
001A-001B:图像的plane总数(恒为1)。
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。第3部分为颜色表。颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如果该值为零,则由biBitCount指定,即2的biBitCount次幂个元素)。RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:
typedef struct tagRGBQUAD { BYTE rgbBlue;BYTE rgbGreen;BYTE rgbRed;BYTE rgbReserved;}RGBQUAD;3.颜色表
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号0的颜色,接下来表示颜色号1的颜色,依此类推。
第4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。对于有颜色表的位图,位图数据就是该像素颜色在调色板中的索引值;对于真彩色图,位图数据就是实际的R、G、B值(三个分量的存储顺序是B、G、R)。下面分别就2色、16色、256色和真彩色位图的位图数据进行说明:
— 对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。
— 对于16色位图,用4位可以表示一个像素的颜色。所以一个字节可以存储2个像素的颜色值。
— 对于256色位图,1个字节刚好存储1个像素的颜色值。— 对于真彩色位图,3个字节才能表示1个像素的颜色值。需要注意两点:
第一,Windows规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:
DataSizePerLine =(biWidth * biBitCount /8+ 3)/ 4*4 那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:
biSizeImage = DataSizePerLine * biHeight 第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。
CDIB类的建立
cla CDib { public:
LPRGBQUAD
m_lpRgbQuad;//颜色表指针
LPBYTE
m_lpData;//位图数据指针
UINT
m_numberOfColors;//颜色数
BOOL
m_bValid;//位图是否有效 BOOL
m_bHasRgbQuad;//是否有颜色表 HPALETTE
m_hPalette;
//调色板句柄
LPBITMAPFILEHEADER m_lpBmpFileHeader;//位图文件头指针
LPBITMAPINFOHEADER m_lpBmpInfoHeader;//位图信息头指针
LPBITMAPINFO
m_lpBmpInfo;//位图信息指针 LPBYTE
m_lpDib;//位图指针,包含除位图文件头的所有内容、需要动态分配和释放 DWORD size;public:
char m_fileName[256];
LPCTSTR GetFileName();
BOOL LoadFile(LPCTSTR dibFileName);BOOL SaveFile(LPCTSTR filename);//LPCTSTR GetFileName();
LONG GetWidth();
LONG GetHeight();
DWORD GetSize();//获取位图大小
WORD GetBitCount();//获取单个像素所占的位数
UINT GetLineByte();//获取每行像素所占字节数
UINT GetNumOfColor();//获取位图颜色数
LPRGBQUAD GetRgbQuad();//获取位图颜色表
LPBYTE
GetData();
//获取位图数据 BOOL Draw(CDC* pDC,BYTE *,CPoint origin,CSize size);//显示位图 BOOL HasRgbQuad();//判断是否有颜色表?
BITMAPINFO* GetInfo();
BOOL IsGrade();//判断是否为灰度图像 WORD PaletteSize(LPBYTE lpDIB);WORD DIBNumColors(LPBYTE lpDIB);
BOOL IsValid();//判断位图是否有效? protected:
DWORD CalcRgbQuadLength();//计算位图颜色表的长度 BOOL MakePalette();//根据颜色表生成调色板 void Empty(BOOL bFlag=TRUE);//清理空间
public: CDib(void);~CDib(void);
};
主要成员函数:
////////////////////////////////////////////////////////// //函数功能:从文件加载位图
//输入参数:LPCTSTR dibFileName表示待加载位图文件路径 //返回值:加载是否成功
///////////////////////////////////////////////////////////
BOOL CDib::LoadFile(LPCTSTR dibFileName){
strcpy(m_fileName,dibFileName);//记录位图文件名 CFile dibFile;//选择读模式定义文件对象
if(!dibFile.Open((LPCTSTR)m_fileName, CFile::modeRead|CFile::shareDenyWrite)){ } //Empty(FALSE);//为位图文件头指针分配空间,并初始化为 return FALSE;m_lpBmpFileHeader=(LPBITMAPFILEHEADER)new BYTE[sizeof(BITMAPFILEHEADER)];
memset(m_lpBmpFileHeader,0,sizeof(BITMAPFILEHEADER));//读取位图文件头
int nCount= dibFile.Read(m_lpBmpFileHeader,sizeof(BITMAPFILEHEADER));//读bmp文件头信息到指针m_lpBmpfileHeader if(nCount!=sizeof(BITMAPFILEHEADER))return FALSE;if(m_lpBmpFileHeader->bfType == 0x4d42)//判断是否是bmp文件
{ DWORD fileLength = dibFile.GetLength();//获取文件长度信息 size = fileLength-sizeof(BITMAPFILEHEADER);//文件数据区大小=文件长度-文件头大小
m_lpDib=new BYTE[size];memset(m_lpDib,0,size);dibFile.Read((void*)m_lpDib, size);//读除bmp文件头外的所有数据到指
dibFile.Close();//关闭文件
m_lpBmpInfo =(LPBITMAPINFO)m_lpDib;//获取bmp文件的信息 m_lpBmpInfoHeader =(LPBITMAPINFOHEADER)m_lpDib;//获取文件信息头地址 针m_lpDib m_lpRgbQuad =(LPRGBQUAD)(m_lpDib +m_lpBmpInfoHeader->biSize);
//颜色表地址=pDib +m_lpBmpInfoHeader->biSize;
int m_numberOfColors =GetNumOfColor();//颜色数 if(m_lpBmpInfoHeader->biClrUsed == 0)// m_lpBmpInfoHeader->biClrUsed =m_numberOfColors;//颜色表的大小CalcRgbQuadLength(){return m_numberOfColors *sizeof(RGBQUAD)} DWORD colorTableSize =CalcRgbQuadLength();//位图数据区地址
m_lpData =m_lpDib + m_lpBmpInfoHeader->biSize+ colorTableSize;
if(m_lpRgbQuad ==(LPRGBQUAD)m_lpData)// No color table m_lpRgbQuad = NULL;
}
m_lpBmpInfoHeader->biSizeImage = GetSize();m_bValid = TRUE;return TRUE;}
else {
} m_bValid = FALSE;AfxMeageBox(“This isn't a bitmap file!”);return FALSE;///////////////////////////////////////////////// //将位图保存到文件
//LPCTSTR filename表示位图文件保存路径文件名 //返回值,TRUE-表示成功
///////////////////////////////////////////////// BOOL CDib::SaveFile(LPCTSTR filename){
CFile dibFile;//以写模式打开文件
if(!dibFile.Open((LPCTSTR)filename, CFile::modeCreate|CFile::modeWrite|CFile::shareExclusive)){ } return FALSE;strcpy(m_fileName,filename);dibFile.Write(m_lpBmpFileHeader,sizeof(BITMAPFILEHEADER));//将位图文件头结构写进文件
dibFile.Write(m_lpBmpInfoHeader,sizeof(BITMAPINFOHEADER));//将位图信息头结构写进文件
DWORD dwRgbQuandLength=CalcRgbQuadLength();//计算颜色表长度
if(dwRgbQuandLength!=0)dibFile.Write(m_lpRgbQuad,dwRgbQuandLength);//若存在颜色表,则将颜色表写进位图文件
} DWORD dwDataSize=GetLineByte()*GetHeight();dibFile.Write(m_lpData,dwDataSize);//将位图数据写进位图文件 dibFile.Close();//关闭文件 return TRUE;
////////////////////////////////////////// //根据颜色表生成调色板
/////////////////////////////////////////// BOOL CDib::MakePalette(){ DWORD dwRgbQuadLength=CalcRgbQuadLength();if(dwRgbQuadLength==0)return FALSE;//为表示图像为真彩色图像,没有调色板 if(m_hPalette!=NULL)//删除旧的调色板对象
{
} //申请缓冲器,初始化为 DeleteObject(m_hPalette);m_hPalette=NULL;/*调色板编程见到这样两个结构: typedef struct tagPALETTEENTRY {
BYTE peRed;
BYTE peGreen;
BYTE peBlue;
BYTE peFlags;} PALETTEENTRY;
typedef struct tagLOGPALETTE {
WORD
palVersion;
WORD
palNumEntries;
PALETTEENTRY palPalEntry[1];// } LOGPALETTE;*/ DWORD dwNumOfColor=GetNumOfColor();DWORD dwSize= 2*sizeof(WORD)+dwNumOfColor*sizeof(PALETTEENTRY);LPLOGPALETTE lpLongPalette=(LPLOGPALETTE)new
BYTE[dwSize];
memset(lpLongPalette,0,dwSize);//生成逻辑调色板
lpLongPalette->palVersion=0x300;lpLongPalette->palNumEntries=dwNumOfColor;LPRGBQUAD lpRgbQuad =(LPRGBQUAD)m_lpRgbQuad;// m_lpRgbQuad位图文件颜色表地址
} for(int i=0;i
} m_hPalette=CreatePalette(lpLongPalette);//创建逻辑调色板 delete []lpLongPalette;return TRUE;lpLongPalette->palPalEntry[i].peRed=lpRgbQuad->rgbRed;lpLongPalette->palPalEntry[i].peGreen=lpRgbQuad->rgbGreen;lpLongPalette->palPalEntry[i].peBlue=lpRgbQuad->rgbBlue;lpLongPalette->palPalEntry[i].peFlags=0;lpRgbQuad++;LPCTSTR CDib::GetFileName(){ }
LONG CDib::GetWidth(){ } return m_lpBmpInfoHeader->biWidth;return m_fileName;
LONG CDib::GetHeight(){ }
DWORD CDib::GetSize(){
}
WORD CDib::GetBitCount(){ } return m_lpBmpInfoHeader->biBitCount;if(m_lpBmpInfoHeader->biSizeImage!=0){ } else { return GetWidth()*GetHeight();return m_lpBmpInfoHeader->biSizeImage;return m_lpBmpInfoHeader->biHeight;}
UINT CDib::GetLineByte(){ } /////////////////////////////////////////////// //获取图像使用的颜色数
////////////////////////////////////////////// UINT CDib::GetNumOfColor(){ UINT dwNumOfColor;//m_lpBmpInfoHeader->biClrUsed图像中使用的颜色数,m_lpBmpInfoHeader->biBitCount像素位数,,if((m_lpBmpInfoHeader->biClrUsed==0)&&(m_lpBmpInfoHeader->biBitCount
switch(m_lpBmpInfoHeader->biBitCount)
{
case 1:dwNumOfColor=2;break;
case 4:dwNumOfColor=16;break;
case 8:dwNumOfColor=256;
} } else
dwNumOfColor=m_lpBmpInfoHeader->biClrUsed;return dwNumOfColor;}
DWORD CDib::CalcRgbQuadLength(){ DWORD dwNumOfColor=GetNumOfColor();if(dwNumOfColor>256){
dwNumOfColor=0;} return dwNumOfColor*sizeof(RGBQUAD);} //////////////////////////////////////// //获取颜色表 return(GetWidth()*GetBitCount()/8+3)/4*4;//返回颜色表指针
/////////////////////////////////////// LPRGBQUAD CDib::GetRgbQuad(){ return m_lpRgbQuad;} ////////////////////////////////////// //获取位图数据区指针
//////////////////////////////////// LPBYTE CDib::GetData(){ return m_lpData;}
/////////////////////////////////////////////////////////// //函数功能:显示位图
//CDC *pDC表示设备环境指针
//CPoint origin 表示显示矩形区域的左上角 //CSize size表示显示矩形区域的大小
//////////////////////////////////////////////////////////// BOOL CDib::Draw(CDC* pDC,BYTE * lpData,CPoint origin,CSize size){
if(!IsValid())return FALSE;if(m_lpDib==NULL)return FALSE;HPALETTE hOldPalette=NULL;if(m_hPalette!=NULL)//如果位图有调色板则选进设备环境中 hOldPalette=SelectPalette(pDC->GetSafeHdc(),m_hPalette,TRUE);pDC->SetStretchBltMode(COLORONCOLOR);//设置位图伸缩模式 //将位图在pDC所指向的设备上进行显示
StretchDIBits(pDC->GetSafeHdc(),origin.x,origin.y,size.cx,size.cy,0,0,GetWidth(),GetHeight(),lpData,m_lpBmpInfo,DIB_RGB_COLORS,SRCCOPY);if(hOldPalette!=NULL)SelectPalette(pDC->GetSafeHdc(),hOldPalette,TRUE);//恢复旧的调试板
} BOOL CDib::HasRgbQuad(){ } BOOL CDib::IsValid(){ } BOOL CDib::IsGrade(){ } void
CDib::Empty(BOOL bFlag)//清理空间 { if(bFlag)strcpy(m_fileName,“”);return(GetBitCount()0);return m_bValid;return m_bHasRgbQuad;return TRUE;
} if(m_lpBmpFileHeader!=NULL){
} if(m_lpDib!=NULL){
} if(m_hPalette!=NULL){
} m_bHasRgbQuad=FALSE;m_bValid=FALSE;DeleteObject(m_hPalette);m_hPalette=NULL;delete[] m_lpDib;m_lpDib=NULL;m_lpBmpInfo=NULL;m_lpBmpInfoHeader=NULL;m_lpRgbQuad=NULL;m_lpData=NULL;delete[] m_lpBmpFileHeader;m_lpBmpFileHeader=NULL;
MFC单文档中图像的显示与操作
一、创建MFC单文档工程:DIPAX
二、在DIPAX工程添加CDib类的定义及其实现。
三、在DIPAX工程MFC单文档中创建两个视图类,左右分开
1、首先创建类:
cla CDynSplitterWnd :public CSplitterWnd { public: CDynSplitterWnd(void);~CDynSplitterWnd(void);};在CMainFrame中包含上述类的头文件,重写CMainFrame类的方法virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
2、在重写类之前,创建新的视图类
cla CDynSplitView : public CView //第一个视图类:CdipaxView
以及在CMainFrame里创建上述窗口分割类的对象CDynSplitterWnd m_wndSplitter;
3、现在可以重写上述OnCreateClient()方法了:{
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)// TODO: 在此添加专用代码和/或调用基类 if(!m_wndSplitter.CreateStatic(this, 1, 2)){ TRACE0(“Failed to Splitter windown”);return FALSE;} // add the first splitter panean input view in column 1 if(!m_wndSplitter.CreateView(0, 1,RUNTIME_CLASS(CDynSplitView), CSize(0, 0), pContext)){ TRACE0(“Failed to create second panen”);return FALSE;} // activate the input view SetActiveView((CView*)m_wndSplitter.GetPane(0,1));return TRUE;//return CFrameWnd::OnCreateClient(lpcs, pContext);
4、运行效果
四、在视图类CdipaxView中显示位图 1.在CdipaxDoc文档类中添加:
(1)添加头文件 #include “DIB.h”(2)添加成员变量: CDib Cdib;CString filename;int statedoc;(3)添加OnFileOpen()事件函数: OnFileOpen()void CdipaxDoc::OnFileOpen(){ // TODO: 在此添加命令处理程序代码
CFileDialog dlg(TRUE,_T(“BMP”),_T(“*.BMP”),OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,_T(“位图文件(*.BMP)|*.BMP|”));
if(IDOK==dlg.DoModal())
filename.Format(“%s”,dlg.GetPathName());
Cdib.LoadFile(filename);
statedoc=1;}(4)在构造函数中添加: CdipaxDoc::CdipaxDoc(){ // TODO: 在此添加一次性构造代码
statedoc=0;}
2、在CdipaxView视图类中添加:
(1)在CdipaxView.h中添加成员变量
public: CString filename;int state1;(2)在构造函数中添加: CdipaxView::CdipaxView(){ // TODO: 在此处添加构造代码 state1=0;}(3)改写菜单项:
(4)改写工具栏:
(5)在CdipaxView中为菜单ID_ORIGINIMAGE添加事件处理程序: void CdipaxView::OnOriginimage(){ // TODO: 在此添加命令处理程序代码
CdipaxDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);filename=pDoc->filename;state1=1;Invalidate();}
(6)重写OnDraw函数:
void CdipaxView::OnDraw(CDC* pDC){ CdipaxDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);
// TODO: 在此处为本机数据添加绘制代码
if(state1==1){
pDoc->Cdib.Draw(pDC,pDoc->Cdib.m_lpData,CPoint(0,0),CSize(pDoc->Cdib.GetWidth(),pDoc->Cdib.GetHeight()));
}
}(7)运行效果:
五、一个简单的二值化操作
1、在CDynSplitView中显示经过处理之后的图像(1)在CDynSplitView.h中添加 public: BYTE* image_out;//处理后图像数据区指针 BYTE* image_in;//处理前图像数据区指针
long m_imagex;//图像的宽度 long m_imagey;//图像的高度
int state2;//CDynSplitView视图类是否为当前视图 CPalette hPalette;public: void clearmem(void);//复制图像数据
(2)构造函数
CDynSplitView::CDynSplitView(){
image_out=NULL;
image_in=NULL;
state2=0;
m_imagex=0;
m_imagey=0;}(3)成员函数的实现
void CDynSplitView::clearmem(void){ CdipaxDoc* pDoc =(CdipaxDoc*)GetDocument();ASSERT_VALID(pDoc);pDoc->statedoc=0;state2=1;m_imagex=pDoc->Cdib.GetWidth();m_imagey=pDoc->Cdib.GetHeight();
long int size=m_imagex*m_imagey;if(pDoc->Cdib.GetBitCount()>8)
size=size*3;image_out=new BYTE[size];image_in=new BYTE[size];memcpy(image_in,pDoc->Cdib.m_lpData,size);//复制原图像到处理区 }(4)改写OnDraw()函数:
void CDynSplitView::OnDraw(CDC* pDC){ CdipaxDoc* pDoc = GetDocument();
} ASSERT_VALID(pDoc);if(!pDoc->statedoc&&state2==1){
pDoc->Cdib.Draw(pDC,image_out,CPoint(0,0),CSize(m_imagex,m_imagey));}
2、灰度图像的二值化处理操作
(1)添加图像操作菜单:ID_BINARIZATION,标题为二值化处理,并添加事件处理程序。
void CDynSplitView::OnBinarization(){ // TODO: 在此添加命令处理程序代码
clearmem();//复制图像数据
for(int i=0;i
for(int j=0;j
{
if(*(image_in+i*m_imagex+j)>128)
*(image_out+i*m_imagex+j)=255;
else
*(image_out+i*m_imagey+j)=0;
} } Invalidate();}
二值化处理:像素灰度值>128的为白色值255,否则为黑色值0。
MFC中类的作用(一)类的作用面向对象的的程序设计体现在类对数据和操作的封装,但是这只是模板,要想真正去使用里面的数据和操作,必须实例化类的一个对象,这样类内部的成员才会真......
刀豆文库小编为你整合推荐3篇跟单类英文简历,也许这些就是您需要的文章,但愿刀豆文库能带给您一些学习、工作上的帮助。......
第二章 蚊类防制规范一、实施灭蚊措施及防蚊措施(一) 蚊幼控制1、小型积水:妥善处理/清除缸、罐、盆、桶等各种废弃或闲置的容器,该项工作定期进行,及时处理。2、池、塘、河等大......
创建一个employee类,该类中有字符数组,表示姓名、街道地址、市、省和邮政编码。把表示构造函数、changname()、display()的函数的原型放在类定义中,构造函数初始化每个成员,disp......
东北财经大学网络教育 课程考试论文(案例)考核劳动法作者 XXX 考试批次 XXXXXX 学籍批次 XXXXXX 学习中心 XX学习中心 层次 XXXXXX 专业 XXXXXX 完成时间 XXXX年X月X日......
