上篇博客简要介绍了如何利用MFC读取并显示一幅位图图像,并获取鼠标点击位置的像素坐标和灰度值信息,主要包含了对话框的创建和添加程序,代码也在上一页中给了大家,但是并没有详细说明功能,所以在这一节当中主要介绍代码的含义。
一、打开并显示位图图片
(一)程序清单
void Cwj_zuoyeDlg::OnBnClickedOpen()
{
// TODO: 在此添加控件通知处理程序代码
//打开文件
CString filter = (CString)"图像文件(*.bmp)|*.bmp;*.BMP||";//指明可供选择的文件类型和相应的扩展名
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter, NULL); //打开文件
//按下确定按钮 dlg.DoModal() 函数显示对话框
if (dlg.DoModal() == IDOK)
{
//打开对话框获取图像信息
CString BmpName = dlg.GetPathName(); //获取文件路径名
CString EntName = dlg.GetFileExt(); //获取文件扩展名
EntName.MakeLower(); //将文件扩展名转换为一个小写字符
if (EntName.Compare(_T("bmp")) == 0) //如果是bmp图片则打开显示
{
//定义变量存储图片信息
BITMAPINFO *pBmpInfo; //记录图像信息头内容
BYTE *pBmpData; //图像数据
BITMAPFILEHEADER bmpHeader; //文件头
BITMAPINFOHEADER bmpInfo; //信息头
CFile bmpFile; //记录打开文件
//以只读的方式打开文件 读取bmp图片各部分 bmp文件头 信息 数据
if (!bmpFile.Open(BmpName, CFile::modeRead | CFile::typeBinary))
return;
if (bmpFile.Read(&bmpHeader, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER))
return;
if (bmpFile.Read(&bmpInfo, sizeof(BITMAPINFOHEADER)) != sizeof(BITMAPINFOHEADER))
return;
pBmpInfo = (BITMAPINFO *)new char[sizeof(BITMAPINFOHEADER)];
//为图像数据申请空间
memcpy(pBmpInfo, &bmpInfo, sizeof(BITMAPINFOHEADER)); //存储图像信息头内容
DWORD dataBytes = bmpHeader.bfSize - bmpHeader.bfOffBits;//图像数据大小,单位为字节
pBmpData = (BYTE*)new char[dataBytes];
bmpFile.Read(pBmpData, dataBytes); //存储图像数据
bmpFile.Close();
//显示图像
CStatic *pwnd = (CStatic*)GetDlgItem(IDC_STATIC); //里面的参数是图片控件的ID
//pwnd->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
pwnd->ModifyStyle(0xf, SS_BITMAP);
pwnd->SetBitmap((HBITMAP)::LoadImage(GetModuleHandle(NULL), BmpName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));//打开图片
}
}
}
(二)函数含义
CString filter = (CString)"图像文件(*.bmp)|*.bmp;*.BMP||";//指明可供选择的文件类型和相应的扩展名
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter, NULL); //打开文件
其中CFileDialog是MFC当中的一个类,它的构造函数如下:
explicit CFileDialog(BOOL bOpenFileDialog, //TRUE则显示打开对话框,为FALSE则显示保存对话文件对
话框。
LPCTSTR lpszDefExt = NULL, //指定默认的文件扩展名。
LPCTSTR lpszFileName = NULL, //指定默认的文件名, 可带上完整的文件路径
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
// 指明一些特定风格
LPCTSTR lpszFilter = NULL, //指明可供选择的文件类型和相应的扩展名。
CWnd* pParentWnd = NULL, //为父窗口指针。
DWORD dwSize = 0, //OPENFILENAME结构体的大小。
BOOL bVistaStyle = TRUE //指定文件对话框的风格,设为TRUE则使用Vista风格的文件对
//话框,否则使用旧版本的文件对话框。
);
所以上面代码的意思就是打开一个对话框,寻找bmp类型的文件并打开(参数不完整时后面的为默认形式)
相关的链接是https://www.cnblogs.com/kex1n/p/3595800.html和https://blog.csdn.net/grllery/article/details/76234863
//显示图像
CStatic *pwnd = (CStatic*)GetDlgItem(IDC_STATIC); //里面的参数是图片控件的ID
//pwnd->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
pwnd->ModifyStyle(0xf, SS_BITMAP);
pwnd->SetBitmap((HBITMAP)::LoadImage(GetModuleHandle(NULL), BmpName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));//打开图片
SetWindowPos函数的含义如下
BOOL SetWindowPos(const CWnd* pWndInsertAfter, //窗口的 Z 顺序
int x, int y, //窗口位置
int cx, int cy, //窗口大小
UINT nFlags); //选项
参考链接https://www.cnblogs.com/findumars/p/3948315.html
显示部分主要参考https://blog.csdn.net/sundy_2004/article/details/7183600
还有另一种显示方法,这种显示方法会把整个图片框都填充满,也就是说可能拉伸或者收缩图像的大小,图像很可能失去原来的形状,主要用法如下
//显示图像
CWnd *pWnd=GetDlgItem(IDC_STATIC_PIC); //获得pictrue控件窗口的句柄
CRect rect;
pWnd->GetClientRect(&rect); //获得pictrue控件所在的矩形区域
CDC *pDC=pWnd->GetDC(); //获得pictrue控件的DC
pDC->SetStretchBltMode(COLORONCOLOR);
StretchDIBits(pDC->GetSafeHdc(),0,0,rect.Width(),rect.Height(),0,0, bmpInfo.biWidth,bmpInfo.biHeight,pBmpData,pBmpInfo,DIB_RGB_COLORS,SRCCOPY);
参考程序https://blog.csdn.net/lynn1258/article/details/54376311
该函数具体用法如https://blog.csdn.net/hnu_zxc/article/details/7491366
二、显示像素坐标和灰度值
(一)程序清单
void Cwj_zuoyeDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
CWnd *pWnd = GetDlgItem(IDC_STATIC); //图像控件框的ID
pWnd->GetWindowRect(&rect);
ScreenToClient(&rect);
//先获取鼠标相对于屏幕的绝对坐标
GetCursorPos(&point);
int temp_x = point.x; //为了获取灰度值使用
int temp_y = point.y;
//然后得到static控件的rect坐标
CRect pRect;
pWnd->GetClientRect(&pRect);
//最后把当前鼠标的坐标转化为相对于rect的坐标(相对坐标)
pWnd->ScreenToClient(&point);
int x = point.x; //相对坐标
int y = point.y;
SetDlgItemInt(IDC_EDIT1, x); //写入坐标值x
SetDlgItemInt(IDC_EDIT2, y); //写入坐标值y
HDC hDC = ::GetDC(NULL);
COLORREF rgb = ::GetPixel(hDC, temp_x, temp_y); //后两个参数是屏幕绝对坐标,如果用相对坐标则获取错误的灰度值
int r = GetRValue(rgb); //获得灰度分量
int g = GetGValue(rgb);
int b = GetBValue(rgb);
SetDlgItemInt(IDC_EDIT3, r); //写入灰度分量R
SetDlgItemInt(IDC_EDIT4, g); //写入灰度分量G
SetDlgItemInt(IDC_EDIT5, b); //写入灰度分量B
CDialogEx::OnLButtonDown(nFlags, point);
}
(二)程序简述
GetCursorPos()的用法 通常是 :
CPoint cp;
GetCursorPos(&cp);
它获取的是 鼠标相对屏幕的左上角的距离,单位是像素。而对于一个窗口来说,它的消息响应函数的输入参数通常是相对于客户区左上角的距离。
比如说OnLButtonDown(UINT nFlags, CPoint point)的 point参数,就是相对于客户区的左上角而言的。想要把从GetCursorPos()获得的坐标转化成相对于客户区的坐标,要调用ScreenToClient()函数。
主要参考https://www.cnblogs.com/SnailProgramer/p/4175561.html
关于MFC编辑框的读写参考https://blog.csdn.net/c_gyl/article/details/66972310
这基本把主要部分介绍完了,资料整理不易,所以我就以链接的方式包含起来了,否则长篇大论读者可能不喜欢。
关于这部分内容就介绍到这里,后续还有更新请留意