BMP位图文件的存储格式

2024-02-10 06:18
文章标签 存储 格式 bmp 位图文件

本文主要是介绍BMP位图文件的存储格式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘  要:本文简单介绍了位图文件的两种存储格式,并且在VC++6.0下实现了读取位图文件中的数据,用SetPixel()函数在窗口中重现图像,最后在程序中实现了一种存储格式到另一种存储格式的转换。

关键字:BMP、灰度位图、24位真彩色位图、存储格式

一、前言

BMP(Bitmap的缩写)图像是指文件名后缀为BMP的位图图像。位图图像在计算机中使用很广泛,例如在windows中,记事本、写字板中的文字就是用位图图像表示出来的。许多以其它格式存储的图像,就是在位图图像的基础上,进行优化处理后得到的,例如JPEG图像等。

    在数字图像处理中,许多算法就是针对24位真彩色位图或灰度位图设计的。因此,很有必要介绍一下位图文件的这两种存储格式。

二、24位真彩色图像存储格式

把下图的24位真彩色图像格式在16位编辑器(例如VC编辑器)中打开,可以看到图像的二进制数据。


 

24位真彩色的二进制数据为:


    这是24位真彩色位图文件数据一部分。这一部分数据包括位图文件头、位图信息头和位图阵列三部分。

    (一)位图文件头

    位图文件头用来记录标志文件大小的一些信息,在文件中占14个字节,存储的内容如下:

字节
 
 1
 2
 3
 4
 5
 6
 7
 8
 
 9
 10
 11
 12
 13
 14
 
000000
 
 42
 4D
 CC
 B4
 02
 00
 00
 00
 
 00
 00
 36
 00
 00
 00
 

其中:

42 4D          为位图的标志,即ASCII码为BM

CC B4 02        表示位图文件的总字节数,换算成十进制为(02B4CC)H=(177356)10,即这副图像的大小为177356字节。

00 00 00 00 00 为保留字节,用来存储文件大小的数据。

36 00 00 00 00 表示位图阵列的起始位置,(36)H=(54)10即54字节开始为位图阵列。

(二) 位图信息头

位图信息头记录和位图相关的一些信息,在文件中占40个字节,存储的内容如下:

字节
 
 1
 2
 3
 4
 5
 6
 7
 8
 
 9
 10
 11
 12
 13
 14
 15
 16
 
000000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 28
 00
 
000016
 
 00
 00
 2C
 01
 00
 00
 C5
 00
 
 00
 00
 01
 00
 18
 00
 00
 00
 
000032
 
 00
 00
 00
 00
 00
 00
 12
 0B
 
 00
 00
 12
 0B
 00
 00
 00
 00
 
000048
 
 00
 00
 00
 00
 00
 00
 
 
 
 
 
 
 
 
 
 
 
 

其中:

28 00 00 00  表示信息头的长度,(28)H=(40)10,即位图信息头占40个字节。

2C 01 00 00   表示位图宽度,单位为像素。(012C)H=(300)10,即位图的宽度为300个像素。

C5 00 00 00  表示位图高度,单位为像素。(C5)H=(197)10,即位图的宽度为197个像素。

01 00        表示位图设备级别

18 00        位图级别,(0018)H=(24)10,即24位真彩色。

00 00 00 00  表示压缩类型,为零表示不压缩。

00 00 00 00  保留字节。

12 0B 00 00  表示水平分辨率

12 0B 00 00  表示垂直分辨率

00 00 00 00  表示位图实际使用的颜色表中的颜色变址数。

00 00 00 00  表示位图显示过程中被认为重要颜色变址数。

(三)位图像素阵列

    剩下的部分为位图像素阵列,即像素表示部分,每个象素点由3个字节的数据组成,按照从左到右的顺序,分别表示蓝色、绿色、红色。

    在VC++中的wingdi.h中对于位图的编码和格式有更加详细的定义,下面给出24位真彩色位图格式在VC++中的定义。

typedef struct tagBITMAPFILEHEADER {//位图文件头

WORD bfType; //位图标志“BM”

DWORD bfSize; //位图文件总字节数

WORD bfReserved1;

WORD bfReserved2;

DWORD bfOffBits;

} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{ //位图信息头格式定义

DWORD biSize; //位图信息头占用字节数

LONG biWidth; //位图图像宽度(以像素为单位)

LONG biHeight; //位图图像高度(以像素为单位)

WORD biPlanes; //位图设备级别

WORD biBitCount //位图级别设定,每个像素所需的位数,必须是1(双色),
                // 4(16色),8(256色)或24(真彩色)之一

DWORD biCompression; //压缩类型

DWORD biSizeImage; //位图阵列表字节数

LONG biXPelsPerMeter; //水平分辨率

LONG biYPelsPerMeter; //垂直分辨率

DWORD biClrUsed; //位图实际使用的颜色表中的颜色变址数

DWORD biClrImportant; //位图显示过程中被认为重要颜色变址数

} BITMAPINFOHEADER;

typedef struct tagRGBTRIPLE { //位图阵列格式定义

BYTE rgbtBlue; //定义蓝色

BYTE rgbtGreen; //定义绿色

BYTE rgbtRed; //定义红色

} RGBTRIPLE;//构成一个3字节的RGBTRIPLE。

按照这个这个结构可以从BMP文件中读取数据,然后在屏幕上用SetPixel()函数描绘出来。主要代码如下:

if (!cf.Open(TransValue,CFile::modeRead, &e))//找到文件后,打开文件

