VS2015实现bmp格式图片的读取

预备知识:掌握一些mfc基本的控件用法以及bmp格式的图片的一些内容,当然不知道也无伤大雅。

step1:新建基于对话框的mfc工程

VS2015实现bmp格式图片的读取_第1张图片

VS2015实现bmp格式图片的读取_第2张图片

step2:拖控件

 

VS2015实现bmp格式图片的读取_第3张图片

然后将PictureControl的ID随便改个名字,必须改(因为默认它为静态的)

step3:读文件

1.

     双击打开按钮进行添加事件响应程序,当然在这之前你也可以改变按钮的ID,这样有利于程序的读的顺眼。如果你都双击完了,就别再改ID!!!这里我改成了IDC_OPEN和IDC_SAVE

然后将下列代码复制到时间相应程序中:

CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "位图文件(*.bmp)|*.bmp||");
if (dlg.DoModal() != IDOK) return;
CFile file(dlg.GetPathName(), CFile::modeRead);

这时有可能会出现这种错误:

严重性    代码    说明    项目    文件    行    禁止显示状态
错误    C2664    “CFileDialog::CFileDialog(const CFileDialog &)”: 无法将参数 5 从“const char [24]”转换为“LPCTSTR”    Demo    f:\csdn_demo\demo\demo\demo\demodlg.cpp    162    
可以这么解决:

点击解决方案,然后找到你的项目名称,右键然后点击属性,在常规中将字符集改为使用多字节字符集即可。

VS2015实现bmp格式图片的读取_第4张图片

这时候你已经可以选择文件了。

2.读文件头与信息头以及像素数据

①文件头:

file.Read(&m_file_Head, sizeof(BITMAPFILEHEADER));  //WORD是一个字,两个字节。

在.h中添加变量m_file_Head的变量声明:

BITMAPFILEHEADER m_file_Head;

有关位图文件头相关:VS2015实现bmp格式图片的读取_第5张图片

bfSize = bfOffBits + 图片像素数据的大小(图片的行(还有个四字节对齐问题)*列)。

bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +1024(灰度图像有的颜色表,彩色图像没有)。

②位图信息,包括位图信息头和颜色表

添加以下代码

//读取整个位图信息,包括信息头和颜色表
if (m_pdataInfo != NULL) delete[] m_pdataInfo;  //看看这段内存是否已经用了
m_pdataInfo = (BITMAPINFO*)new BYTE[m_file_Head.bfOffBits - 14];
file.Read(m_pdataInfo, m_file_Head.bfOffBits - 14);

//	BITMAPINFOHEADER *pBmih = m_pdataInfo->bmiHeader;//位图信息头指针其实就是位图信息的指针
//int nWidth, nHeight, nBitCount;
m_nWidth = m_pdataInfo->bmiHeader.biWidth;
m_nHeight = m_pdataInfo->bmiHeader.biHeight;
m_nBitCount = m_pdataInfo->bmiHeader.biBitCount;

m_nDibWidth = (m_nWidth*m_nBitCount + 31) / 32 *4;//
int nDL = m_nDibWidth * m_nHeight;//字节

if (m_pImage != NULL) delete[] m_pImage;

m_pImage = new BYTE[nDL];
file.Read(m_pImage, nDL);
file.Close();

RedrawWindow();//回调OnPaint,在OnPaint中实现显示
​

然后我们添加变量,添加变量肯定要在类的声明中添加,故打开类视图,双击C×××Dlg,将下列变量定义加入

public:
BYTE *m_pdataInfo;//存位图信息的变量指针变量
int m_nWidth, m_nHeight, m_nBitCount;//从左到右依次是图像宽度,高度,每个像素的位数
BYTE *m_pImage;//存像素数据

考虑到两个都是指针类型的变量,我们就要有销毁和初始化,初始化肯定是在OnInitDialog中,销毁需要自己加。

初始化:双击OnInitDialog,添加如下代码:

m_pdataInfo = NULL;
m_pImage = NULL;

如图所示:

VS2015实现bmp格式图片的读取_第6张图片

销毁:添加OnDestory函数

VS2015实现bmp格式图片的读取_第7张图片

再将以下代码贴到OnDestory函数中

if (m_pImage != NULL) delete[] m_pImage;
if (m_pdataInfo != NULL) delete[] m_pdataInfo;

然后我们解释解释这句代码:

m_nDibWidth = (m_nWidth*m_nBitCount + 31) / 32 *4;

这句话就牵扯到四字节对齐问题,它的目的就是保证每行的像素个数都是4的倍数,这句话囊可以将每行不是4的倍数转成每行都是4倍数的像素个数。

