位图文件读写综述

位图文件读写综述 

 转自:http://www.vckbase.com/index.php/wv/475

一、位图文件结构

1.位图文件头

2.位图信息

2.1位图信息头

2.2 颜色表

2.位图数据

二、位图文件读写操作

1.类的声明

2.位图的读取

3.位图读取过程中的调色板的创建和调用

4.位图的显示

5.位图的存储

6.新位图的创建

7.其它问题

三、CFG_DIB的使用

关于位图文件操作的资料很多。为了方便开发人员的工作,写下本文,介绍了位图文件结构,在此基础之上设计了通用类CFG_DIB,用于进行位图文件的读写操作。

一、位图文件结构

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

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

1. typedefstruct tagBITMAPFILEHEADER {// bmfh
2.     WORD   bfType;
3.     DWORD  bfSize;
4.     WORD   bfReserved1;
5.     WORD   bfReserved2;
6.     DWORD  bfOffBits;
7. } BITMAPFILEHEADER;

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

2、位图信息中所记录的值用于分配内存,设置调色板信息,读取像素值等。

以下是位图信息结构的定义:

1. typedefstruct tagBITMAPINFO {
2.     BITMAPINFOHEADER    bmiHeader;
3.     RGBQUAD             bmiColors[1];
4. } BITMAPINFO;

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

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

01. typedefstruct tagBITMAPINFOHEADER{// bmih
02.     DWORD biSize;
03.     LONG  biWidth;
04.     LONG  biHeight;
05.     WORD  biPlanes;
06.     WORD  biBitCount
07.     DWORD biCompression;
08.     DWORD biSizeImage;
09.     LONG  biXPelsPerMeter;
10.     LONG  biYPelsPerMeter;
11.     DWORD biClrUsed;
12.     DWORD biClrImportant;
13. } 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 带调色板和不带调色板位图之间的区别

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

1. typedefstruct tagRGBQUAD { // rgbq
2.     BYTE   rgbBlue;
3.     BYTE   rgbGreen;
4.     BYTE   rgbRed;
5.     BYTE   rgbReserved;
6. } RGBQUAD;

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

3、位图数据。最后,在位图文件头、位图信息头、位图颜色表之后,便是位图的主体部分:位图数据。根据不同的位图,位图数据所占据的字节数也是不同的,比如,对于8位位图,每个字节代表了一个像素,对于16位位图,每两个字节代表了一个像素,对于24位位图,每三个字节代表了一个像素,对于32位位图,每四个字节代表了一个像素。 

二、位图文件读写操作

认识了位图文件的结构以后,对特定位图文件进行读写操作就显得简单了。本文附带的源代码中包含了一个能够方便进行位图读写操作的C++类。以下给出该类的使用参考,对于实现代码中的关键部分做出了讲解。

1、类的声明

01. classCFG_DIB : public CObject 
02. {
03. public:
04.     //默认构造函数
05.     CFG_DIB();
06.     //构造函数,根据图象宽和高,以及记录每个象素所需字节数来初始化
07.     CFG_DIB(intwidth, int height, int nBitCounts);
08.     virtual~CFG_DIB();
09.  
10. public:
11.     HBITMAPm_hBitmap;
12.     LPBYTEm_lpDIBits;                  //DIB位的起始位置
13.     LPBITMAPINFOHEADER m_lpBMPHdr;     //BITMAPINFOHEADER信息
14.     LPVOIDm_lpvColorTable;             //颜色表信息
15.     HPALETTEm_hPalette;                //条调色板
16.  
17. private:
18.     DWORDm_dwImageSize;                //非BITMAPINFOHEADER或BITMAPFILEHEADER的位
19.     intm_nColorEntries;                //颜色表项的个数
20.  
21. //显示参数
22. public:
23.     CPoint m_Dest;                     //目的矩形域的左上角坐标
24.     CSize m_DestSize;                  //显示矩形的宽度和高度
25.     CPoint m_Src;                      //原矩形左下角坐标
26.     CSize m_SrcSize;                   //原矩形宽度和高度
27.  
28. public:
29.     voidInitDestroy();                         //初始化变量
30.     voidComputePaletteSize(intnBitCounts);    //计算调色板大小
31.     voidComputeImage();                        //计算图象大小
32.  
33.     //从BMP文件中读入DIB信息
34.     BOOLReadFile(CFile* pFile);
35.     //从BMP文件中读入DIB信息,与ReadFile不同的是使用CreateSection创建位图位
36.     BOOLReadSection(CFile* pFile, CDC* pDC = NULL);
37.     //将DIB写入文件,保存成BMP图片格式
38.     BOOLWriteFile(CFile* pFile);
39.     //创建新的位图文件,根据参数width,height,nBitCounts分配内存空间
40.     BOOLNewFile(int width, int height, int nBitCounts);
41.     //关闭位图文件
42.     BOOLCloseFile();
43.  
44.     //显示位图
45.     BOOLDisplay(CDC* pDC);
46.  
47.     HBITMAPCreateBitmap(CDC* pDC);             //用DIB创建DDB
48.     HBITMAPCreateSection(CDC* pDC = NULL);     //创建位图位数据,即象素数据
49.     //如果DIB没有颜色表,可以用逻辑调色板
50.     BOOLSetLogPalette(CDC* pDC);
51.     //如果DIB有颜色表,可以创建系统调色板
52.     BOOLSetWinPalette();
53.     //把DIB对象的逻辑调色板选进设备环境里,然后实现调色板
54.     UINTUseLogPalette(CDC* pDC);
55.  
56.     //得到BitmapInfoHeader的大小,包含颜色表数据
57.     intGetHeaderSize()
58.     {
59.         returnsizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;
60.     }
61.     //得到图像的高度
62.     intGetHeight()
63.     {
64.         if(m_lpBMPHdr == NULL)return 0;
65.         returnm_lpBMPHdr->biHeight;
66.     }
67.     //得到图像的宽度
68.     intGetWidth()
69.     {
70.         if(m_lpBMPHdr == NULL)return 0;
71.         returnm_lpBMPHdr->biWidth;
72.     }
73.     //得到图像的大小
74.     intGetImageSize()
75.     {
76.         returnm_dwImageSize;
77.     }
78.     longGetLineBit();      //得到一行的象素数
79. };