{

    MessageBox("Can not open the file!","Open File");

    return;

}

cf.SeekToBegin();

cf.Read(&bmfh,sizeof(bmfh));//读取文件头

cf.Read(&bmih,sizeof(bmih));//读取文件信息头

rgb = new RGBTRIPLE[bmih.biWidth*bmih.biHeight];

cf.SeekToBegin();

cf.Seek(54,CFile::begin);

//读取文件数据

if (cf.GetLength()>64*1024)

{

    cf.ReadHuge(rgb,bmih.biWidth*bmih.biHeight*3);//

}

else

{

    cf.Read(rgb,bmih.biWidth*bmih.biHeight);

}

//在屏幕上打点显示图像

for (int i=0; i<bmih.biHeight;i++)

{

    for (int j=0; j<bmih.biWidth; j++)

    {

    pDC->SetPixel(j,bmih.biHeight-i,RGB(rgb[i*bmih.biWidth+j].rgbtRed,rgb[i*bmih.biWidth+j].rgbtGreen,rgb[i*bmih.biWidth+j].rgbtBlue));

    }

}

cf.Close();//关闭文件

delete rgb;//释放内存

三、灰度位图存储格式

同样,把下面的灰度位图在VC编辑器中以Binary方式打开,可以看到如下的数据(部分):


灰度位图数据:


    从上述数据中可以看出,灰度位图的存储格式与24位真彩色位图的存储格式基本相同。唯一的差别是,灰度位图比24位真彩色位图增加了一部分:颜色索引表。因此,灰度位图的像素阵列的起始位置不是第(36)H=(54)10个字节,而是第(436)H=(1078)10个字节,同时灰度位图用一个字节来表示一个像素。这样,灰度位图的像素阵列小了三分之二。

    颜色索引表定义为:

typedef struct rgbn
{
BYTE red;
BYTE green;
BYTE blue;
BYTE null;
} RGBn;
在实际的编程中,读取数据的方式发生了变化,除了要读取文件头,文件信息头外,还要设置变量读取颜色索引表。除此以外,灰度图像的编程读取显示方式与24位真彩色位图的方式完全相同,在此就不再描述。

从上述灰度位图和24位真彩色位图的存储结构中可以看出,把24位真彩色位图的颜色信息去掉,就可以得到灰度位图。根据不同的需要,不同的理论,有不同的去掉颜色的方法。在本文中,仅仅在红、绿、蓝三种基本色前加权三分之一,然后在屏幕上打点显示出来,得到灰度位图图像。如果需要存储,只需要在文件头、文件信息头后加上颜色索引表,然后再以一个字节的空间存储位图像素信息,把上述信息按顺序写到一个文件中,就得到一个灰度位图图像文件。  

这篇关于BMP位图文件的存储格式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/696343

相关文章

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C#中DateTime的格式符的实现示例

《C#中DateTime的格式符的实现示例》本文介绍了C#中DateTime格式符的使用方法,分为预定义格式和自定义格式两类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值... 目录DateTime的格式符1.核心概念2.预定义格式(快捷方案,直接复用)3.自定义格式(灵活可控

使用C#导出Excel数据并保存多种格式的完整示例

《使用C#导出Excel数据并保存多种格式的完整示例》在现代企业信息化管理中,Excel已经成为最常用的数据存储和分析工具,从员工信息表、销售数据报表到财务分析表,几乎所有部门都离不开Excel,本文... 目录引言1. 安装 Spire.XLS2. 创建工作簿和填充数据3. 保存为不同格式4. 效果展示5

MySQL中存储过程(procedure)的使用及说明

《MySQL中存储过程(procedure)的使用及说明》存储过程是预先定义的SQL语句集合,可在数据库中重复调用,它们提供事务性、高效性和安全性,MySQL和Java中均可创建和调用存储过程,示例展... 目录概念示例1示例2总结概念存储过程:在数据库中预先定义好一组SQL语句,可以被程序反复调用。

MySQL存储过程实践(in、out、inout)

《MySQL存储过程实践(in、out、inout)》文章介绍了数据库中的存储过程,包括其定义、优缺点、性能调校与撰写,以及创建和调用方法,还详细说明了存储过程的参数类型,包括IN、OUT和INOUT... 目录简述存储过程存储过程的优缺点优点缺点存储过程的创建和调用mysql 存储过程中的关键语法案例存储

使用python生成固定格式序号的方法详解

《使用python生成固定格式序号的方法详解》这篇文章主要为大家详细介绍了如何使用python生成固定格式序号,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... 目录生成结果验证完整生成代码扩展说明1. 保存到文本文件2. 转换为jsON格式3. 处理特殊序号格式(如带圈数字)4

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

k8s搭建nfs共享存储实践

《k8s搭建nfs共享存储实践》本文介绍NFS服务端搭建与客户端配置,涵盖安装工具、目录设置及服务启动,随后讲解K8S中NFS动态存储部署,包括创建命名空间、ServiceAccount、RBAC权限... 目录1. NFS搭建1.1 部署NFS服务端1.1.1 下载nfs-utils和rpcbind1.1

Redis高性能Key-Value存储与缓存利器常见解决方案

《Redis高性能Key-Value存储与缓存利器常见解决方案》Redis是高性能内存Key-Value存储系统,支持丰富数据类型与持久化方案(RDB/AOF),本文给大家介绍Redis高性能Key-... 目录Redis:高性能Key-Value存储与缓存利器什么是Redis?为什么选择Redis?Red

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结