浅析BMP位图文件结构(含Demo)

简介: 浅析BMP位图文件结构(含Demo)作者:一点一滴的Beer http://beer.cnblogs.com/     关于BMP位图格式在网上可以找到比较详细的相关文档,有兴趣的可以搜索标题为“BMP文件结构的探索”的文章,可以在搜索结果中找到一个WORD文档,里面有很详细的介绍。

浅析BMP位图文件结构(含Demo

作者:一点一滴的Beer http://beer.cnblogs.com/

 

    关于BMP位图格式在网上可以找到比较详细的相关文档,有兴趣的可以搜索标题为“BMP文件结构的探索”的文章,可以在搜索结果中找到一个WORD文档,里面有很详细的介绍。很感谢这个文档的作者(ID是WhatIf),总结得很详细而且还附有详细的应用代码(文档我会放在本文最后面的附件部分)。因为文档中写得很详细,所以我在此就结合自己写的程序示例来介绍下位图的主要结构,用兴趣的可以将附件文件下载下来,结合本节给的相关测试代码进行学习和研究。下面直接引用其描述:

 

    Bmp文件是非常常用的位图文件,无论是游戏还是其他都被广泛使用。针对bmp文件的处理也有一堆现成的api进行调用,然而文件内部究竟怎样,如何自己来解析这样的文件呢?为了消除无聊,我用了几天时间来研究了一下,同时作为学习笔记,进行记录。

    首先,整个bmp文件的内容可以分为3到4块。之所以分为3到4块而不是固定的值,是因为,对于bmp来说可能存在调色板或者一些掩码。具体稍候讨论。

    第一块是bmp的文件头用于描述整个bmp文件的情况。结构如下:

typedef  struct  tagBITMAPFILEHEADER {
   WORD     bfType;   
   DWORD    bfSize;
   WORD     bfReserved1;
   WORD     bfReserved2;
   DWORD    bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
 

    这些信息相当有用,如果你想直接来解析bmp文件。第一个bfType用于表示文件类型,如果它是bmp文件,那么它这个位置的值一定是”BM” 也就是0x4D42。第二个bfSize表示整个文件的字节数。第三第四个 则保留,目前无意义,最后一个相当重要,表示,位图的数据信息离文件头的偏移量,以字节为单位。

    第二块是位图信息头,即BITMAPINFOHEADER,用于描述整个位图文件的情况。以下挑重要的数据进行解释

typedef  struct  tagBITMAPINFOHEADER{
DWORD  biSize; //表示本结构的大小
LONG  biWidth; //位图的宽度
LONG  biHeight; //位图的高度
WORD  biPlanes; //永远为1 ,由于没有用过所以 没做研究 附msdn解释
//Specifies the number of planes for the target device. This value must be set to 1.
WORD  biBitCount; //位图的位数 分为1 4 8 16 24 32 本文没对1 4 进行研究
DWORD  biCompression; //本以为压缩类型,但是却另外有作用,稍候解释
DWORD  biSizeImage; //表示位图数据区域的大小以字节为单位
LONG  biXPelsPerMeter;
LONG  biYPelsPerMeter;
DWORD  biClrUsed;
DWORD  biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

    第三块就是调色板信息或者掩码部分,如果是8位位图 则存放调色板 ;16 与32位位图则存放RGB颜色的掩码,这些掩码以DWORD大小来存放。   

 最后一块就是位图的数据实体。

 

    通过上面网友的一段描述,可能大家和我一样,只是大概了解到位图作为一个文件的存在肯定不仅仅只是对每个像素进行简单地储存的,肯定会有一些附加的信息的。但是单单根据上面的描述,还是不够形象,所以,就用一个简单的例子来实验,帮助了解位图的结构。

实验:准备一张编码格式为RGB565的位图文件,分辨率是320*240。然后用VS2005建立C++程序对文件进行读取和分析。

开始实验:

    在Windows资源管理器中,把鼠标悬停在位图上方,可以看到系统提示的一些位图信息“尺寸:320×40 大小:151K”。这个是通过如下计算方式得到的:位图文件除去位图数据实体外的三个部分的大小在同一文件系统下都是一样的,都为14+46+2*3=66字节(自己可以查看这些结构体数据的详细定义然后自己验证),位图编码为RGB565,也就是说每个彩色像素点是用的2个字节表示,R/G/B三个分量分别用了5/6/5位表示,5+5+6为16,刚好是两个字节,所以位图数据实体大小为320*240*2/1024=150K,再加上前面的66字节,整个位图的大小就是150K到151K之间了,而根据Windows系统的磁盘分块存储原理(最后一块数据即使比单位存储块1K要小,也会占用一个1K的存储块),所以此文件实际占用的空间为151K。此位图的结构示意如下图:

    用VS2005建立C++项目,使用如下的测试代码:

void  ReadBmpDemo()
{
     CFile hFile;
     hFile.Open(L "recvBmpData565.bmp" ,CFile::modeRead); //以打开的形式读取文件
 
 
     //*******************************************
     //***------Step 1:读取文件信息头---------****
     //*******************************************
 
     BITMAPFILEHEADER *pFileHead = NULL; // 位图文件的头指针 
     DWORD    dwFileHeadSize = sizeof (BITMAPFILEHEADER); // 位图文件的头区域大小
     pFileHead=(BITMAPFILEHEADER*) malloc (dwFileHeadSize); //申请一片dwFileHeadSize字节大小的内存区
     hFile.Read(pFileHead,dwFileHeadSize); //从图片的文件当前位置读取一片内容:文件信息头
 
 
 
     //*******************************************
     //***------Step 2:读取位图信息头---------****
     //*******************************************  
     BITMAPINFOHEADER *pBmpInfoHeader=NULL;
     DWORD  dwBmpInfoHeadSize= sizeof (BITMAPINFOHEADER);
     pBmpInfoHeader=(BITMAPINFOHEADER*) malloc (dwBmpInfoHeadSize); //位图信息头
     hFile.Read(pBmpInfoHeader,dwBmpInfoHeadSize); //读入第二块数据块
 
     pBmpInfoHeader->biCompression  = BI_RGB; //RGB555格式---修改压缩信息
 
 
     //*****************************************************
     //***------Step 3:读取调色板信息或掩码部分---------****
     //*****************************************************
     RGBQUAD *pRgbQuad=NULL;
     DWORD  dwRgbQuadSize=3* sizeof (RGBQUAD); //本次实验的RGB565位图有三块掩码.
     pRgbQuad=(RGBQUAD*) malloc (dwRgbQuadSize);
     hFile.Read(pRgbQuad,dwRgbQuadSize);
 
 
     //*****************************************************
     //***------Step 4:读取位图的数据实体---------**********
     //*****************************************************
     BYTE  *pBmpData=NULL;
     //DWORD dwBmpDataSize=2*(pBmpInfoHeader->biWidth)*(pBmpInfoHeader->biHeight);//因为高度是负的,所以暂时不用此方法
     DWORD  dwBmpDataSize=(pFileHead->bfSize) - (pFileHead->bfOffBits); //文件头中的文件大小和数据实体偏移量之间的差
     pBmpData=( BYTE *) malloc (dwBmpDataSize); //申请一片指定字节大小的内存区.
     hFile.Read(pBmpData,dwBmpDataSize);
     hFile.Close();
 
     //**************************************************************
     //***------Step 5:将RGB565的数据实体转成RGB555---------*********
     //**************************************************************   
 
 
     //因为不涉及到本部分内容,所以没有实现
 
 
     //*******************************************
     //***------Step Final:释放动态内存区---------****
     //*******************************************  
 
 
 
     free (pFileHead);
     pFileHead=NULL;
 
     free (pBmpInfoHeader);
     pBmpInfoHeader=NULL;
 
     free (pRgbQuad);
     pRgbQuad=NULL;
 
     free (pBmpData);
     pBmpData=NULL;
     
}

 

     将准备的位图文件素材放到此项目的根目录下。然后断点调试,看运行的中间结果。

clip_image004

    位图文件头:从这里面了解到位图文件相关信息,文件类型为19778(即位图的文件类型编号:0x4D42),文件大小为153666,位图数据实体偏移文件头部66。

clip_image006

    位图信息头:从这个数据我们可以看到这个位图的相关信息,图片宽度为320,高度为240(当biHeight>0的时候位图是倒置的,它小于0的时候正常),位图的像素存储长度是16位(也就是RGB565的编码方式单像素点占用的长度),图片压缩类型为3(用来指示位图的编码方式是RGB565还是RGB555的,详细介绍可以查看WahtIf写的那个文章“BMP文件结构的探索”中的示例代码),位图数据实体大小为153600。

clip_image008

    位图的调色板或掩码部分:对于RGB565的位图,这里面是三个颜色分量的掩码,这个直接关系到此位图文件在Windows下的显示的效果。这三个数据在对位图进行颜色分量提取的时候有比较大的作用,在WahtIf写的那个文章“BMP文件结构的探索”中有示例代码。

clip_image010

    位图文件的数据实体部分:这里面以字节为单位存储着位图的每个个像素点的色彩信息,也是位图文件中数据的主体部分。此部分的数据长度在位图信息头中可以得到。

 

    总结:在了解了位图文件的存储结构后,后面对位图的一切操作和变换都是围绕着这些数据来进行的,到时候不会再看着一张数字图片而茫然不知所措了,而是可以根据自己的需求提取自己想要的信息了。

 

附件示例:

示例C++项目和RGB565图片素材一张:

WinXpBmpDemo.rar :http://files.cnblogs.com/beer/WinXpBmpDemo.rar

 

参考文章:

《BMP文件结构的探索》

http://blog.csdn.net/hollysky/archive/2005/04/12/345086.aspx

 

 

 

------------------------------------------------------------------

Author:一点一滴的Beer

Email /Gtalk:dreamzsm@gmail.com

From:http://www.cnblogs.com/beer

Notes:欢迎转贴,但请在页面中加个链接注明出处

Time:2010-11-21 in Whu

目录
相关文章
|
7天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
6天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
321 130
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
18天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1331 8
|
5天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
17天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1412 87
|
6天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
313 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
5天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
6天前
|
弹性计算 安全 数据安全/隐私保护
2025年阿里云域名备案流程(新手图文详细流程)
本文图文详解阿里云账号注册、服务器租赁、域名购买及备案全流程,涵盖企业实名认证、信息模板创建、域名备案提交与管局审核等关键步骤,助您快速完成网站上线前的准备工作。
254 82
2025年阿里云域名备案流程(新手图文详细流程)