2、位图的读取。

CFG_DIB提供了两个从位图文件读取位图数据的方法:ReadFile和ReadSection,二者不同之处,前者使用动态分配内存的方法初始化存储位位图数据的指针,后者则使用API函数,根据位图信息初始化存储位图数据的指针。

方法1

1. m_lpDIBits = (LPBYTE)new char[m_dwImageSize];

方法2

1. m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
2.          (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
3.          (LPVOID*) &m_lpDIBits, NULL, 0);

3、位图读取过程中的调色板的创建和调用。

关于调色板的详细情况,本文不作详细介绍,只是对读取位图的过程中需要调用的对调色板进行操作的相关函数进行说明。

读取文件的过程中,计算出调色板大小,然后调用创建调色板函数:

1. ComputePaletteSize(m_lpBMPHdr->biBitCount);
2. SetWinPalette();

在显示位图之前,设置调色板:

1. if(m_hPalette != NULL) {
2.      ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
3. }

4、位图的显示。

位图的显示还是调用Windows的API函数来进行,需要传递的参数包括当前位图信息头,位图数据等:

1. ::StretchDIBits(pDC->GetSafeHdc(), m_Dest.x, m_Dest.y,
2.                              m_DestSize.cx, m_DestSize.cy,
3.                              m_Src.x, m_Src.y,
4.                              m_SrcSize.cx, m_SrcSize.cy,
5.                              m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr,
6.                              DIB_RGB_COLORS, SRCCOPY);

其中的m_Dest,m_DestSize,m_Src,m_SrcSize分别代表了图像在当前设备上显示的左上角坐标和范围以及需要显示的源图像的左下角坐标和范围。此处需要说明的是,位图数据的字节数组是从图像的最下面一行开始逐行想上存储的,所以用户在选取源位图的现实范围的时候需要特别注意!

m_Dest,m_DestSize,m_Src,m_SrcSize需要在现实之前设置好。

5、位图的存储。位图的存储用WriteFile实现。

6、新位图的创建。新位图的创建由NewFile实现。需要的参数是位图的宽度、高度、以及位图像素占用的位数。

7、其它问题。存取位图数据的字节数组有个问题需要引起开发人员的注意:字节数组中每个扫描行的字节数必需是4的倍数,如果不足要用0补齐。

以下是处理的办法:

1. DWORDdwBytes = ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
2. if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32) {
3.      dwBytes++;
4. }
5. dwBytes *= 4;
6. m_dwImageSize = dwBytes * m_lpBMPHdr->biHeight;

这段代码按照要求算出了用于记录图像数据的字节数组的大小。

三、CFG_DIB的使用

以下是CFG_DIB的使用示例代码。

01. #include "fg_dib.h"
02.  
03. CFG_DIB m_fgdib;
04.  
05. //new file
06. m_fgdib.NewFile(width, height, nbitnum);
07.  
08. //open file
09. CFile* pf;
10. pf =new CFile;
11. pf->Open(sFileName, CFile::modeRead);
12. m_fgdib.ReadFile(pf);
13. pf->Close();
14. deletepf;
15.  
16. //draw BMP
17. m_fgdib.m_Dest.x = 0;
18. m_fgdib.m_Dest.y = 0;
19. m_fgdib.m_DestSize.cx = m_fgdib.GetWidth();
20. m_fgdib.m_DestSize.cy = m_fgdib.GetHeight();
21. m_fgdib.m_Src.x = 0;
22. m_fgdib.m_Src.y = 0;
23. m_fgdib.m_SrcSize.cx = m_fgdib.GetWidth();
24. m_fgdib.m_SrcSize.cy = m_fgdib.GetHeight();
25. CDC* pDC = GetDC();
26. m_fgdib.Display(pDC);
27.  
28. //close BMP
29. m_fgdib.CloseFile();
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值