位图的读取与显示物联一班谢鑫1231. 实验目的通过位图文件的解析,进一步理解位图文件的格式;熟悉Windows环境下图片的显示方式。
2. 实验内容在Windows环境下,通过解析位图文件的格式,读入位图并进行显示,不能使用Windows中已有的API(如LoadImage函数)读取位图文件,即自己实现LoadImage函数的功能:LoadImage(NULL, “lenna.bmp”, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)三、实验原理及步骤:基本知识:BMP位图文件格式BMP位图文件中主要由4部分内容组成:1、文件头BITMAPFILEHEADER为一STRUCTURE:typedef struct tagBITMAPFILEHEADER {WORD bfType;//文件类型,必须为“BM”或0x424dDWORD bfSize;//文件大小WORD bfReserved1;//保留WORD bfReserved2;//保留DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;2、位图信息头BITMAPINFOHEADER,定义如下:typedef struct tagBITMAPINFOHEADER{DWORD biSize;//structure sizeLONG biWidth;//image widthLONG biHeight;//image heightWORD biPlanes;//value is 1WORD biBitCount;//color bitsDWORD biCompression;//compression or notDWORD biSizeImage;//Image size=width*height( 其中width必须为4的倍数。
LONG biXPelsPerMeter;//LONG biYPelsPerMeter;DWORD biClrUsed;//DWORD biClrImportant;} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;3、调色板typedef struct tagRGBQUAD {BYTE rgbBlue;BYTE rgbGreen;BYTE rgbRed;BYTE rgbReserved;} RGBQUAD;用于存放图像的颜色。
4、图像的实际数据。
对于2色图,用1位表示像素的值。
对于16色图,用4位表示像素的值。
对于256色图,一个字节刚好表示1个像素。
对于用到调色板的位图,图像数据就是该像素颜色在调色板中索引值,对于真彩色,不用调色板,三个字节的数据分别代表图像的B、G、R。
实验步骤:1、生成一名为Gsm的基于MFC的应用程序框架:选择file菜单new选项,在打开的窗口中选择project选项,选中MFC AppWizard(exe)。
并在project name输入Gsm ,选择存放project 的位置。
如下图所示。
选择确定,进入下一步。
选择single document,并在最后CdipView 类的基类中选择CscrollView,使应用程序视图具有滚动条。
2、在应用程序中加入具体的函数和变量。
在Class View中选择CGsmView单击右键选择添加成员变量,加入下列变量:public:int m_x;HBITMAP m_Bmp;LPVOID m_ColorList;LPBYTE m_Image;LPBITMAPINFOHEADER m_DibHead;enum allocate {None, crtallocate, heapallocate};allocate m_nBmpallocate;allocate m_nImageallocate;DWORD m_ImageSize;int m_nPalette;HANDLE m_hFile;HANDLE m_hMap;LPVOID m_lpvFile;HPALETTE m_hPalette;HGLOBAL m_hGlob;在Class View中选择CGsmView单击右键选择添加成员函数,把下列函数加入到C++View类中void SetPaletteSize(int nBitCount);void Clear();BOOL ReadFile(CFile *pFile);BOOL SetPalette();BOOL GetPalette();BOOL DibToDC(CDC* pDC,CSize size);BOOL MemToDib(LPVOID lmem);CSize GetDibSize();3、把对应函数代码拷贝到新的函数中;void CGsmView::SetPaletteSize(int nBitCount){if(m_DibHead->biSize != sizeof(BITMAPINFOHEADER)) {throw new CException;}m_ImageSize = m_DibHead->biSizeImage;if(m_ImageSize == 0) {DWORD dwBytes = ((DWORD) m_DibHead->biWidth *m_DibHead->biBitCount) / 32;if(((DWORD) m_DibHead->biWidth * m_DibHead->biBitCount) % 32){dwBytes++;}dwBytes *= 4;m_ImageSize = dwBytes * m_DibHead->biHeight;}m_ColorList = (LPBYTE) m_DibHead + sizeof(BITMAPINFOHEADER);if((m_DibHead == NULL) || (m_DibHead->biClrUsed == 0)) { switch(nBitCount) {case 1:m_nPalette = 2;break;case 4:m_nPalette = 16;break;case 8:m_nPalette = 256;break;case 16:case 24:case 32:m_nPalette = 0;break;default:ASSERT(FALSE);}}else {m_nPalette = m_DibHead->biClrUsed;}ASSERT((m_nPalette >= 0) && (m_nPalette <= 256));}void CGsmView::Clear(){if(m_hFile == NULL) return;::UnmapViewOfFile(m_lpvFile);::CloseHandle(m_hMap);::CloseHandle(m_hFile);m_hFile = NULL;if(m_nBmpallocate == crtallocate) {delete [] m_DibHead;}else if(m_nBmpallocate == heapallocate) {::GlobalUnlock(m_hGlob);::GlobalFree(m_hGlob);}if(m_nImageallocate == crtallocate) delete [] m_Image;if(m_hPalette != NULL) ::DeleteObject(m_hPalette);if(m_Bmp != NULL) ::DeleteObject(m_Bmp);m_nBmpallocate = m_nImageallocate = None;m_hGlob = NULL;m_DibHead = NULL;m_Image = NULL;m_ColorList = NULL;m_nPalette = 0;m_ImageSize = 0;m_lpvFile = NULL;m_hMap = NULL;m_hFile = NULL;m_Bmp = NULL;m_hPalette = NULL;}BOOL CGsmView::ReadFile(CFile *pFile){int nCount, nSize;BITMAPFILEHEADER bmfh;Clear();try {nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));if(nCount != sizeof(BITMAPFILEHEADER)) {throw new CException;}if(bmfh.bfType != 0x4d42) {throw new CException;}nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);m_DibHead = (LPBITMAPINFOHEADER) new char[nSize];m_nBmpallocate = m_nImageallocate = crtallocate;nCount = pFile->Read(m_DibHead, nSize);SetPaletteSize(m_DibHead->biBitCount);GetPalette();m_Image = (LPBYTE) new char[m_ImageSize];nCount = pFile->Read(m_Image, m_ImageSize);}catch(CException* tmpc) {AfxMessageBox("文件读取错误");tmpc->Delete();return FALSE;}return TRUE;}BOOL CGsmView::SetPalette(){if(m_nPalette!=0)return FALSE;CClientDC dc(this);CDC *pDC=&dc;m_hPalette=::CreateHalftonePalette(pDC->GetSafeHdc());return TRUE;}BOOL CGsmView::GetPalette(){if(m_nPalette==0)return FALSE;if(m_hPalette!=NULL)::DeleteObject(m_hPalette);LPLOGPALETTE pTempPalette=(LPLOGPALETTE) new char[2*sizeof(WORD)+ m_nPalette*sizeof(PALETTEENTRY)]; pTempPalette->palVersion=0x30;pTempPalette->palNumEntries=m_nPalette;LPRGBQUAD pRGBQuad=(LPRGBQUAD)m_ColorList;for(int i=0;i<m_nPalette;i++){pTempPalette->palPalEntry[i].peRed=pRGBQuad->rgbRed;pTempPalette->palPalEntry[i].peGreen=pRGBQuad->rgbGreen;pTempPalette->palPalEntry[i].peBlue=pRGBQuad->rgbBlue;pTempPalette->palPalEntry[i].peFlags=0;pRGBQuad++;}m_hPalette=::CreatePalette(pTempPalette);delete pTempPalette;return TRUE;}BOOL CGsmView::DibToDC(CDC *pDC, CSize size){if(m_DibHead==NULL)return FALSE;if(m_hPalette!=NULL){HDC hdc=pDC->GetSafeHdc();::SelectPalette(hdc,m_hPalette,TRUE);}pDC->SetStretchBltMode(COLORONCOLOR);::StretchDIBits(pDC->GetSafeHdc(),0,0,size.cx,size.cy,0,0,m_DibHead->biWidth,m_DibHead->biHeight,m_Image,(LPBITMAPINFO)m_DibHead,DIB_RGB_COLORS,SRCCOPY);return TRUE;}BOOL CGsmView::MemToDib(LPVOID lmem){Clear();m_DibHead=(LPBITMAPINFOHEADER)lmem;SetPaletteSize(m_DibHead->biBitCount);m_Image=(LPBYTE)m_ColorList+sizeof(RGBQUAD)*m_nPalette;GetPalette();return TRUE;}CSize CGsmView::GetDibSize(){if(m_DibHead==NULL)return CSize(0,0);return CSize((int)m_DibHead->biWidth,(int)m_DibHead->biHeight); }4、编译检验没有出现错误;5、在程序资源中创建位图条为默认;6、修改OnInitialUpdate函数中的代码;void CGsmView::OnInitialUpdate(){CScrollView::OnInitialUpdate();m_x=25;CSize MaxSize(24000,32000);CSize MinSize(MaxSize.cx/100,MaxSize.cy/100);SetScrollSizes(MM_HIMETRIC,MaxSize,MaxSize,MinSize);LPVOID lFirstBMP=(LPVOID)::LoadResource(NULL,::FindResource(NULL,MAKEINTRESOURCE(IDB_BITMAP1),RT_BITMAP));MemToDib(lFirstBMP);}7、修改OnDraw函数中的代码;void CGsmView::OnDraw(CDC* pDC){CGsmDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);BeginWaitCursor();CSize DibSize = GetDibSize();DibSize.cx *= m_x;DibSize.cy *= -m_x;DibToDC(pDC, DibSize);EndWaitCursor();}8、建立打开文件的消息响应函数在Menu中打开菜单编辑窗口,单击“文件”,在下拉菜单中选中“打开”,右键单击,在弹出菜单中选择“类向导”并打开。