实验一 位图文件的读取与显示
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验一位图文件的读取与显示
一、实验背景
1 位图文件格式说明
位图文件格式由四部分组成,如图1所示,分别是位图文件头、位图信息头、调色板以及位图像素数据,其中调色板信息为可选信息,只有当每个像素的比特数小于或等于8(BITMAPINFOHEADER.biBitCount<=8)时才存在,即为一个颜色查找表。
需要注意的是,位图文件存储时为了提高内存访问的速度,每一行的字节数必须是4的倍数,即:如果一幅图像的宽度为253,每个像素用8bit表示,因此,该图像实际每行所占的存储空间数为253Byte,但为了与4对齐,存储时所用的存储空间为256Byte。具体而言,假设图像的宽度为w,每个像素用n比特表示,则图像每行像素所占的字节数为:
(w * n + 31)/32 * 4
图1 位图文件格式说明
2 位图文件读取
位图文件的读取包括两步:(1)根据第1节中的位图文件格式说明,对位图文件进行解析;(2)根据读取的内容创建可供显示的位图句柄。
(1)位图文件解析
//open file
FILE *fp = NULL;
fopen_s(&fp, strPath, _T("rb"));
if (fp == NULL)
{
CString str = _T("File not exist: " )+ strPath;
AfxMessageBox(str);
return NULL;
}
//bitmap file header
BITMAPFILEHEADER bmFileHeader;
fread(&bmFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
if (bmFileHeader.bfType != 0x4d42)
{
AfxMessageBox(_T("file type is not bitmap"));
return NULL;
}
//bitmap info header
BITMAPINFO bmInfo;
BITMAPINFOHEADER &bmInfoHeader = bmInfo.bmiHeader;
fread(&bmInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
if (bmInfoHeader.biSize != sizeof(BITMAPINFOHEADER))
{
AfxMessageBox(_T("size of bitmap info header is inconsistent"));
return NULL;
}
//whether is compressed
if (bmInfoHeader.biCompression != BI_RGB)
{
AfxMessageBox(_T("File is compressed"));
return NULL;
}
int nPalettes = bmInfoHeader.biClrUsed;
if (nPalettes == 0 && bmInfoHeader.biBitCount <= 8)
nPalettes = 1 << bmInfoHeader.biBitCount;
if (bmFileHeader.bfOffBits != sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) + nPalettes * sizeof(RGBQUAD))
{
AfxMessageBox(_T("off bits is inconsistent"));
return NULL;
}
//Palette
//RGBQUAD *pPalette = NULL;
byte *pBmInfo = NULL;
if (nPalettes > 0)
{
pBmInfo = new byte[sizeof(BITMAPINFOHEADER) + nPalettes *
sizeof(RGBQUAD)];
memcpy(pBmInfo, &bmInfoHeader, sizeof(BITMAPINFOHEADER));
byte *pPalette = pBmInfo + sizeof(BITMAPINFOHEADER);
fread(pPalette, sizeof(RGBQUAD), nPalettes, fp);
}
//line width
int nLineByte = (bmInfoHeader.biWidth * bmInfoHeader.biBitCount + 31) / 32 * 4;
//不直接使用bmInfoHeader.biSizeImage,因为图像不压缩时该字段可以为零
int nImageBytes = nLineByte * bmInfoHeader.biHeight;
//image data
byte *pContents = new byte[nImageBytes];
fread(pContents, nImageBytes, 1, fp);
(2)将读取的内容转换为Bitmap句柄
该步骤需使用系统函数CreateDIBitmap。CreateDIBitmap的函数说明如下:
HBITMAP CreateDIBitmap(HDC hdc, CONST BITMAPINFOHEADER *lpbmih, DWORD fdwlnit, CONST VOID *lpblnit, CONST BITMAPINFO *lpbmi, UINT fuUsage);
参数:
hdc:设备环境句柄。
lpbmih:指向位图信息头结构的指针,它可以是下列操作系统位图信息头之一:
Fdwlnit:位标识集。它指定系统如何对位图的位进行初始化。
CBM_INIT:如果设置了该标志,那么系统将使用lpblnit和lpbmi两个参数指向的数据来对位图中的位进行初始化。如果没有该标志,那么表示上述两个参数指向的数据无效。如果fdwlnit为0,那么系统不会对位图的位进行初始化。
lpblnit:该指针指向包含初始的位图数据的字节类型数组。数据格式与参数lpbmi指向的BITMAPINFO结构中的成员biBitCount有关。
lpbmi:指向BITMAPINFO结构的旨针。该结构描述了参数lpbmi指向的数组的维数和