weidagang2046的专栏

物格而后知致
随笔 - 8, 文章 - 409, 评论 - 57, 引用 - 0
数据加载中……

位图文件读写综述

位图文件读写综述
作者: 吉林大学 胡卓玮

一、位图文件结构

  1. 位图文件头
  2. 位图信息
    2.1 位图信息头
    2.2 颜色表
  3. 位图数据

二、位图文件读写操作

  1. 类的声明
  2. 位图的读取
  3. 位图读取过程中的调色板的创建和调用
  4. 位图的显示
  5. 位图的存储
  6. 新位图的创建
  7. 其它问题

三、 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);                      // 创建位图位数据,即象素数据

            //