bmp图片格式详解
bmp图片格式详解
1. BMP文件简介
BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。windows 3.0以前的BMP图文件格式与显示设备有关,因此把这种BMP图象文件格式称为设备相关位图DDB(device-dependent bitmap)文件格式。Windows 3.0以后的BMP图象文件与显示设备无关,因此把这种BMP图象文件格式称为设备无关位图dib(device-independent bitmap)格式,目的是为了让Windows能够在任何类型的显示设备上显示所存储的图象。BMP位图文件默认的文件扩展名是BMP或者bmp(有时它也会以.DIB或.rle作扩展名)。
2. android是如何识别BMP文件的
其实很简单,就是判断前面2个字节是什么,如果发现是BM开始,那就认为它是bmp图片。(注意此处识别的是ASCII码,’B’ ‘M’ 的ASCII码42 4D)
// SkImageDecoder_libbmp.cpp (external\skia\src\images)
static bool is_bmp(SkStream* stream) {
static const char kBmpMagic[] = { 'B', 'M' };//此处只有一种情况就是开始2个字节是BM
char buffer[sizeof(kBmpMagic)];
return stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
!memcmp(buffer, kBmpMagic, sizeof(kBmpMagic));
}
3. BMP图片格式详解
Bmp图片格式组成部分:bmp文件头(14 bytes) + 位图信息头(40 bytes) + 调色板(由颜色索引数决定) + 位图数据(由图像尺寸决定)
3.1 BMP图片的数据源
先打开一张bmp图片,查看其图片格式与信息。
图表 1 bmp图片详细信息
接着以2进制形式打开该图片,查看图片的2进制原始数据=>
图表 2 bmp图片2进制数据
我们就以上面bmp文件为例子,讲解我们接下去的内容。
3.2 BMP文件头
bmp文件头占14个字节
1) 前2 bytes(0,1)是’BM’(windows),’BA’(os/2 bitmap array),’CI’(os/2 color icon), ‘CP’(os/2 color pointer), ‘IC’(os/2 icon), ‘PT’(os/2 pointer)
如此处是:42 4D ,BM的ASCII也就是42 4D
2) 接下来4个字节(2-5)说明该位图文件的大小,用字节表示。(注意此处是位图文件大小不是图像大小,位图文件大小是指整个文件的大小(包含信息头等),图像大小是指图像数据的大小。4个字节最多可以表示4GB的图片大小)
例如此处:36 08 07 00 => 00 07 08 36 = 460854 = 450.052734375 kb(与实际的451 kb一致)
3) 接下来就是2个保留位,各占2个字节,一共4个字节的保留bytes,必须设置为0.
例如此处:(6-9) 00 00 00 00
4) 接下来4个字节是:文件头开始到实际图像数据之间的字节偏移量。
例如此处:(a-d) 36 00 00 00 => 36 = 54个字节
ps:我们一般见到的图像以24位图像为主,即R、G、B三种颜色各用8个bit来表示,这样的图像我们称为真彩色,这种情况下是不需要调色板的,也就是所位图信息头后面紧跟的就是位图数据了。因此,我们常常见到有这样一种说法:位图文件从文件头开始偏移54个字节就是位图数据了,这其实说的是24或32位图的情况。这也就解释了我们按照这种程序写出来的程序为什么对某些位图文件没用了
3.3 位图信息头
位图信息头40 byte
图表 3 位图信息头
1) 0xe-0x11:4个字节,位图信息头需要的字节数
例如此处:28 00 00 00 => 28 = 40个字节
2) 0x12-0x15:4个字节,图像宽度,以像素为单位
例如此处:40 01 00 00 => 01 40 = 320宽度
3) 0x16-0x19:4个字节,图像高度,以像素为单位(这个值除了用于描述图像高度之外,它还有另外一个用处,就是说明该位图是倒向位图还是正向位图,如果是正数则是倒向位图,如果是负数则是正向位图,大多数bmp图片都是倒向位图)
例如此处:E0 01 00 00 => 01 E0 = 480高度(倒向位图,说明图像数据是从图像左下角到右上角排列的)
4) 0x1a-0x1b:2个字节,为目标设备说明颜色平面数,其值将总被设为1.
例如此处:01 00 => 1
5) 0x1c-0x1d:2个字节,说明比特数/像素,其值为1、4、8、16、24、32
例如此处:18 00 => 24 说明其是RGB888的24位图(8位位图有256中颜色;24位位图有16777216种颜色,也就是1600万色)
6) 0x1e-0x21:4个字节,说明图像数据压缩类型。
取值范围:
0 => 不压缩(最常用)
1 => 8比特游程编码(RLE),只用于8位位图
2 => 4比特又称编码(RLE),只用于4位位图
3 => 比特域,用于16/32位位图
4 => 位图含JPEG图像(仅用于打印机)
5 => 位图含PNG图像(仅用于打印机)
例如此处:00 00 00 00 => 0 不压缩
7) 0x22-0x25:4个字节,说明图像大小,以字节为单位。当(0x1e-0x21)设置为0不压缩时,此处可以设置为0.
例如此处:00 08 07 00 => 07 08 00 = 460800 bytes = 450 kb, 此处比(0x2-0x5)位图文件的大小少了0x36 = 54个bytes,就是少了前面的信息头,仅包含数据。
8) 0x26-0x29:4个字节,说明水平分辨率,用像素/米表示,有符号整数。可以不设置,不设置时是0。
例如此处:00 00 00 00
9) 0x2a-0x2d:4个字节,说明垂直分辨率,用像素/米表示,有符号整数。可以不设置,不设置时是0。
例如此处:00 00 00 00
10) 0x2e-0x31:4个字节,说明位图时间使用的颜色表中的颜色索引数(设置为0的话,则说明使用所有的调色板项,一般与0x1c-0x1d使用的位图数相匹配,一般指多少种颜色)
例如此处:00 00 00 00
11) 0x32-0x35:4个字节,说明对图像显示有重要影响的颜色索引数码(设置为0的话,表示都重要)
例如此处:00 00 00 00
3.4 调色板
调色板的大小主要决定与0x2e-0x31的颜色索引数N。
调色板大小 = N*4 (因为每种颜色包含blue,green,red,alpha 4个字节的分量)此处我们一般都没有使用,所以就不细讲。
3.5 位图数据
1) 由于位图信息头中的位图高度是正的,所以位图数据在文件中的排列顺序是从左下角到右上角,以行为主序排列的。也就是第一个数据(此处指前3个bytes)是图像最后一行第一列像素色彩数据,第二个数据是图像最后一行第二列像素色彩数据。(有效信息从0x36-0x70835大小是0x70800,与0x22-0x25图像大小的值是一致的)
2) 如果RGB 24位位图则使用3个bytes存储一个像素,按照BGR顺序存储。如果是32位ARGB数据则按照BGRA的顺序存储。
例如下面android包含RGB和alpha的数据:
private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
Config config, boolean hasAlpha) {
……
if (config == Config.ARGB_8888 && !hasAlpha) {
nativeErase(bm.mNativeBitmap, 0xff000000);//一共32位,最前面2位是alpha分量,ff代表不透明
nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
……
}
至于为什么会反向存储,这个是由于计算机windows x86架构是小端系统,高字节存放在高地址里面。
3) 如果存在调色板,则这些值代表的是调色板的索引序号。