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

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

python dict转换成json格式的实现

《pythondict转换成json格式的实现》本文主要介绍了pythondict转换成json格式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下... 一开始你变成字典格式data = [ { 'a' : 1, 'b' : 2, 'c编程' : 3,

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

Python实现PDF与多种图片格式之间互转(PNG, JPG, BMP, EMF, SVG)

《Python实现PDF与多种图片格式之间互转(PNG,JPG,BMP,EMF,SVG)》PDF和图片是我们日常生活和工作中常用的文件格式,有时候,我们可能需要将PDF和图片进行格式互转来满足... 目录一、介绍二、安装python库三、Python实现多种图片格式转PDF1、单张图片转换为PDF2、多张图

Java实现数据库图片上传与存储功能

《Java实现数据库图片上传与存储功能》在现代的Web开发中,上传图片并将其存储在数据库中是常见的需求之一,本文将介绍如何通过Java实现图片上传,存储到数据库的完整过程,希望对大家有所帮助... 目录1. 项目结构2. 数据库表设计3. 实现图片上传功能3.1 文件上传控制器3.2 图片上传服务4. 实现

C语言中的浮点数存储详解

《C语言中的浮点数存储详解》:本文主要介绍C语言中的浮点数存储详解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、首先明确一个概念2、接下来,讲解C语言中浮点型数存储的规则2.1、可以将上述公式分为两部分来看2.2、问:十进制小数0.5该如何存储?2.3 浮点

Python中Windows和macOS文件路径格式不一致的解决方法

《Python中Windows和macOS文件路径格式不一致的解决方法》在Python中,Windows和macOS的文件路径字符串格式不一致主要体现在路径分隔符上,这种差异可能导致跨平台代码在处理文... 目录方法 1:使用 os.path 模块方法 2:使用 pathlib 模块(推荐)方法 3:统一使

Java中使用注解校验手机号格式的详细指南

《Java中使用注解校验手机号格式的详细指南》在现代的Web应用开发中,数据校验是一个非常重要的环节,本文将详细介绍如何在Java中使用注解对手机号格式进行校验,感兴趣的小伙伴可以了解下... 目录1. 引言2. 数据校验的重要性3. Java中的数据校验框架4. 使用注解校验手机号格式4.1 @NotBl