BMP位图格式分析

anew_1916 2013-03-25 09:27:00

如下是我打开BMP文件的相应函数,结果图片能显示在视图中,但是却不对,图片是斜的,是倒置的,不理解,求指点

void CBMPView::OnFileOpen()
{
// TODO: 在此添加命令处理程序代码
CFileDialog fileDlg(TRUE);
//注意过滤器组的写法
//1. 每一组过滤器由一对字符串构成(每个字符串以\0结尾),第一个字符串是类型说明,
// 第二个字符串则是过滤格式,如果一组过滤器对多种格式过滤,不同的格式间用分号隔开
// 每一种格式由*.加上拓展名构成。
//2. 如果有多组过滤,那么有几组过滤就有几组字符串。
//3. 实例
// fileDlg.m_ofn.lpstrFilter =L"位图文件(*.bmp),文本文件(*.txt)\0*.bmp;*.txt\0音频文件(.mp3)\0*.mp3\0";
fileDlg.m_ofn.lpstrFilter =L"位图文件\0*.bmp\0";
if(IDOK == fileDlg.DoModal())
{
//打开BMP文件
CFile openFile(fileDlg.m_ofn.lpstrFile, CFile::modeRead | CFile::typeBinary);
//获取位图文件头、信息头
BITMAPFILEHEADER bmpFileHeader;
openFile.Read(&bmpFileHeader, 14);
BITMAPINFOHEADER bmpInfHeader;
openFile.Read(&bmpInfHeader, 40);
//绘制视图
CDC* pDC = GetDC();
openFile.Seek(bmpFileHeader.bfOffBits, CFile::begin);
if(bmpInfHeader.biBitCount == 24)
{
RGBTRIPLE* pRGB3;
pRGB3 = new RGBTRIPLE[bmpInfHeader.biWidth * bmpInfHeader.biHeight];
openFile.Read(pRGB3, bmpInfHeader.biWidth * bmpInfHeader.biHeight * 3);
for(int i=0; i< bmpInfHeader.biHeight; i++)
{
for(int j =0; j< bmpInfHeader.biWidth; j++)
{
pDC->SetPixelV(j, bmpInfHeader.biHeight - i, RGB(pRGB3[i*bmpInfHeader.biWidth+j].rgbtRed,pRGB3[i*bmpInfHeader.biWidth+j].rgbtGreen,pRGB3[i*bmpInfHeader.biWidth+j].rgbtBlue));
}//这里纵坐标如果直接用i图像显示出来是倒置的
}
delete [] pRGB3;
}
else if(bmpInfHeader.biBitCount == 32)
{
RGBQUAD* pRGB4;
pRGB4 = new RGBQUAD[bmpInfHeader.biWidth * bmpInfHeader.biHeight];
openFile.Read(pRGB4, bmpInfHeader.biWidth * bmpInfHeader.biHeight * 4);
for(int i=0; i< bmpInfHeader.biHeight; i++)
{
for(int j =0; j< bmpInfHeader.biWidth; j++)
{
pDC->SetPixelV(j, bmpInfHeader.biHeight - i, RGB(pRGB4[i*bmpInfHeader.biWidth+j].rgbRed,pRGB4[i*bmpInfHeader.biWidth+j].rgbGreen,pRGB4[i*bmpInfHeader.biWidth+j].rgbBlue));
}
}
delete [] pRGB4;
}
else
{
MessageBox(L"不支持的位图格式");
}
openFile.Close();
ReleaseDC(pDC);
}
}
...全文
125 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
Red_angelX 2013-03-25
  • 打赏
  • 举报
回复
32位图正好是4字节对齐 BMP的y坐标系是不是从上往下,是从下往上.
anew_1916 2013-03-25
  • 打赏
  • 举报
回复
知道了,在读取文件时将补位 的0也读到了缓冲区,做如下修改后OK了


if(bmpInfHeader.biBitCount == 24)
		{
			RGBTRIPLE* pRGB3;
			pRGB3 = new RGBTRIPLE[bmpInfHeader.biWidth * bmpInfHeader.biHeight];
			BYTE addtion = (bmpInfHeader.biWidth*3) % 4;
			addtion = 4 - addtion;
			for(int k=0; k<bmpInfHeader.biHeight; k++)
			{
				if(openFile.Read(&pRGB3[k * bmpInfHeader.biWidth], bmpInfHeader.biWidth * 3) < bmpInfHeader.biWidth * 3)
				{
					MessageBox(L"ERROR");
					return;
				}
				openFile.Seek(addtion, CFile::current);
			}
//			openFile.Read(pRGB3, bmpInfHeader.biWidth * bmpInfHeader.biHeight * 3);
			for(int i=0; i< bmpInfHeader.biHeight; i++)
			{
				for(int j =0; j< bmpInfHeader.biWidth; j++)
				{
					pDC->SetPixelV(j, bmpInfHeader.biHeight - i, RGB(pRGB3[i*bmpInfHeader.biWidth+j].rgbtRed,pRGB3[i*bmpInfHeader.biWidth+j].rgbtGreen,pRGB3[i*bmpInfHeader.biWidth+j].rgbtBlue));
				}
			}
			delete [] pRGB3;
		}

看了一本数字图像处理的书,上面说到BMP位图的每行都必须是4字节的整数倍,不足的用0补充。这一点对32位色的位图没影响,对于少于32色的图像有影响 但是书上还说道像素数组的排列方式有正向和负向之分,不怎么理解,有人知道的请帮忙说明一下
anew_1916 2013-03-25
  • 打赏
  • 举报
回复

