说到图片,位图(Bitmap)当然是最简单的,它Windows显示图片的基本格式,其文件扩展名为*.BMP。在Windows下,任何各式的图片文件(包括视频播放)都要转化为位图个时候才能显示出来,各种格式的图片文件也都是在位图格式的基础上采用不同的压缩算法生成的(Flash中使用了适量图,是按相同颜色区域存储的)。
一、下面我们来看看位图文件(*.BMP)的格式。
位图文件主要分为如下3个部分:
块名称
对应Windows结构体定义
大小(Byte)
文件信息头
BITMAPFILEHEADER
14
位图信息头
BITMAPINFOHEADER
40
RGB颜色阵列
BYTE*
由图像长宽尺寸决定
1、   文件信息头BITMAPFILEHEADER
结构体定义如下:
typedef struct tagBITMAPFILEHEADER { /* bmfh */
UINT bfType;  
DWORD bfSize; 
UINT bfReserved1; 
UINT bfReserved2; 
DWORD bfOffBits;
} BITMAPFILEHEADER;
其中:
bfType
说明文件的类型,该值必需是0x4D42,也就是字符'BM'。
bfSize
说明该位图文件的大小,用字节为单位
bfReserved1
保留,必须设置为0
bfReserved2
保留,必须设置为0
bfOffBits
说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
2、位图信息头BITMAPINFOHEADER
结构体定义如下:
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结构所需要的字数。
biWidth
说明图象的宽度,以象素为单位。
biHeight
说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。
biPlanes
为目标设备说明位面数,其值将总是被设为1。
biBitCount
说明比特数/象素,其值为1、4、8、16、24、或32。但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像。
biCompression
说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:BI_RGB。
biSizeImage
说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0。
biXPelsPerMeter
说明水平分辨率,用象素/米表示。
biYPelsPerMeter
说明垂直分辨率,用象素/米表示。
biClrUsed
说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。
biClrImportant
说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
3、RGB颜色阵列
有关RGB三色空间我想大家都很熟悉,这里我想说的是在Windows下,RGB颜色阵列存储的格式其实BGR。也就是说,对于24位的RGB位图像素数据格式是:
蓝色B值
绿色G值
红色R值
对于32位的RGB位图像素数据格式是:
蓝色B值
绿色G值
红色R值
透明通道A值
透明通道也称Alpha通道,该值是该像素点的透明属性,取值在0(全透明)到255(不透明)之间。对于24位的图像来说,因为没有Alpha通道,故整个图像都不透明。
二、搞清了文件格式,下一步我们要实现加载。
            加载文件的目的是要得到图片属性,以及RGB数据,然后可以将其绘制在DC上(GDI),或是生成纹理对象(3D:OpenGL/Direct3D)。这两种用途在数据处理上有点区别,我们主要按前一种用法讲,在和3D有不同的地方,我们再提出来。
1、加载文件头
            //Load the file header
            BITMAPFILEHEADER header;
            memset(&header, 0, sizeof(header));
            inf.read((char*)&header, sizeof(header));
            if(header.bfType != 0x4D42)
                        return false;
            这个很简单,没有什么好说的。
            2、加载位图信息头
            //Load the image information header
            BITMAPINFOHEADER infoheader;
            memset(&infoheader, 0, sizeof(infoheader));
            inf.read((char*)&infoheader, sizeof(infoheader));
            m_iImageWidth = infoheader.biWidth;
            m_iImageHeight = infoheader.biHeight;
            m_iBitsPerPixel = infoheader.biBitCount;
            这里我们得到了3各重要的图形属性:宽,高,以及每个像素颜色所占用的位数。
3、行对齐
由于Windows在进行行扫描的时候最小的单位为4个字节,所以当
图片宽 X 每个像素的字节数 != 4的整数倍
时要在每行的后面补上缺少的字节,以0填充(一般来说当图像宽度为2的幂时不需要对齐)。位图文件里的数据在写入的时候已经进行了行对齐,也就是说加载的时候不需要再做行对齐。但是这样一来图片数据的长度就不是:宽 X 高 X 每个像素的字节数  了,我们需要通过下面的方法计算正确的数据长度:
//Calculate the image data size
int iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel) + 31) >> 5) << 2;
m_iImageDataSize = iLineByteCnt * m_iImageHeight;
4、加载图片数据
对于24位和32位的位图文件,位图数据的偏移量为sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是说现在我们可以直接读取图像数据了。
            if(m_pImageData) delete []m_pImageData;
            m_pImageData = new unsigned char[m_iImageDataSize];
            inf.read((char*)m_pImageData, m_iImageDataSize);
如果你足够细心,就会发现内存m_pImageData里的数据的确是BGR格式,可以用个纯蓝色或者是纯红色的图片测试一下。
5、绘制
好了,数据和属性我们都有了,现在就可以拿来随便用了,就和吃馒头一样,爱粘白糖粘白糖,爱粘红糖粘红糖。下面是我的GDI绘制代码,仅作参考。
void CImage::DrawImage(HDC hdc, int iLeft, int iTop, int iWidth, int iHeight)
{
            if(!hdc || m_pImageData == NULL)
                        return;
            BITMAPINFO bmi;
            memset(&bmi, 0, sizeof(bmi));
            bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
            bmi.bmiHeader.biWidth = m_iImageWidth;
            bmi.bmiHeader.biHeight = m_iImageHeight;
            bmi.bmiHeader.biPlanes = 1;
            bmi.bmiHeader.biBitCount = m_iBitsPerPixel;
            bmi.bmiHeader.biCompression = BI_RGB;
            bmi.bmiHeader.biSizeImage = m_iImageDataSize;
            StretchDIBits(hdc, iLeft, iTop, iWidth, iHeight,
                                                0, 0, m_iImageWidth, m_iImageHeight,
                                                m_pImageData, &bmi, DIB_RGB_COLORS, SRCCOPY);
}
6、3D(OpenGL)的不同之处
如果你是想用刚才我们得到的数据生成纹理对象,那么你还要请出下面的问题。
首先,用来生成纹理的数据不需要对齐,也就是说不能在每行的后面加上对齐的字节。当然在OpenGL里要求纹理图片的尺寸为2的幂,所以这个问题实际上不存在;
其次,我们得到的图形数据格式是BGR(BGRA),所以在生成纹理的时候,需指定格式为GL_BGR_EXT(GL_BGRA_EXT);否则需要做BGR->RGB(BGRA->RGBA)的转化。