假设m_nWidth = 3,8位灰度图像,由于这些全部都是整型,所以(3*8+31)/32*4 = 55/32*4 = 1*4 = 4。

为啥弄成四字节对齐,这牵涉计算机底层了,我们也没必要知道。

 

3.图像的显示

接下来我们要用到那个框了,先给框加变量。如图所示

VS2015实现bmp格式图片的读取_第8张图片

在OnPaint中添加:

//显示第一个框
	if (m_pdataInfo != NULL && m_pImage != NULL)
	{
		//以上只是读完了图片,下面开始显示,m_ctrlImage就是那个框
		HDC hdc = m_ctrlImage.GetDC()->GetSafeHdc(); //获得显示的句柄
													 //把图形的哪一部分显示

		CRect rc;
		m_ctrlImage.GetWindowRect(&rc);//得到框的信息给到rc中,左上角是原点,
		m_ctrlImage.ScreenToClient(&rc);//坐标转换,将框的坐标转换到rc中
		SetStretchBltMode(hdc, STRETCH_HALFTONE); //设置缩放显示模式
		StretchDIBits(hdc, rc.left, rc.top, rc.Width(), rc.Height(),
			0, 0, m_nWidth, m_nHeight, m_pImage, (BITMAPINFO *)m_pdataInfo, DIB_RGB_COLORS, SRCCOPY);
	}

step4:效果演示

VS2015实现bmp格式图片的读取_第9张图片

VS2015实现bmp格式图片的读取_第10张图片

step5:bmp图片的保存操作

关键是要区分彩色图片和灰度图片的差别。

双击控件按钮保存添加处理代码,

VS2015实现bmp格式图片的读取_第11张图片

然后加入以下程序:

// TODO: 在此添加控件通知处理程序代码
	int nDL = m_nDibWidth * m_nHeight;
	BITMAPFILEHEADER fileheader;
	BITMAPINFOHEADER infoHeader;
	BYTE datacolor[sizeof(RGBQUAD) * 256];
	BYTE *m_pImage2 = NULL;
	/*
	BYTE *m_pImage_t = NULL;
	if (m_pImage_t != NULL) delete[] m_pImage_t;
	m_pImage_t = new BYTE[nDL];
	memcpy(m_pImage_t, m_pImage, nDL);
	*/
	CFile bmpFile;
	CString strFileName;
	CFileDialog dlg(FALSE, "*.BMP", NULL, NULL, "位图文件(*.BMP)|*.bmp;*.BMP");
	if (!dlg.DoModal() == IDC_SAVE) return;
	strFileName = dlg.GetPathName();
	if (bmpFile.Open(strFileName, CFile::modeCreate | CFile::modeWrite) == 0)return;

	fileheader.bfType = 0x4d42;
	fileheader.bfOffBits = m_file_Head.bfOffBits;
	fileheader.bfSize = m_file_Head.bfOffBits + nDL;
	fileheader.bfReserved1 = 0;
	fileheader.bfReserved2 = 0;

	
	infoHeader.biSize = sizeof(BITMAPINFOHEADER);
	infoHeader.biWidth = m_pdataInfo->bmiHeader.biWidth;
	infoHeader.biHeight = m_pdataInfo->bmiHeader.biHeight;
	infoHeader.biBitCount = m_pdataInfo->bmiHeader.biBitCount;
	infoHeader.biClrImportant = m_pdataInfo->bmiHeader.biClrImportant;
	infoHeader.biClrUsed = m_pdataInfo->bmiHeader.biClrUsed;
	infoHeader.biCompression = m_pdataInfo->bmiHeader.biCompression;
	infoHeader.biPlanes = m_pdataInfo->bmiHeader.biPlanes;
	infoHeader.biSizeImage = nDL;
	infoHeader.biXPelsPerMeter = m_pdataInfo->bmiHeader.biXPelsPerMeter;
	infoHeader.biYPelsPerMeter = m_pdataInfo->bmiHeader.biXPelsPerMeter;
	
	if (m_pImage2 != NULL) {
		delete[]m_pImage2;
	}
	m_pImage2 = new BYTE[nDL];
	memcpy(m_pImage2, m_pImage, nDL);

	bmpFile.Write(&fileheader, 14);
	bmpFile.Write(&infoHeader,40);
	if (m_pdataInfo->bmiHeader.biBitCount == 8) {
		memcpy(datacolor, m_pdataInfo->bmiColors, 1024);
		bmpFile.Write(datacolor,1024);
	}
	bmpFile.Write(m_pImage2, nDL);


	bmpFile.Close();

再看下效果:

VS2015实现bmp格式图片的读取_第12张图片此时桌面会有VS2015实现bmp格式图片的读取_第13张图片

你可能感兴趣的:(mfc图像处理,VS)