音视频入门-03-RGB转成BMP图片
- 2019 年 10 月 3 日
- 筆記
BMP 文件格式解析
BMP 文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
位图文件头(14个字节) | 位图信息头(40个字节) | 颜色信息 | 图形数据 |
---|
- 文件头与信息头一共是 54 字节
- RGB 数据部分:
RGB24 文件存储的顺序是 RGB, RGB, RGB …… RGB
BMP 文件 RGB 数据存储的顺序是 BGR, BGR, BGR … BGR
位图文件头
位图文件头分 4 部分,共 14 字节
名称 | 占用空间 | 内容 | 示例数据 |
---|---|---|---|
bfType | 2字节 | 标识,就是“BM” | BM |
bfSize | 4字节 | 整个 BMP 文件的大小 | 0x000C0036(786486) |
bfReserved1 | 2字节 | 保留字 | 0 |
bfReserved2 | 2字节 | 保留字 | 0 |
bfOffBits | 4字节 | 偏移数,即位图文件头+位图信息头+调色板的大小 | 0x36(54) |
位图信息头
位图信息头共 40 字节
名称 | 占用空间 | 内容 | 示例数据 |
---|---|---|---|
biSize | 4字节 | 位图信息头的大小,为40 | 0x28(40) |
biWidth | 4字节 | 位图的宽度,单位是像素 | 0x200(512) |
biHeight | 4字节 | 位图的高度,单位是像素 | 0x200(512) |
biPlanes | 2字节 | 固定值1 | 1 |
biBitCount | 2字节 | 每个像素的位数 1-黑白图,4-16色,8-256色,24-真彩色,32-带 alpha 通道 | 0x18(24) |
biCompression | 4字节 | 压缩方式,BI_RGB(0)为不压缩 | 0 |
biSizeImage | 4字节 | 位图全部像素占用的字节数,BI_RGB时可设为0 | 0x0C |
biXPelsPerMeter | 4字节 | 水平分辨率(像素/米) | 0 |
biYPelsPerMeter | 4字节 | 垂直分辨率(像素/米) | 0 |
biClrUsed | 4字节 | 位图使用的颜色数 如果为0,则颜色数为2的biBitCount次方 | 0 |
biClrImportant | 4字节 | 重要的颜色数,0代表所有颜色都重要 | 0 |
将 RGB24 像素点数据转成 BMP 格式图片
转换代码:
#include <stdio.h> #include <stdlib.h> // 彩虹的七种颜色 u_int32_t rainbowColors[] = { 0XFF0000, // 红 0XFFA500, // 橙 0XFFFF00, // 黄 0X00FF00, // 绿 0X007FFF, // 青 0X0000FF, // 蓝 0X8B00FF // 紫 }; /*bmp file header*/ typedef struct { unsigned int bfSize; /* Size of file */ unsigned short bfReserved1; /* Reserved */ unsigned short bfReserved2; /* ... */ unsigned int bfOffBits; /* Offset to bitmap data */ } BitmapFileHeader; /*bmp info header*/ typedef struct { unsigned int biSize; /* Size of info header */ int biWidth; /* Width of image */ int biHeight; /* Height of image */ unsigned short biPlanes; /* Number of color planes */ unsigned short biBitCount; /* Number of bits per pixel */ unsigned int biCompression; /* Type of compression to use */ unsigned int biSizeImage; /* Size of image data */ int biXPelsPerMeter; /* X pixels per meter */ int biYPelsPerMeter; /* Y pixels per meter */ unsigned int biClrUsed; /* Number of colors used */ unsigned int biClrImportant; /* Number of important colors */ } BitmapInfoHeader; void writeRGBToBmp(char *filename, int width, int height) { FILE *bitmapFile = fopen(filename, "wb"); if(!bitmapFile) { printf("Could not write file n"); return; } uint16_t bfType = 0x4d42; BitmapFileHeader fileHeader; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfSize = 2 + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + width*height*3; fileHeader.bfOffBits = 0x36; BitmapInfoHeader infoHeader; infoHeader.biSize = sizeof(BitmapInfoHeader); infoHeader.biWidth = width; infoHeader.biHeight = height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biSizeImage = 0; infoHeader.biCompression = 0; infoHeader.biXPelsPerMeter = 5000; infoHeader.biYPelsPerMeter = 5000; infoHeader.biClrUsed = 0; infoHeader.biClrImportant = 0; fwrite(&bfType, sizeof(bfType), 1, bitmapFile); fwrite(&fileHeader, sizeof(fileHeader), 1, bitmapFile); fwrite(&infoHeader, sizeof(infoHeader), 1, bitmapFile); // 写入图像数据 for (int i = 0; i < width; ++i) { // 当前颜色 u_int32_t currentColor = rainbowColors[0]; if(i < 100) { currentColor = rainbowColors[0]; } else if(i < 200) { currentColor = rainbowColors[1]; } else if(i < 300) { currentColor = rainbowColors[2]; } else if(i < 400) { currentColor = rainbowColors[3]; } else if(i < 500) { currentColor = rainbowColors[4]; } else if(i < 600) { currentColor = rainbowColors[5]; } else if(i < 700) { currentColor = rainbowColors[6]; } // 当前颜色 R 分量 u_int8_t R = (currentColor & 0xFF0000) >> 16; // 当前颜色 G 分量 u_int8_t G = (currentColor & 0x00FF00) >> 8; // 当前颜色 B 分量 u_int8_t B = currentColor & 0x0000FF; for (int j = 0; j < height; ++j) { // 按 BGR 顺序写入一个像素 RGB24 到文件中 fwrite(&B, 1, 1, bitmapFile); fwrite(&G, 1, 1, bitmapFile); fwrite(&R, 1, 1, bitmapFile); } } // 关闭文件 fclose(bitmapFile); } int main() { writeRGBToBmp("/Users/staff/Desktop/rainbow-700x700.bmp", 700, 700); return 0; }
检查生成的 BMP 图片
Congratulations! 图片查看软件识别出我们的 BMP 图片了,预览正常!
BUT!好像哪里不对劲?!我们的彩虹倒过来了!
彩虹的颜色,从上到下应该是:
红 -> 橙 -> 黄 -> 绿 -> 青 -> 蓝 -> 紫
这张图是:
紫 -> 蓝 -> 青 -> 绿 -> 黄 -> 橙 -> 红
处理图片倒立问题
BitmapInfoHeader 中的 biHeight 字段,
biHeight 为正,位图自底向顶扫描,
biHeight 为负,位图自顶向底扫描。
如果这个值的设置和原始位图文件扫描方式不符,则图像显示可能会颠倒。
将上面的转换代码中,BitmapInfoHeader 部分:
// infoHeader.biHeight = height; infoHeader.biHeight = -height;
Congratulations!
成功用像素点拼出了一张 “真正” 的图片!
代码:
参考资料:
non-dword-aligned-pixel-to-dword-aligned-bitmap
generate-bmp-file-from-array-of-rgb-values
内容有误?联系作者: