ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:19.72KB ,
资源ID:3689313      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3689313.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(位图结构.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

位图结构.docx

1、位图结构BMP文件结构的探索WhatIf 2004-9-10一、文件格式Bmp文件是非常常用的位图文件,无论是游戏还是其他都被广泛使用。针对bmp文件的处理也有一堆现成的api进行调用,然而文件内部究竟怎样,如何自己来解析这样的文件呢?为了消除无聊,我用了几天时间来研究了一下,同时作为学习笔记,进行记录。首先,整个bmp文件的内容可以分为3到4块。之所以分为3到4块而不是固定的值,是因为,对于bmp来说可能存在调色板或者一些掩码。具体稍候讨论。第一块是bmp的文件头用于描述整个bmp文件的情况。结构如下:typedef struct tagBITMAPFILEHEADER WORD bfTyp

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

3、下挑重要的数据进行解释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 bi

4、Compression; /本以为压缩类型,但是却另外有作用,稍候解释 DWORD biSizeImage; /表示位图数据区域的大小以字节为单位 LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; BITMAPINFOHEADER, *PBITMAPINFOHEADER; 第三块就是调色板信息或者掩码部分,如果是8位位图 则存放调色板 ;16 与32位 位图则存放RGB颜色的掩码,这些掩码以DWORD大小来存放。 最后一块就是位图的数据实体。 以上文件信息可以在任意一篇bmp文件

5、结构的文章中找到描述,所以本文只是稍微带过。二、4字节对其问题 关于数据读取。Bmp文件有个重要特性,那就是对于数据区域而言,每行的数据它必须凑满4字节,如果没有满,则用冗余的数据来补齐。这个特性直接影响到我们读取位图数据的方法,因为在我们看来 (x,y)的数据应该在 y*width+x这样的位置上 但是因为会有冗余信息 那么必须将width用width该行的冗余量来处理,而由于位图文件有不同的位数,所以这样的计算也不尽相同。 下面列出计算偏移量的一般公式。 首先将位图信息读入一个UCHAR 的buffer中 : 8位:int pitch; if(width%4=0) pitch=width;

6、 else pitch=width+4-width%4; index=buffery*pitch+x; 因为8位位图的数据区域存放的是调色板索引值,所以只需读取这个index 16位 int pitch=width+width%2; buffer(y*pitch+x)*2 buffer(i*pitch+j)*21两个UCHAR内,存放的是(x,y)处的颜色信息 24位 int pitch=width%4; buffer(y*width+x)*3+y*pitch; buffer(y*width+x)*3+y*pitch+1;buffer(y*width+x)*3+y*pitch+2; 32位 由

7、于一个象素就是4字节 所以无需补齐 虽然计算比较繁琐,但是这些计算是必须的,否则当你的位图每行的象素数不是4的倍数,那么y*width+x带给你的是一个扭曲的图片,当然如果你想做这样的旋转,也不错啊,至少我因为一开始没有考虑(不知道这个特性) 让一个每行象素少1字节的16位图片变成了扭曲的菱形。三、有了数据分离RGB分量。 由于我的测试代码用了GDI,所以我必须讲得到的某一个点的值 分离成 24位模式下的RGB分离,这不是一件容易的工作。位图麻烦的地方之一就是他的格式太多,所以我们还是要分格式再讨论。 8位 通过第二部分提到的操作我们得到了一个index,这个值的范围是0255 一共256个

8、正好是调色板的颜色数量。 在8位bmp图片中 数据信息前256个RGBQUAD的大小开始就是调色板的信息。不过如果要组织成调色板还要一定的转换 因为里面是RGBQUAD信息 r b 两个与调色板中的顺序是颠倒的。因为我不需要调色板设置所以我字节读取到RGBQUAD数组中,并且通过下面的表达式获取RGB值:UCHAR r=quadindex.rgbRed; UCHAR g=quadindex.rgbGreen; UCHAR b=quadindex.rgbBlue;16位这是最麻烦的一个。因为在处理时有555 565 两种格式的区别,而且还有所谓压缩类型的区别。之前的bitmapinfoheade

9、r里面提到一个biCompression现在我们分两种情况讨论:BI_RGB和BI_BITFIELDS当他等于BI_RGB时 只有555 这种格式,所以可以放心大胆的进行如下的数据分离:UCHAR b=buffer(i*pitch+j)*2&0x1F;UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25);UCHAR r=(buffer(i*pitch+j)*2+13;希望不要被这个表达式折磨的眼花缭乱,我想既然你在看这篇文章,你就有能力阅读这样的代码,否则只能说你还没有到阅读这方面的地步,需要去学习基础的语法了。有一点值得提醒的是由于有

10、较多的位操作 ,所以在处理的时候在前一次操作的上面加上一对括号,我就曾经因为没有加而导致出现误差,另外虽然buffer中一个元素代表的是一个UCHAR 但是右移操作会自动增长为两字节 所以需要在进行一次与操作截取低位的1字节数据。现在讨论BI_BITFIELDS。这个模式下 既可以有555 也可以有565 。555 格式 xrrrrrgggggbbbbb565 格式 rrrrrggggggbbbbb显然不同的格式处理不同,所以我们要首先判断处到底属于那种格式。Bitmapinfoheader的biCompression为BI_BITFIELDS时,在位图数据区域前存在一个RGB掩码的描述 是3

11、个DWORD值,我们只需要读取其中的R或者G的掩码,来判断是那种格式。以红色掩码为例 0111110000000000的时候就是555格式 1111100000000000就是565格式。以下是565格式时的数据分离:UCHAR b=buffer(i*pitch+j)*2&0x1F;UCHAR g=(buffer(i*pitch+j)*2+12)+(buffer(i*pitch+j)*25);UCHAR r=buffer(i*pitch+j)*2+13;现在我们得到了RGB各自的分量,但是还有一个新的问题,那就是由于两字节表示了3个颜色 555下每个颜色最多到0x1F 565格式下最大的绿色分

12、量也就0x3F。所以我们需要一个转换 color=color*255/最大颜色数 即可如565下RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F)24位UCHAR b=buffer(i*width+j)*3+realPitch;UCHAR g=buffer(i*width+j)*3+1+realPitch;UCHAR r=buffer(i*width+j)*3+2+realPitch; 32位UCHAR b=buffer(i*width+j)*4; UCHAR g=buffer(i*width+j)*4+1; UCHAR r=buffer(i*width+j)*4

