这是一个基于对话框的mfc程序,程序名为moduleForProcess。(说出程序的名字,只是为将来叙述方便一些)
---------------------------------
首先,在moduleForProcessDlg.h 里面写上#define DIBFILETYPE ((WORD)('M'<<8)|'B'),然后,还要给CmoduleForProcessDlg类添加一些数据成员和函数成员。具体如下:
// moduleForProcessDlg.h : 头文件
//
#pragma once
//----------------------------------
//some define
//
#define DIBFILETYPE ((WORD)('M'<<8)|'B')
// CmoduleForProcessDlg 对话框
class CmoduleForProcessDlg : public CDialog
{
// 构造
public:
CmoduleForProcessDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_MODULEFORPROCESS_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedOpenorg();
//------------------------------------------------------------
//data member
//
public:
LPSTR m_lpDibbitsOrg;//the place of original bits
LPSTR m_lpDibbitsChg;//the place of changed bits
HANDLE m_hDIBOrg;//the HGLOBAL of the memory where the original bits put in
HANDLE m_hDIBChg;//the HGLOBAL of the memory where the changed bits put in
BITMAPINFOHEADER m_bmiHeader;
DWORD m_size;//the size of the data
int m_Width;//the width of the bitmap,to use it ,just handy
int m_Height;//the height of the bitmap,to use it ,just handy
DWORD m_bytePerLine;//the real numbers of bits in one line,just for handy
DWORD m_byteSpacePerLine;//the non use number of bits in one line,just for handy
//----------------------------------------------------------
//function member
void ShowOrgImg(void);//show the original image
void ShowChgImg(void);//show the image which has changed
//下面的函数是用向导自动生成的
afx_msg void OnBnClickedSavechg();
afx_msg void OnBnClickedShowchaned();
afx_msg void OnBnClickedProcess();
};
----------------------------------------------------------------------
现在是在moduleForProcessDlg.cpp 中,下面只把改动了的地方标示出来
//记住成员函数,特别是涉及到指针的时候一定要初始化的,否则会有很大的问题
CmoduleForProcessDlg::CmoduleForProcessDlg(CWnd* pParent /*=NULL*/)
: CDialog(CmoduleForProcessDlg::IDD, pParent),
m_lpDibbitsChg(NULL),
m_lpDibbitsOrg(NULL),
m_Height(0),
m_Width(0),
m_byteSpacePerLine(0),
m_bytePerLine(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CmoduleForProcessDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
if (m_lpDibbitsOrg)
{
ShowOrgImg();
}
if (m_lpDibbitsChg)
{
ShowChgImg();
}
CDialog::OnPaint();
}
}
下面的函数实现的是打开一个bmp文件,然后,把文件中的数据保存到两个内存区域中,方便修改使用。这是一个按钮的响应函数
void CmoduleForProcessDlg::OnBnClickedOpenorg()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(TRUE,"bmp","*.bmp");
if (dlg.DoModal()==IDOK)
{
CFile file;
CFileException fe;
//打开文件失败
if(!file.Open(dlg.GetPathName(),CFile::modeRead|CFile::shareDenyWrite,&fe))
{
AfxMessageBox(TEXT("打开文件失败"));
//返回
return;
}
//--------------------------------------------------------
//如果打开文件成功,则开始读文件
//
//step0:---------------------------------
//如果曾经读入图片,要内存释放
if (m_lpDibbitsOrg)
{
::GlobalUnlock(static_cast<HGLOBAL>(m_hDIBOrg));
::GlobalFree(static_cast<HGLOBAL>(m_hDIBOrg));
//if the following used ,there will be wrong,don't know the reason
//CloseHandle(m_hDIBOrg);
m_lpDibbitsOrg=NULL;
}
//step1:------------------------------
//尝试读取DIB文件头
//
//位图文件头
BITMAPFILEHEADER bmfHeader;
if(file.Read((LPSTR)&bmfHeader,sizeof(bmfHeader))!=sizeof(bmfHeader))
{
//大小不对
MessageBox(TEXT("read bitmapfileheader uncorrect"));
return ;
}
//判断是否是DIB对象,检查头两个字节是否是BM
if(bmfHeader.bfType!=DIBFILETYPE)
{
//非DIB对象,返回NULL
MessageBox(TEXT("Not a bitmap file!"));
return;
}
//step2------------------------------------
//read BITMAPINFOHEADER m_bmiHeader
//
if(file.Read((LPSTR)&m_bmiHeader,sizeof(m_bmiHeader))!=sizeof(m_bmiHeader))
{
//have the wrong size
MessageBox(TEXT("Read bitmapinfoheader uncorrect!"));
return;
}
//step3------------------------------------
//read the data into the memory
//
m_size=static_cast<DWORD>(file.GetLength()-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER));
//为data分配内存
m_hDIBOrg=(HANDLE)::GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,m_size);
if(m_hDIBOrg==NULL)
{
MessageBox(TEXT("Alloc memory failed!"));
return;
}
//锁定DIB
m_lpDibbitsOrg=(LPSTR)::GlobalLock((HGLOBAL)m_hDIBOrg);
//now read the data from the file into the memory
if(file.Read(m_lpDibbitsOrg,m_size)!=m_size)
{
//if don't read correct
MessageBox(TEXT("Read the data wrong!"));
::GlobalUnlock((HGLOBAL)m_hDIBOrg);
::GlobalFree((HGLOBAL)m_hDIBOrg);
return;
}
//---------------------------------------------------------------
//now show the bitmap out on the screen
//
CWnd* pWnd=GetDlgItem(IDC_ORGIMG);
CDC* theDC=pWnd->GetDC();
CRect rect;
pWnd->GetClientRect(&rect);
StretchDIBits(theDC->m_hDC,
rect.left, rect.top,
rect.right-rect.left,
rect.bottom-rect.top,
0,0,
m_bmiHeader.biWidth,
m_bmiHeader.biHeight,
m_lpDibbitsOrg,
(LPBITMAPINFO)&m_bmiHeader,
DIB_RGB_COLORS,
SRCCOPY);
//--------------------------------------------------------------------
//now copy the original data into another memory play and show it out
//
//step0:---------------------
//在重新分配之前一定要释放原有的内存
//
if (m_lpDibbitsChg)
{
::GlobalUnlock(static_cast<HGLOBAL>(m_hDIBChg));
::GlobalFree(static_cast<HGLOBAL>(m_hDIBChg));
//the following used ,there will be wrong,don't know the reason
//CloseHandle(m_hDIBChg);
m_lpDibbitsChg=NULL;
}
m_hDIBChg=(HANDLE)::GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,m_size);
m_lpDibbitsChg=(LPSTR)::GlobalLock((HGLOBAL)m_hDIBChg);
memcpy(m_lpDibbitsChg,m_lpDibbitsOrg,m_size);
CWnd* pWndChg=GetDlgItem(IDC_CHGIMG);
CDC* theDCChg=pWndChg->GetDC();
CRect rectChg;
pWndChg->GetClientRect(&rectChg);
StretchDIBits(theDCChg->m_hDC,
rectChg.left, rectChg.top,
rectChg.right-rectChg.left,
rectChg.bottom-rectChg.top,
0,0,
m_bmiHeader.biWidth,
m_bmiHeader.biHeight,
m_lpDibbitsChg,
(LPBITMAPINFO)&m_bmiHeader,
DIB_RGB_COLORS,
SRCCOPY);
}
//------------------------------------------------------------
//now just for handy,to store some date
//
m_Height=m_bmiHeader.biHeight;
m_Width=m_bmiHeader.biWidth;
m_bytePerLine=(24*m_Width+31)/32*4;
m_byteSpacePerLine=m_bytePerLine-(24*m_Width+7)/8;
}
下面是保存内存中的图像到一幅bmp图像中去的函数,里面由于用的还是打开文件的对话框,看着有些别扭,但是总的是没有问题的
void CmoduleForProcessDlg::OnBnClickedSavechg()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(TRUE,"bmp","*.bmp");
if(dlg.DoModal()==IDOK)
{
//write out a bmp file
//
HANDLE hf=CreateFile(dlg.GetPathName(),GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, NULL, NULL );
if(hf==INVALID_HANDLE_VALUE)
return ;
//write out the file header
//
BITMAPFILEHEADER bfh;
memset(&bfh,0,sizeof(BITMAPFILEHEADER));
bfh.bfType='MB';
//设置位图文件的大小
bfh.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+m_size;
//设置位图像素所在的位置
bfh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
DWORD dwWritten=0;
WriteFile(hf,&bfh,sizeof(bfh),&dwWritten,NULL);
//and the bitmap format
//
BITMAPINFOHEADER bih;
memset(&bih,0,sizeof(BITMAPINFOHEADER));
bih.biSize=sizeof(BITMAPINFOHEADER);
bih.biWidth=m_Width;
bih.biHeight=m_Height;
bih.biPlanes=1;
bih.biBitCount=24;
WriteFile(hf,&bih,sizeof(bih),&dwWritten,NULL);
//and the bits themselfs
WriteFile(hf,m_lpDibbitsChg,m_size,&dwWritten,NULL);
CloseHandle(hf);
}
}
下面是对内存中的图像数据进行修改的代码,作为示例,只是很简单的把24位图像变成灰度图像。里面演示了两种获取每一点像素值的方法,其中被注释掉的是另一种方法。要注意RGB的排序问题。
void CmoduleForProcessDlg::OnBnClickedProcess()
{
// TODO: 在此添加控件通知处理程序代码
BYTE rColor,gColor,bColor;
BYTE changeColor;
//------------------------------------------
//method 1
//
LPSTR lpBufferOrg=m_lpDibbitsOrg;
LPSTR lpBufferChg=m_lpDibbitsChg;
for (int i=0;i<m_Height;i++)
{
for (int j=0;j<m_Width;j++)
{
bColor=*lpBufferOrg;
gColor=*(lpBufferOrg+1);
rColor=*(lpBufferOrg+2);
changeColor=(rColor+gColor+bColor)/3;
*lpBufferChg=changeColor;
*(lpBufferChg+1)=changeColor;
*(lpBufferChg+2)=changeColor;
lpBufferOrg+=3;
lpBufferChg+=3;
}
lpBufferOrg+=m_byteSpacePerLine;
lpBufferChg+=m_byteSpacePerLine;
}
/*//-------------------------------------------------------------
//method 2
//
for (int i=0;i<m_Height;i++)
{
for (int j=0;j<m_Width;j++)
{
bColor=*(m_lpDibbitsOrg+(m_Height-i-1)*m_bytePerLine+j*3);
gColor=*(m_lpDibbitsOrg+(m_Height-i-1)*m_bytePerLine+j*3+1);
rColor=*(m_lpDibbitsOrg+(m_Height-i-1)*m_bytePerLine+j*3+2);
changeColor=(rColor+gColor+bColor)/3;
*(m_lpDibbitsChg+(m_Height-i-1)*m_bytePerLine+j*3)=changeColor;
*(m_lpDibbitsChg+(m_Height-i-1)*m_bytePerLine+j*3+1)=changeColor;
*(m_lpDibbitsChg+(m_Height-i-1)*m_bytePerLine+j*3+2)=changeColor;
}
}*/
}
下面是把内存中存放的数据显示出来,这里显示的是用于修改的那个内存块中的数据
void CmoduleForProcessDlg::ShowChgImg(void)
{
CWnd* pWndChg=GetDlgItem(IDC_CHGIMG);
CDC* theDCChg=pWndChg->GetDC();
CRect rectChg;
pWndChg->GetClientRect(&rectChg);
StretchDIBits(theDCChg->m_hDC,
rectChg.left, rectChg.top,
rectChg.right-rectChg.left,
rectChg.bottom-rectChg.top,
0,0,
m_bmiHeader.biWidth,
m_bmiHeader.biHeight,
m_lpDibbitsChg,
(LPBITMAPINFO)&m_bmiHeader,
DIB_RGB_COLORS,
SRCCOPY);
}
下面是把内存中存放的图像的原始数据显示出来
void CmoduleForProcessDlg::ShowOrgImg(void)
{
CWnd* pWnd=GetDlgItem(IDC_ORGIMG);
CDC* theDC=pWnd->GetDC();
CRect rect;
pWnd->GetClientRect(&rect);
StretchDIBits(theDC->m_hDC,
rect.left, rect.top,
rect.right-rect.left,
rect.bottom-rect.top,
0,0,
m_bmiHeader.biWidth,
m_bmiHeader.biHeight,
m_lpDibbitsOrg,
(LPBITMAPINFO)&m_bmiHeader,
DIB_RGB_COLORS,
SRCCOPY);
}
最后的两个函数都是自己定义的函数,作为辅助用的,直接从内存中读取数据然后显示到屏幕的相应区域,这样会比较的快的。
这样,很简单的,一个处理bmp图像的模板程序就完成了。如果要对图像进行别的处理,比如图像增强等等,就可以在CmoduleForProcessDlg::OnBnClickedProcess()中添加代码就可以了。