10、bitmap格式分析的更多相关文章

  1. bitmap格式分析(转)

    源:bitmap格式分析 参考:bitmap图像介绍 最近正在着手开发一个图片库,也就是实现对常见图片格式的度写操作.作为总结与积累,我会把这些图片格式以及加载的实现写在我的Blog上. 说到图片,位 ...

  2. bitmap格式分析

    位图(Bitmap)当然是最简单的,它Windows显示图片的基本格式,其文件扩展名为*.BMP.在Windows下,任何各式的图片文件(包括视频播放)都要转化为位图个时候才能显示出来,各种格式的图片 ...

  3. X264库直接压缩BITMAP格式数据

    最近帮朋友看了下X264压缩视频,主要参考了雷霄骅(leixiaohua1020)的专栏的开源代码: http://blog.csdn.net/leixiaohua1020/article/detai ...

  4. AAC 格式分析

    一直在做一个语音项目,到了测试阶段,近来不是很忙,想把之前做的内容整理一下. 关于AAC音频格式基本情况,可参考维基百科http://en.wikipedia.org/wiki/Advanced_Au ...

  5. AAC ADTS AAC LATM 格式分析

    http://blog.csdn.net/tx3344/article/details/7414543# 目录(?)[-] ADTS是个啥 ADTS内容及结构 将AAC打包成ADTS格式 1.ADTS ...

  6. .net下二进制序列化的格式分析[转]

    .net下二进制序列化的格式分析[转] -- 综合应用 (http://www.Host01.Com/article/Net/00020003/) --- .net下二进制序列化的格式分析 (http ...

  7. tcp、udp、ip、icmp报文格式分析

    TCP .UDP .IP. ICMP协议报文格式分析 Tcp报文格式: Wireshark抓包如图: 源端口/目的端口(16bit): 在TCP报文中包涵了源端口/目的端口,源端口标识了发送进程,目的 ...

  8. vsftp日志xferlog格式分析

    vsftp日志xferlog格式分析 [日期:2014-06-25] 来源:Linux社区  作者:Linux [字体:大 中 小]   1.开始vsftp记录日志.修改/etc/vsftpd/vsf ...

  9. (转)AAC ADTS格式分析

    1,ADTS是个啥ADTS全称是(Audio Data Transport Stream),是AAC的一种十分常见的传输格式记得第一做demux的时候,把AAC音频的ES流从FLV封装格式中抽出来送给 ...

随机推荐

  1. javafx style and cssFile

    public class EffectTest extends Application { public static void main(String[] args) { launch(args); ...

  2. AMD规范(RequireJS)、CMD规范(SeaJS)、CommonJS(BravoJS)规范的辨析

    首先,AMD,CMD,CommonJS都实现了文件模块化. 对于依赖的模块:AMD是提前执行:CMD是延迟执行: AMD是依赖前置,CMD是依赖就近: AMD官方解释:https://github.c ...

  3. 小米开源便签Notes-源码研究(0)-整体功能介绍(图文并茂)

    本周对小米开源文件管理器,做了整体的研究,大致弄清了源码的来龙去脉,剩下的就是重点研究几个活动的流程了. 讲解Android应用这种可视化的程序,感觉还是有图比较好,不然功能界面都不清楚,自己不好介绍 ...

  4. Chrome不能在网易网盘中上传文件的解决办法

    Chrome不能在网易网盘中上传文件的解决办法1. 安装 Adobe Flash Player PPAPI,设置flash插件 chrome://settings/content/flash,许可[* ...

  5. spring的BeanWrapper类的原理和使用方法

    转自:http://blog.sina.com.cn/s/blog_79ae79b30100t4hh.html 如果动态设置一个对象属性,可以借助Java的Reflection机制完成: Class ...

  6. JVM 基础知识(GC)

    几年前写过一篇关于JVM调优的文章,前段时间拿出来看了看,又添加了一些东西.突然发现,基础真的很重要.学习的过程是一个由表及里,再由里及表的过程,所谓的"温故而知新".而真正能走完 ...

  7. 将二级目录下的文件合并成一个文件的Python小脚本

    这个小程序的目的是将二级目录下的文件全部合并成一个文件(其实几级目录都可以,只要做少许改动) #coding:utf8 import sys, os def process(path): new_fi ...

  8. 洛谷 P2692 覆盖

    P2692 覆盖 题目背景 WSR的学校有B个男生和G个女生都来到一个巨大的操场上扫地. 题目描述 操场可以看成是N 行M 列的方格矩阵,如下图(1)是一个4 行5 列的方格矩阵.每个男生负责打扫一些 ...

  9. ontouch-控件添加ontouch监听事件

    1,代码public class CalculatorViewPager extends ViewPager {}中 package com.android.calculator2; import a ...

  10. 洛谷 P2969 [USACO09DEC]音符Music Notes

    P2969 [USACO09DEC]音符Music Notes 题目描述 FJ is going to teach his cows how to play a song. The song cons ...