王朝网络
分享
 
 
 

位图文件读写综述

王朝vc·作者佚名  2006-01-17
宽屏版  字体: |||超大  

位图文件读写综述

作者:吉林大学 胡卓玮

一、位图文件结构

位图文件头

位图信息

2.1 位图信息头

2.2 颜色表

位图数据

二、位图文件读写操作

类的声明

位图的读取

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

位图的显示

位图的存储

新位图的创建

其它问题

三、CFG_DIB的使用

下载本文配套代码

关于位图文件操作的资料很多。为了方便开发人员的工作,写下本文,介绍了位图文件结构,在此基础之上设计了通用类CFG_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位位图,每四个字节代表了一个像素。

二、位图文件读写操作

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

1、类的声明

class CFG_DIB : public CObject

{

public:

//默认构造函数

CFG_DIB();

//构造函数,根据图象宽和高,以及记录每个象素所需字节数来初始化

CFG_DIB(int width, int height, int nBitCounts);

virtual ~CFG_DIB();

public:

HBITMAP m_hBitmap;

LPBYTE m_lpDIBits;//DIB位的起始位置

LPBITMAPINFOHEADER m_lpBMPHdr;//BITMAPINFOHEADER信息

LPVOID m_lpvColorTable;//颜色表信息

HPALETTE m_hPalette;//条调色板

private:

DWORD m_dwImageSize;//非BITMAPINFOHEADER或BITMAPFILEHEADER的位

int m_nColorEntries;//颜色表项的个数

//显示参数

public:

CPoint m_Dest;//目的矩形域的左上角坐标

CSize m_DestSize;//显示矩形的宽度和高度

CPoint m_Src;//原矩形左下角坐标

CSize m_SrcSize;//原矩形宽度和高度

public:

void InitDestroy();//初始化变量

void ComputePaletteSize(int nBitCounts);//计算调色板大小

void ComputeImage();//计算图象大小

//从BMP文件中读入DIB信息

BOOL ReadFile(CFile* pFile);

//从BMP文件中读入DIB信息,与ReadFile不同的是使用CreateSection创建位图位

BOOL ReadSection(CFile* pFile, CDC* pDC = NULL);

//将DIB写入文件,保存成BMP图片格式

BOOL WriteFile(CFile* pFile);

//创建新的位图文件,根据参数width,height,nBitCounts分配内存空间

BOOL NewFile(int width, int height, int nBitCounts);

//关闭位图文件

BOOL CloseFile();

//显示位图

BOOL Display(CDC* pDC);

HBITMAP CreateBitmap(CDC* pDC);//用DIB创建DDB

HBITMAP CreateSection(CDC* pDC = NULL);//创建位图位数据,即象素数据

//如果DIB没有颜色表,可以用逻辑调色板

BOOL SetLogPalette(CDC* pDC);

//如果DIB有颜色表,可以创建系统调色板

BOOL SetWinPalette();

//把DIB对象的逻辑调色板选进设备环境里,然后实现调色板

UINT UseLogPalette(CDC* pDC);

//得到BitmapInfoHeader的大小,包含颜色表数据

int GetHeaderSize()

{

return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;

}

//得到图像的高度

int GetHeight()

{

if(m_lpBMPHdr == NULL) return 0;

return m_lpBMPHdr-biHeight;

}

//得到图像的宽度

int GetWidth()

{

if(m_lpBMPHdr == NULL) return 0;

return m_lpBMPHdr-biWidth;

}

//得到图像的大小

int GetImageSize()

{

return m_dwImageSize;

}

long GetLineBit();//得到一行的象素数

};

2、位图的读取。

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

方法1

m_lpDIBits = (LPBYTE) new char[m_dwImageSize];

方法2

m_hBitmap = ::CreateDIBSection(pDC-GetSafeHdc(),

(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,

(LPVOID*) &m_lpDIBits, NULL, 0);

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

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

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

ComputePaletteSize(m_lpBMPHdr-biBitCount);

SetWinPalette();在显示位图之前,设置调色板:if(m_hPalette != NULL) {

::SelectPalette(pDC-GetSafeHdc(), m_hPalette, TRUE);

}

4、位图的显示。

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

::StretchDIBits(pDC-GetSafeHdc(), m_Dest.x, m_Dest.y,

m_DestSize.cx, m_DestSize.cy,

m_Src.x, m_Src.y,

m_SrcSize.cx, m_SrcSize.cy,

m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr,

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补齐。

以下是处理的办法:DWORD dwBytes = ((DWORD) m_lpBMPHdr-biWidth * m_lpBMPHdr-biBitCount) / 32;

if(((DWORD) m_lpBMPHdr-biWidth * m_lpBMPHdr-biBitCount) % 32) {

dwBytes++;

}

dwBytes *= 4;

m_dwImageSize = dwBytes * m_lpBMPHdr-biHeight;

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

三、CFG_DIB的使用

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

#include "fg_dib.h"

CFG_DIB m_fgdib;

//new file

m_fgdib.NewFile(width, height, nbitnum);

//open file

CFile* pf;

pf = new CFile;

pf-Open(sFileName, CFile::modeRead);

m_fgdib.ReadFile(pf);

pf-Close();

delete pf;

//draw BMP

m_fgdib.m_Dest.x = 0;

m_fgdib.m_Dest.y = 0;

m_fgdib.m_DestSize.cx = m_fgdib.GetWidth();

m_fgdib.m_DestSize.cy = m_fgdib.GetHeight();

m_fgdib.m_Src.x = 0;

m_fgdib.m_Src.y = 0;

m_fgdib.m_SrcSize.cx = m_fgdib.GetWidth();

m_fgdib.m_SrcSize.cy = m_fgdib.GetHeight();

CDC* pDC = GetDC();

m_fgdib.Display(pDC);

//close BMP

m_fgdib.CloseFile();

如果您在阅读文章和使用代码过程中遇到的问题,请与作者联系:

吉林省长春市西民主大街6号地球探测科学与技术学院2001级硕士研究生(130026)

欢迎访问作者的主页:Forevergis.6to23.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有