13、+2;四、剩余的问题 当数据取到了,颜色也分离出来了 ,但是可能你绘出的位图是倒转的,这是因为有些位图的确是翻转的。通过bitmapinfoheader的biHeight可以判断是正常还是翻转,当biHeight0的时候颠倒,它小于0的时候正常,不过测试写到现在看到的文件都是颠倒过来的。五、相关测试代码: 采用MFC 目的只是实现自行解析位图文件void CBmpTestView:OnDraw(CDC* pDC) CBmpTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: 在此处为本机数据添加绘制代码 if(filename=)

14、 return; FILE *fp=fopen(filename,r); if(fp=NULL) pDC-TextOut(100,200,no file found); return; BITMAPFILEHEADER fileheader; BITMAPINFO info; fread(&fileheader,sizeof(fileheader),1,fp); if(fileheader.bfType!=0x4D42) pDC-TextOut(100,200,无位图文件 请选择位图文件); fclose(fp); return ; fread(&info.bmiHeader,sizeof(B

15、ITMAPINFOHEADER),1,fp); long width=info.bmiHeader.biWidth; long height=info.bmiHeader.biHeight; UCHAR *buffer=new UCHARinfo.bmiHeader.biSizeImage; fseek(fp,fileheader.bfOffBits,0); fread(buffer,info.bmiHeader.biSizeImage,1,fp); if(info.bmiHeader.biBitCount=8) int pitch; if(width%4=0) pitch=width; el

16、se pitch=width+4-width%4; RGBQUAD quad256; fseek(fp,fileheader.bfOffBits-sizeof(RGBQUAD)*256,0); fread(quad,sizeof(RGBQUAD)*256,1,fp); if(height0) /height0 表示图片颠倒 for(int i=0;iheight;i+) for(int j=0;jSetPixel(j,height-i,RGB(r,g,b); else for(int i=0;i0-height;i+) for(int j=0;jSetPixel(j,i,RGB(r,g,b);

17、 else if(info.bmiHeader.biBitCount=16) int pitch=width+width%2; if(height0) /height0 表示图片颠倒 if(info.bmiHeader.biCompression=BI_RGB) /该模式只有555 for(int i=0;iheight;i+) for(int j=0;jwidth;j+) /5 5 5 格式 UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(b

18、uffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB(r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F); else if(info.bmiHeader.biCompression=BI_BITFIELDS) /该模式在bitmapinfoheader之后存在RGB掩码 每个掩码1 DWORD fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0); DWORD rMask; fread(&rMask,sizeof(DWORD ),1,fp); if(rMask=0x7C

19、00) / 5 5 5 格式 MessageBeep(0); for(int i=0;iheight;i+) for(int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB(r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F); else if(rMask=0xF800) /5 6

20、5 格式 for(int i=0;iheight;i+) for(int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+12)+(buffer(i*pitch+j)*25); UCHAR r=buffer(i*pitch+j)*2+13; pDC-SetPixel(j,height-i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F); else if(info.bmiHeader.biCompression=BI_RGB) /该模式只有555 for(

21、int i=0;i0-height;i+) for(int j=0;jwidth;j+) /5 5 5 格式 UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buffer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,i,RGB(r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F); else if(info.bmiHeader.biCompression=BI_BITFIELDS) /该模式在b

22、itmapinfoheader之后存在RGB掩码 每个掩码1 DWORD fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0); DWORD rMask; fread(&rMask,sizeof(DWORD ),1,fp); if(rMask=0x7C00) / 5 5 5 格式 MessageBeep(0); for(int i=0;i0-height;i+) for(int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+13)+(buf

23、fer(i*pitch+j)*25); UCHAR r=(buffer(i*pitch+j)*2+13; pDC-SetPixel(j,i,RGB(r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F); else if(rMask=0xF800) /5 6 5 格式 for(int i=0;i0-height;i+) for(int j=0;jwidth;j+) UCHAR b=buffer(i*pitch+j)*2&0x1F; UCHAR g=(buffer(i*pitch+j)*2+12)+(buffer(i*pitch+j)*25); UCHAR r=buf

24、fer(i*pitch+j)*2+13; pDC-SetPixel(j,i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F); /pDC-TextOut(100,200,16位图); else if(info.bmiHeader.biBitCount=24) int pitch=width%4; /b g r if(height0) /height0 表示图片颠倒 for(int i=0;iheight;i+) int realPitch=i*pitch; for(int j=0;jSetPixel(j,height-i,RGB(r,g,b); else for

25、(int i=0;i0-height;i+) int realPitch=i*pitch; for(int j=0;jSetPixel(j,i,RGB(r,g,b); /pDC-TextOut(100,200,24位图); else if(info.bmiHeader.biBitCount=32) / b g r a if(height0) /height0 表示图片颠倒 for(int i=0;i0-height;i+) for(int j=0;jSetPixel(j,height-i,RGB(r,g,b); else for(int i=0;iheight;i+) for(int j=0;jSetPixel(j,i,RGB(r,g

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1