标签:class += rom fbi std 保留 ade write map
BMP文件格式详解
-------------------------------------------------------------------------------------------------------
Lena

摘录百科:BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。
BMP文件存储的是原始的BGR数据,格式非常简单,研究数字图入门必备。因为数据没有经过任何压缩,所以BMP文件都比较大。
BMP文件格式
1. BITMAPFILEHEADER
typedef struct {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAP_FILE_HEADER;
WORD --> unsigned short
DWORD --> unsigned long (32位占4位,64位占8位)
|
变量名 |
大小(字节) |
作用 |
|
bfType |
2 |
文件标头BM |
|
bfSize |
4 |
整个文件大小 |
|
bfReserved1 |
2 |
保留 |
|
bfReserved2 |
2 |
保留 |
|
bfOffBits |
4 |
偏移,一般偏移长度是BITMAPFILEHEADER+BITMAPINFOHEADER,如果存在调色板则随着调色板长度变化 |
2.BITMAPINFOHEADER
typedef struct BITMAP_INFO_HEADER {
DWORD biSize;
int biWidth;
int biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAP_INFO_HEADER;
这里的int原来是long,64位下会出问题改了下。
|
变量名 |
大小(字节) |
作用 |
|
biSize |
4 |
sizeof(BITMAP_INFO_HEADER) |
|
biWidth |
4 |
宽度 |
|
biHeight |
4 |
高度 BMP文件图像是倒着存储的,所以如果biHeight>0表示图像是倒立的,如果biHeight<0表示图像是正的。 |
|
biPlanes |
2 |
颜色平面数 |
|
biBitCount |
2 |
位数(1,4,8,16,24,32) |
|
biCompression |
4 |
压缩 0 BI_RGB(BMP文件不压缩) 1 BI_RLE8 2 BI_RLE4 3 BI_BITFILELDS 4 BI_JPEG 5 BI_PNG |
|
biSizeImage |
4 |
图像数据大小 |
|
biXPelsPerMeter |
4 |
水平分辨率 |
|
biYPelsPerMeter |
4 |
垂直分辨率 |
|
biClrUsed |
4 |
实际使用的颜色索引数 |
|
biClrImportant |
4 |
对图像显示有重要影响的颜色索引的数目,如果是0表示都重要 |
3.调色板
调色板实际上是一种颜色索引表,因为常见的BMP文件都是24和32位的,而24和32位不需要调色板,所以这里不做过多研究。
4.图像数据
24位位图 --> bgr,bgr,bgr
32位位图 --> bgra,bgra,bgra
5.内存对齐
Windows默认是4字节对齐,如果不了解内存对齐可以研究一下,c语言sizeof(结构体)的大小。内存对齐的主要目的是为了加速,BMP文件也需要进行内存对齐处理,简单来说就是每一行的字节数%4==0,如果不足则由0补足。比如:一个24位BMP,宽度为99,那么他的图像部分字节数位 99 * 3 ==> 297 % 4 = 1,需要补3个字节0。
参考文章:
https://www.cnblogs.com/Matrix_Yao/archive/2009/12/02/1615295.html
/*****************************************************
BMP文件读写
hatsusakana@gmail.com
*****************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned short WORD;
typedef unsigned int DWORD;
#pragma pack(1)
typedef struct {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAP_FILE_HEADER;
typedef struct BITMAP_INFO_HEADER {
DWORD biSize;
int biWidth;
int biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAP_INFO_HEADER;
#pragma pack()
/**
* 32->24
*/
static void bmp_remove_aplpha (unsigned char *data, unsigned char *buf, size_t *size, size_t w, size_t h) {
size_t i = 0, j = 0, dst_fix = 0;
dst_fix = 4 - ((w * 24)>>3) & 3;
*size = ((((w * 24) + 31) >> 5) << 2) * h;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
memcpy(buf, data, 3);
data += 4;
buf += 3;
}
buf += dst_fix;
}
}
/**
* 倒转图像
*/
static void bmp_reverse (unsigned char *data, unsigned char *buf, size_t size, size_t w, size_t h) {
unsigned char *src = NULL;
int i = 0, j = 0, preline = 0;
preline = size / h;
for (i = 0, j = h - 1; j >= 0; i++, j--) {
src = data + j * preline;
memcpy(buf + i * preline, src, preline);
}
}
/**
* bmp_read
*
* 读取一个BMP文件
* 只支持24/32位,32位会转为24位,倒转的图像会摆正
*/
unsigned char *bmp_read (const char *path, size_t *size, size_t *w, size_t *h) {
FILE *fp = NULL;
BITMAP_FILE_HEADER file = {0};
BITMAP_INFO_HEADER info = {0};
unsigned char *data = NULL, *buf = NULL;
if (!path || *path == 0 || !size || !w || !h)
return NULL;
if (!(fp = fopen(path, "rb")))
return NULL;
if (fread(&file, 1, sizeof(BITMAP_FILE_HEADER), fp) != sizeof(BITMAP_FILE_HEADER)) {
fclose(fp);
return NULL;
}
if (fread(&info, 1, sizeof(BITMAP_INFO_HEADER), fp) != sizeof(BITMAP_INFO_HEADER)) {
fclose(fp);
return NULL;
}
//非BM开头
if (file.bfType != 0x4d42) {
fclose(fp);
return NULL;
}
//暂时只能支持24与32位
if (info.biBitCount != 24 && info.biBitCount != 32) {
fclose(fp);
return NULL;
}
if (info.biSizeImage == 0) {
info.biSizeImage = info.biWidth * abs(info.biHeight) * (info.biBitCount == 24 ? 3 : 4);
}
data = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
buf = (unsigned char *)malloc(sizeof(unsigned char) * info.biSizeImage);
if (!data || !buf) {
if (data) free(data);
if (buf) free(buf);
fclose(fp);
return NULL;
}
if (fread(data, 1, info.biSizeImage, fp) != info.biSizeImage) {
free(data);
free(buf);
fclose(fp);
return NULL;
}
fclose(fp);
*size = info.biSizeImage;
*w = info.biWidth;
*h = abs(info.biHeight);
//32转24
if (info.biBitCount == 32) {
bmp_remove_aplpha(data, buf, size, *w, *h);
memcpy(data, buf, *size);
}
//图像倒转
if (info.biHeight > 0) {
bmp_reverse(data, buf, *size, *w, *h);
memcpy(data, buf, *size);
}
free(buf);
return data;
}
/**
* bmp_write
*/
int bmp_write (unsigned char *data, size_t size, size_t w, size_t h, const char *path) {
FILE *fp = NULL;
BITMAP_FILE_HEADER file = {0};
BITMAP_INFO_HEADER info = {0};
unsigned char *src = NULL;
int hsrc = 0, preline = 0;
if (!data || size == 0 || w == 0 || h == 0 || !path || *path == 0)
return 0;
if (!(fp = fopen(path, "wb+")))
return 0;
file.bfType = 0x4d42;
file.bfSize = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER) + size;
file.bfReserved1 = 0;
file.bfReserved2 = 0;
file.bfOffBits = sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER);
info.biSize = sizeof(BITMAP_INFO_HEADER);
info.biWidth = w;
info.biHeight = h;
info.biPlanes = 1;
info.biBitCount = 24;
info.biCompression = 0L;
info.biSizeImage = size;
info.biXPelsPerMeter = 0;
info.biYPelsPerMeter = 0;
info.biClrUsed = 0;
info.biClrImportant = 0;
fwrite(&file, 1, sizeof(BITMAP_FILE_HEADER), fp);
fwrite(&info, 1, sizeof(BITMAP_INFO_HEADER), fp);
//倒转写入图像数据
preline = size / h;
for (hsrc = h - 1; hsrc >= 0; hsrc--) {
src = data + hsrc * preline;
fwrite(src, 1, preline, fp);
}
fclose(fp);
return 1;
}
int main (int argc, char *argv[]) {
unsigned char *data = NULL;
size_t size = 0, w = 0, h = 0;
data = bmp_read("1.bmp", &size, &w, &h);
bmp_write(data, size, w, h, "2.bmp");
return 1;
}
标签:class += rom fbi std 保留 ade write map
原文地址:https://www.cnblogs.com/hatsusakana/p/12643850.html