音视频入门-03-RGB转成BMP图片
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
内容有误?联系作者:

音视频入门-03-RGB转成BMP图片的更多相关文章
- 音视频入门-19-使用giflib处理GIF图片
* 音视频入门文章目录 * GIFLIB The GIFLIB project 上一篇 [手动生成一张GIF图片], 自己生成了一张 GIF 动态图 rainbow.gif. 下面,使用 GIFLIB ...
- 音视频入门-20-BMP、PNG、JPG、GIF静态图生成GIF动态图
* 音视频入门文章目录 * 静态图 -> 动态图 前面 [18-手动生成一张GIF图片] 和 [19-使用giflib处理GIF图片] 生成的 GIF 每一帧都是一个颜色,平时用到的 GIF 每 ...
- 音视频入门-01-认识RGB
* 音视频入门文章目录 * RGB 简介 RGB 色彩模式是工业界的一种颜色标准,是通过对红(R).绿(G).蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红 ...
- 音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合
* 音视频入门文章目录 * libyuv libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转.缩放等的库.它是跨平台的,可在 Windows.Linux.Mac.A ...
- 音视频入门-09-RGB&YUV互转-使用开源库
* 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...
- 音视频入门-08-RGB&YUV
* 音视频入门文章目录 * YUV & RGB 相互转换公式 YCbCr 的 Y 与 YUV 中的 Y 含义一致,Cb 和 Cr 与 UV 同样都指色彩,Cb 指蓝色色度,Cr 指红色色度,在 ...
- 音视频入门-05-RGB-TO-BMP使用开源库
* 音视频入门文章目录 * RGB-TO-BMP 回顾 将 RGB 数据转成 BMP 图片: 了解 BMP 文件格式 准备 BMP 文件头信息 准备 BMP 信息头 BMP 存储 RGB 的顺序是 B ...
- 音视频入门-04-BMP图像四字节对齐的问题
* 音视频入门文章目录 * BMP 图像四字节对齐 表示 BMP 位图中像素的位元是以行为单位对齐存储的,每一行的大小都向上取整为4字节(32 位 DWORD)的倍数.如果图像的高度大于 1,多个经过 ...
- 音视频入门-11-PNG文件格式详解
* 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...
随机推荐
- Vue学习手记02 - 路由
1.项目 注意:项目在初始化的时候没有安装vue-router就需要进行安装 2.安装路由: 在项目中使用ctrl+`, 打开终端, 执行如下命令 npm i vue-router -S 或者 cn ...
- Linux中 mkdir 创建文件夹命令
语法 mkdir (选项)(参数) 选项 -Z:设置安全上下文,当使用SELinux时有效: -m<目标属性>或--mode<目标属性>建立目录的同时设置目录的权限: -p或- ...
- Random Projection
Random Projection在k-means的应用 1. 随机投影 (Random Projection) 首先,这是一种降维方法.之前已经介绍过相对普遍的PCA的降维方法,这里介绍另一种降 ...
- linux内核中的__cpu_suspend是在哪里实现的呀?
1. 内核版本 4.19 2. 在arch/arm/kernel/sleep.S中实现如下: /* * Save CPU state for a suspend. This saves the CPU ...
- 基于Android的ADT目录
src: 源代码(重要) gen : 工具自动生成的代码 > BUildconfig 调试的开关,默认开启 > R.java 很多的静态的内部类 > 开发用的jar包 Android ...
- 开启windows ping端口功能
1.打开控制面板,选择程序 2.选择打开和关闭windows功能 3.将Tenet客户端选项勾上 4.运行栏中输入cmd,进入到命令窗口 5.输入命令 ping ip地址 端口号 ...
- $().attr() 和 $().css的区别
使用jquery的.attr( )方法去给div隐藏,这样写的 $("#div_id").attr("display","none"),发现 ...
- PAT 甲级 1044 Shopping in Mars (25 分)(滑动窗口,尺取法,也可二分)
1044 Shopping in Mars (25 分) Shopping in Mars is quite a different experience. The Mars people pay ...
- 执行spark-shell报错:
执行spark-shell报错: [ERROR] Terminal initialization failed; falling back to unsupportedjava.lang.NoClas ...
- 01.轮播图之三 : collectionView 轮播
个人觉得 collection view 做轮播是最方便的,设置下flowlayout 其他不会有很大的变动,没有什么逻辑的代码 let's begin…… 创建自定义的view .h 声明文件 @i ...