张爱玲:人生是一袭华丽的袍子,里面爬满了虱子。 林世霖:BMP是一幅美丽的图画,里面爬满了算法。
平常接触的图像格式有很多种,其中BMP是windows系统的标准图像格式,BMP没有像jpeg那样的压缩比,因此他通常很臃肿,不适合用在网络间传输,但他是微软的亲生子,因此在计算机世界也大行其道,颇有影响力。
宽泛来说,BMP图像是支持压缩的,他甚至支持jpeg压缩算法,但更一般的情况是,BMP用来存储所谓的真彩色影像,即24位的BitMap(位图),本文并不想刨BMP的祖坟,将它所有的细节抽丝剥茧一一展现,本文只想针对其最常见 的存储模式做个总结,备忘。
先来看BMP格式图像的文件总体结构:
从上到下,分别是三个结构体,代码表示如下(重要的成员已标注为红色):
struct header { int16_t type; int32_t size; // 图像文件大小 int16_t reserved1; int16_t reserved2; int32_t offbits; // bmp图像数据偏移量 }__attribute__((packed)); struct info { int32_t size; // 本结构大小 int32_t width; // 图像宽度(单位像素) int32_t height; // 图像高度(单位像素) int16_t planes; // 总为零 int16_t bit_count; // 色深 int32_t compression; // 是否压缩 int32_t size_img; int32_t X_pel; int32_t Y_pel; int32_t clrused; int32_t clrImportant; }__attribute__((packed)); struct quad { int8_t blue; int8_t green; int8_t red; int8_t reserved; }__attribute__((packed)); 看代码总是很无聊的,尤其是看不懂的代码!但是如果真要处理BMP图像数据,那就必须搞清楚以上代码了,挑几个重点说一下:
第一,定义了这三个结构体之后,一定要使用__attribute__((packed));来去除系统的地址对齐,否则读到的格式头会发生错误。
第二,header.size就是图像文件的大小(即文件总大小减去格式头大小)。
第三,header.offbits就是格式头的大小(可能是前两个结构体,也可能是三个结构体,因为第三个结构体quad可能有也可能没有)
第四,info.compression决定了格式头中是否含有quad结构体。
最后,要正确处理BMP图像还必须牢记在心的几个要点:
1,图像每一行所包含的字节数,必须是4的倍数,如果不够则会凑齐补足到够为止。比如某BMP图像色深为24bits,宽度为65像素,算下来一行的字节数是65乘以3等于195个字节,那在文件中将会增加一个额外的字节凑够196个字节来表示一行的数据量。
2,最后一行数据是图像的第一行,换句话说BMP是反着存储的。因此在读取BMP图像时一般从最后一行开始读取,然后读倒数第二行,以此类推,然后将读取到的数据依次刷新到显存,这样才能正确显示图像,否则图片看起来是反的。
附一张刷BMP图的代码:
1,bmpfile是需要显示的BMP图片名称
2,FB是显存指针
3,vinfo是LCD参数结构信息
4,xoffset和yoffet是图片要显示的位置坐标