一、BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
2、位图信息头(40字节)
typedef struct /**** BMP file info structure ****/
{
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;
3、颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
typedef struct tagRGBQUAD{
BYTErgbBlue;//蓝色的亮度(值范围为0-255)
BYTErgbGreen;//绿色的亮度(值范围为0-255)
BYTErgbRed;//红色的亮度(值范围为0-255)
BYTErgbReserved;//保留,必须为0
} RGBQUAD;
颜色表中的RGBQUAD结构数据的个数由biBitCount来确定:当biBitCount=1,4,8时,分别为2,16,256个表项;当biBitCount=24时,没有颜色表项。
???RGBQUAD还不知道怎么用。
4、位图数据
位图 数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;
当biBitCount=32时,1个像素占3个字节,按顺序分别为B,G,R;
对应的,在通过ffmpeg获取位图数据的时候需要指定数据格式,这里以biBitCount=24和biBitCount=32为例子分别加以说明:
a. biBitCount=24
ffmpeg -i origin.png -s 128x128 -pix_fmt bgr24 origin.rgb
b. biBitCount=32
ffmpeg -i origin.png -s 128x128 -pix_fmt bgra origin.rgb
二、将rgb数据保存为bmp图片的方法
1.bgr24数据与bmp图片像素的对应关系(bgra据此类推)
bmp图片每个像素点按bgr24的格式存放颜色数据。
2.将bgr24数据保存成bmp图片的函数实现
void MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
/*
* Magic number for file. It does not fit in the header structure due to
* alignment requirements, so put it outside
* 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
* 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
*/
unsigned short bfType=0x4d42; //'BM'
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*3;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen(filename, "wb");
if (!file)
{
printf("Could not write file\n");
return;
}
/*Write headers*/
fwrite(&bfType,sizeof(bfType),1,file);
fwrite(&bfh,sizeof(bfh),1, file);
fwrite(&bih,sizeof(bih),1, file);
fwrite(rgbbuf,width*height*3,1,file);
fclose(file);
}
三.完整代码(将一个128 * 128的png文件转换成bmp文件,bgr24格式)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
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 MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
/*
* Magic number for file. It does not fit in the header structure due to
* alignment requirements, so put it outside
* 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
* 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
*/
unsigned short bfType=0x4d42; //'BM'
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*3;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bih.biSize = sizeof(BITMAPINFOHEADER);
printf("filesize = %u header size = %u \n", bfh.bfSize, bfh.bfOffBits);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen(filename, "w+");
if (!file)
{
printf("Could not write file\n");
return;
}
/*Write headers*/
fwrite(&bfType,sizeof(bfType),1,file);
fwrite(&bfh,sizeof(bfh),1, file);
fwrite(&bih,sizeof(bih),1, file);
fwrite(rgbbuf,width*height*3,1,file);
fclose(file);
}
int main(void)
{
unsigned int len = 0, i = 0;
unsigned char *dest = NULL;
unsigned char *dest2 = NULL;
int ret = 0;
dest = (char *)malloc(sizeof(unsigned char) * 3 * 128 * 128);
if(!dest) {
ret = -1;
goto fail;
}
dest2 = (char *)malloc(sizeof(unsigned char) * 3 * 128 * 128);
if(!dest2) {
ret = -1;
goto fail;
}
ret = system("ffmpeg -i origin.png -s 128x128 -pix_fmt bgr24 origin.rgb");
if(ret)
goto fail;
FILE *fp = fopen("origin.rgb", "r");
if(!fp) {
ret = 1;
goto fail;
}
ret = fseek(fp, 0, SEEK_END); //读写位置指针移动到文件尾
if(ret) {
ret = -1;
goto fail;
}
len = ftell(fp);
if(!len) {
ret = -1;
goto fail;
}
ret = fseek(fp, 0, SEEK_SET); //读写位置指针移动到文件头
if(ret) {
ret = -1;
goto fail;
}
len = fread(dest, sizeof(unsigned char), len, fp);
if(!len) {
ret = -1;
goto fail;
}
fclose(fp);
for(i = 0; i < 128; i++)
memcpy(&dest2[i * sizeof(unsigned char) * 3 * 128], &dest[(127-i) * sizeof(unsigned char) * 3 * 128], sizeof(unsigned char) * 3 * 128);
MySaveBmp("origin.bmp", dest2, 128, 128);
ret = system("rm -rf origin.rgb");
fail:
free(dest);
free(dest2);
return ret;
}
四.完整代码(将一个128 * 128的png文件转换成bmp文件,bgra格式)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
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 MySaveBmp(const char *filename,unsigned char *rgbbuf,int width,int height)
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
/*
* Magic number for file. It does not fit in the header structure due to
* alignment requirements, so put it outside
* 文件的魔术字,由于对齐的需要,没办法将魔术字作为BITMAPFILEHEADER的成员,所以
* 这里将魔术字放在BITMAPFILEHEADER开头外面的位置。
*/
unsigned short bfType=0x4d42; //'BM'
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2/* 2B魔术字 */+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+width*height*4;
bfh.bfOffBits = 2/* 2B魔术字 */ + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bih.biSize = sizeof(BITMAPINFOHEADER);
printf("filesize = %u header size = %u \n", bfh.bfSize, bfh.bfOffBits);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 32; //一个像素对应的32bit
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen(filename, "w+");
if (!file)
{
printf("Could not write file\n");
return;
}
/*Write headers*/
fwrite(&bfType,sizeof(bfType),1,file);
fwrite(&bfh,sizeof(bfh),1, file);
fwrite(&bih,sizeof(bih),1, file);
fwrite(rgbbuf,width*height*4,1,file);
fclose(file);
}
int main(void)
{
unsigned int len = 0, i = 0;
unsigned char *dest = NULL;
unsigned char *dest2 = NULL;
int ret = 0;
printf("unsigned int = %ld\n", sizeof(unsigned int));
printf("unsigned short = %ld\n", sizeof(unsigned short));
dest = (char *)malloc(sizeof(unsigned char) * 4 * 128 * 128);
if(!dest) {
ret = -1;
goto fail;
}
dest2 = (char *)malloc(sizeof(unsigned char) * 4 * 128 * 128);
if(!dest2) {
ret = -1;
goto fail;
}
ret = system("ffmpeg -i origin.png -s 128x128 -pix_fmt bgra origin.rgb");
if(ret)
goto fail;
FILE *fp = fopen("origin.rgb", "r");
if(!fp) {
ret = 1;
goto fail;
}
ret = fseek(fp, 0, SEEK_END); //读写位置指针移动到文件尾
if(ret) {
ret = -1;
goto fail;
}
len = ftell(fp);
if(!len) {
ret = -1;
goto fail;
}
ret = fseek(fp, 0, SEEK_SET); //读写位置指针移动到文件头
if(ret) {
ret = -1;
goto fail;
}
len = fread(dest, sizeof(unsigned char), len, fp);
if(!len) {
ret = -1;
goto fail;
}
printf("bgra file len= %u\n", len);
fclose(fp);
for(i = 0; i < 128; i++)
memcpy(&dest2[i * sizeof(unsigned char) * 4 * 128], &dest[(127-i) * sizeof(unsigned char) * 4 * 128], sizeof(unsigned char) * 4 * 128);
MySaveBmp("origin.bmp", dest2, 128, 128);
ret = system("rm -rf origin.rgb");
fail:
free(dest);
free(dest2);
return ret;
}