void CBMPView::OnFileOpen()
{
	// TODO: 在此添加命令处理程序代码
	CFileDialog fileDlg(TRUE);
//注意过滤器组的写法
//1.	每一组过滤器由一对字符串构成(每个字符串以\0结尾),第一个字符串是类型说明,
//		第二个字符串则是过滤格式,如果一组过滤器对多种格式过滤,不同的格式间用分号隔开
//		每一种格式由*.加上拓展名构成。
//2.	如果有多组过滤,那么有几组过滤就有几组字符串。
//3.	实例
//		fileDlg.m_ofn.lpstrFilter =L"位图文件(*.bmp),文本文件(*.txt)\0*.bmp;*.txt\0音频文件(.mp3)\0*.mp3\0";
	fileDlg.m_ofn.lpstrFilter =L"位图文件\0*.bmp\0";
	if(IDOK == fileDlg.DoModal())
	{
		//打开BMP文件
		CFile openFile(fileDlg.m_ofn.lpstrFile, CFile::modeRead | CFile::typeBinary);
		//获取位图文件头、信息头
		BITMAPFILEHEADER bmpFileHeader;
		openFile.Read(&bmpFileHeader, 14);
		BITMAPINFOHEADER bmpInfHeader;
		openFile.Read(&bmpInfHeader, 40);
		//绘制视图
		CDC* pDC = GetDC();
		openFile.Seek(bmpFileHeader.bfOffBits, CFile::begin);
		if(bmpInfHeader.biBitCount == 24)
		{
			RGBTRIPLE* pRGB3;
			pRGB3 = new RGBTRIPLE[bmpInfHeader.biWidth * bmpInfHeader.biHeight];
			openFile.Read(pRGB3, bmpInfHeader.biWidth * bmpInfHeader.biHeight * 3);
			for(int i=0; i< bmpInfHeader.biHeight; i++)
			{
				for(int j =0; j< bmpInfHeader.biWidth; j++)
				{
					pDC->SetPixelV(j, bmpInfHeader.biHeight - i, RGB(pRGB3[i*bmpInfHeader.biWidth+j].rgbtRed,pRGB3[i*bmpInfHeader.biWidth+j].rgbtGreen,pRGB3[i*bmpInfHeader.biWidth+j].rgbtBlue));
				}//这里纵坐标如果直接用i图像显示出来是倒置的
			}
			delete [] pRGB3;
		}
		else if(bmpInfHeader.biBitCount == 32)
		{
			RGBQUAD* pRGB4;
			pRGB4 = new RGBQUAD[bmpInfHeader.biWidth * bmpInfHeader.biHeight];
			openFile.Read(pRGB4, bmpInfHeader.biWidth * bmpInfHeader.biHeight * 4);
			for(int i=0; i< bmpInfHeader.biHeight; i++)
			{
				for(int j =0; j< bmpInfHeader.biWidth; j++)
				{
					pDC->SetPixelV(j, bmpInfHeader.biHeight - i, RGB(pRGB4[i*bmpInfHeader.biWidth+j].rgbRed,pRGB4[i*bmpInfHeader.biWidth+j].rgbGreen,pRGB4[i*bmpInfHeader.biWidth+j].rgbBlue));
				}
			}
			delete [] pRGB4;
		}
		else
		{
			MessageBox(L"不支持的位图格式");
		}
		openFile.Close();
		ReleaseDC(pDC);
	}
}
anew_1916 2013-03-25
  • 打赏
  • 举报
回复
上面在正常情况下没有释放buffer,失误啊
anew_1916 2013-03-25
  • 打赏
  • 举报
回复
可以用Win32API函数SetDIBitsToDevice来打开位图,代码如下


CDC* pDC = GetDC();
		BITMAPINFO* pbi = (BITMAPINFO*)new BYTE[40];//没有调色板,仅用于真彩色
	//关于 BITMAPINFO 对象的构造涉及到一个长度为1的颜色结构的数组,其意义参见
	//http://blog.csdn.net/zhanyan4s/article/details/8718499
		pbi->bmiHeader = bmpInfHeader;
		BYTE* buffer = NULL;
		ULONG len =0;
		if(bmpInfHeader.biBitCount == 24)
		{
			BYTE addtion = (bmpInfHeader.biWidth*3) % 4;
			if(addtion)
			{
				addtion = 4 - addtion;
				len = (bmpInfHeader.biWidth * 3 + addtion) * bmpInfHeader.biHeight;
			}
			else
			{
				len = bmpInfHeader.biWidth * bmpInfHeader.biHeight * 3;
			}
		}
		else if(bmpInfHeader.biBitCount == 32)
		{
			len = bmpInfHeader.biWidth * bmpInfHeader.biHeight * 4;
		}
		else
		{
			MessageBox(L"不支持的位图格式");
			openFile.Close();
			ReleaseDC(pDC);
			return;
		}
		buffer = new BYTE[len];
		openFile.Seek(bmpFileHeader.bfOffBits, CFile::begin);
		if(openFile.Read(buffer, len) < len)
		{
			MessageBox(L"ERROR");
			delete [] buffer;
			openFile.Close();
			ReleaseDC(pDC);
			return;
		}
		::SetDIBitsToDevice(pDC->m_hDC, 0, 0, bmpInfHeader.biWidth, bmpInfHeader.biHeight, 0, 0, 0, bmpInfHeader.biHeight, buffer, pbi, DIB_RGB_COLORS);
		openFile.Close();
		ReleaseDC(pDC);

DIB有关的AIP函数有 SetDIBitsToDevice SetDIBits StretchDIBits GetDIBits GetDIBColorTable MFC中的CBitmap可以用来处理BMP位图 从第一种处理BMP位图的方式可以看出BMP格式的位图没有进行数据压缩

64,642

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