DIB位图文件的格式、读取、保存和显示

一、位图文件结构

位图文件由三部分组成:文件头 + 位图信息 + 位图像素数据

1、位图文件头。位图文件头主要用于识别位图文件。以下是位图文件头结构的定义:

typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;

其中的bfType值应该是“BM”(0x4d42),标志该文件是位图文件。bfSize的值是位图文件的大小。

2、位图信息中所记录的值用于分配内存,设置调色板信息,读取像素值等。
以下是位图信息结构的定义:

typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO;

可见位图信息也是由两部分组成的:位图信息头 + 颜色表

2.1位图信息头。位图信息头包含了单个像素所用字节数以及描述颜色的格式,此外还包括位图的宽度、高度、目标设备的位平面数、图像的压缩格式。以下是位图信息头结构的定义:

typedef struct tagBITMAPINFOHEADER{ // bmih DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;

下表是对结构体当中各个成员的说明:
结构成员
 说 明
biSize 结构BITMAPINFOHEADER的字节数,即sizeof(BITMAPINFOHEADER)*
biWidth
 以像素为单位的图像宽度*
biHeight
 以像素为单位的图像长度*
biplanes
 目标设备的位平面数
biBitCount
 每个像素的位数*(1)
biCompression
 图像的压缩格式(这个值几乎总是为0)
biSizeImage
 以字节为单位的图像数据的大小(对BI_RGB压缩方式而言)
biXPelsPermeter
 水平方向上的每米的像素个数
biYpelsPerMeter
 垂直方向上的每米的像素个数
biClrused
 调色板中实际使用的颜色数(2)
biClrImportant
 现实位图时必须的颜色数(3)

说明:*是需要加以注意的部分,因为它们是我们在进行位图操作时经常参考的变量
(1)对于每个像素的字节数,分别有一下意义:
0,用在JPEG格式中
1,单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片
4,16色图
8,256色图,通常说的灰度图
16,64K图,一般没有调色板,图像数据中每两个字节表示一个像素,5个或6个位表示一个RGB分量
24,16M真彩色图,一般没有调色板,图像数据中每3个字节表示一个像素,每个字节表示一个RGB分量
32,4G真彩色,一般没有调色板,每4个字节表示一个像素,相对24位真彩图而言,加入了一个透明度,即RGBA模式

(2)这个值通常为0,表示使用biBitCount确定的全部颜色,例外是使用的颜色数目小于制定的颜色深度的颜色数目的最大值。

(3)这个值通常为0,表示所有的颜色都是必需的

2.2颜色表。颜色表一般是针对16位一下的图像而设置的,对于16位和16位以上的图像,由于其位图像素数据中直接对对应像素的RGB(A)颜色进行描述,因而省却了调色板。而对于16位一下的

图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。颜色表的作用就是创建调色板。

下图是带调色板和不带调色板的位图的简单示意图

图1 带调色板和不带调色板位图之间的区别

颜色表是由颜色表项组成的,颜色表项结构的定义如下:

typedef struct tagRGBQUAD { // rgbq BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD;

其中需要注意的问题是,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。

3、位图数据。最后,在位图文件头、位图信息头、位图颜色表之后,便是位图的主体部分:位图数据。根据不同的位图,位图数据所占据的字节数也是不同的,比如,对于8位位图,每个字

节代表了一个像素,对于16位位图,每两个字节代表了一个像素,对于24位位图,每三个字节代表了一个像素,对于32位位图,每四个字节代表了一个像素

二、位图文件的读取、保存和显示

头文件中定义

private: DWORD m_dwDibSize; CPalette m_Palette; int m_nPaletteEntries; RGBQUAD *m_pPalette; unsigned char *m_pDib, *m_pDibBits; BITMAPINFOHEADER *m_pBIH;   

1、读取位图

//加载图片 void CImageDisposeDlg::OnBtnloadimage() { // TODO: Add your control notification handler code here //文件路径名称 CString pszFilename; //浏览文件对话框 CFileDialog hFileDlg(TRUE,"bmp", NULL, OFN_FILEMUSTEXIST|OFN_READONLY|OFN_PATHMUSTEXIST|OFN_NOCHANGEDIR, TEXT("BMP (*.bmp)|*.bmp|所有文件(*.*)|*.*|"), NULL); if(hFileDlg.DoModal() == IDOK) { //获得文件路径名称 pszFilename=hFileDlg.GetPathName(); } //文件类 CFile cf; //文件打开失败,程序返回 if( !cf.Open( pszFilename, CFile::modeRead ) ) { return; } //获得位图信息文件大小 DWORD dwDibSize; dwDibSize = cf.GetLength() - sizeof( BITMAPFILEHEADER ); //申请一块内存存放位图信息 unsigned char *pDib; pDib = new unsigned char [dwDibSize]; if( pDib == NULL ) { return; } //位图文件头 BITMAPFILEHEADER BFH; //从文件读取位图文件头和位图数据 try{ // 判断读取位图文件头是否成功 if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) ) != sizeof( BITMAPFILEHEADER ) || // 判断是否是位图类型 BFH.bfType != 'MB' || // 判断读取位图数据是否成功 cf.Read( pDib, dwDibSize ) != dwDibSize ){ //释放位图数据指针 delete [] pDib; //读取失败,程序返回 return; } } catch( CFileException *e ){ e->Delete(); delete [] pDib; return; } //重置全局位图信息指针 if( m_pDib != NULL ) { delete m_pDib; } //将位图信息指针和位图信息大小赋值给全局变量 m_pDib = pDib; m_dwDibSize = dwDibSize; //获取位图信息头指针 m_pBIH = (BITMAPINFOHEADER *) m_pDib; //获取位图调色板指针 m_pPalette = (RGBQUAD *) &m_pDib[sizeof(BITMAPINFOHEADER)]; // 计算调色板中实际颜色数量 m_nPaletteEntries = 1 << m_pBIH->biBitCount;//1左移 if( m_pBIH->biBitCount > 8 ) { m_nPaletteEntries = 0; } else if( m_pBIH->biClrUsed != 0 ) { m_nPaletteEntries = m_pBIH->biClrUsed; } // 获取位图数据指针 m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER)+m_nPaletteEntries*sizeof(RGBQUAD)]; // 重置全局调色板 if( m_Palette.GetSafeHandle() != NULL ) { m_Palette.DeleteObject(); } //如果调色板颜色数量不为零,则通过逻辑调色板创建调色板 if( m_nPaletteEntries != 0 ){ //为逻辑调色板分配内存 LOGPALETTE *pLogPal = (LOGPALETTE *) new char [sizeof(LOGPALETTE)+ m_nPaletteEntries*sizeof(PALETTEENTRY)]; if( pLogPal != NULL ){ //设置逻辑调色板的版本 pLogPal->palVersion = 0x300; //设置逻辑调色板的颜色数量 pLogPal->palNumEntries = m_nPaletteEntries; //为每个颜色实体赋颜色值 for( int i=0; i<m_nPaletteEntries; i++ ){ pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed; pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen; pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue; } //创建调色板 m_Palette.CreatePalette( pLogPal ); //释放内存 delete [] pLogPal; } } //重绘 Invalidate(); }

2、保存位图

//保存图片 void CImageDisposeDlg::OnBtnsave() { // TODO: Add your control notification handler code here //文件路径名称 CString pszFilename; //浏览文件对话框 CFileDialog hFileDlg(FALSE,"bmp", NULL, OFN_FILEMUSTEXIST|OFN_READONLY|OFN_PATHMUSTEXIST|OFN_NOCHANGEDIR, TEXT("BMP (*.bmp)|*.bmp|所有文件(*.*)|*.*|"), NULL); if(hFileDlg.DoModal() == IDOK) { //获得文件路径名称 pszFilename=hFileDlg.GetPathName(); } // 如果位图信息为空则程序返回 if( m_pDib == NULL ) return; //文件类 CFile cf; // 创建文件 if( !cf.Open( pszFilename, CFile::modeCreate | CFile::modeWrite ) ) return; // 写入数据 try{ //创建位图文件头 BITMAPFILEHEADER BFH; memset( &BFH, 0, sizeof( BITMAPFILEHEADER ) ); BFH.bfType = 'MB'; BFH.bfSize = sizeof( BITMAPFILEHEADER ) + m_dwDibSize; BFH.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + m_nPaletteEntries * sizeof( RGBQUAD ); //将数据写入文件 cf.Write( &BFH, sizeof( BITMAPFILEHEADER ) ); cf.Write( m_pDib, m_dwDibSize ); } catch( CFileException *e ){ e->Delete(); return; } }

3、显示位图

void CImageDisposeDlg::OnPaint() { CPaintDC dc(this); //如果位图信息为空,程序返回 if( m_pDib == NULL ) return; //获得位图宽高 int nWidth,nHeight; nWidth = m_pBIH->biWidth; nHeight = m_pBIH->biHeight; //如果有调色板则使用调色板 if( m_Palette.GetSafeHandle() != NULL ) { CPalette *pOldPalette; pOldPalette = dc.SelectPalette( &m_Palette, FALSE );//选择调色板 dc.RealizePalette();//实现调色板 //绘图 StretchDIBits( dc.m_hDC, 0, 0, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO *) m_pBIH, BI_RGB, SRCCOPY ); //恢复调色板 dc.SelectPalette( pOldPalette, FALSE ); } else//没有调色板,直接绘制 { StretchDIBits( dc.m_hDC, 0, 0, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO *) m_pBIH, BI_RGB, SRCCOPY ); } }

你可能感兴趣的:(struct,null,BI,delete,byte,IM)