这里演示写出。主要难点是BMP文件头的生成。标准的BMP文件头为54个字节,可采用结构体保存。
在保存文件头时,应当把编译器的对齐优化关掉,否则BM_Header结构体的长度会变成16。
程序的基本操作是先定义BM_Header和BM_Info文件头,检查运行环境是否正确,然后打开一个文件,先写出BM_Header和BM_Info文件头,再通过一个循环逐像素地以 [B, G, R] (蓝、绿、红,小头端)的顺序写出图像信息,直到把一个图像写完。
这段代码没有考虑比特填充,所以为了便于Windows快速存取,只支持(4×M, N)的分辨率。
参考资料:BMP文件格式详解(BMP file format)
https://www.cnblogs.com/Matrix_Yao/archive/2009/12/02/1615295.html
程序在C-Free 4.0,mingw2.95编译器下编译通过。
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#pragma pack(2) // 这行很重要,否则BM_Header的尺寸会因优化而出现错误
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define s8 int8_t
#define s16 int16_t
#define s32 int32_t
struct BM_Header
{
u8 bfType[2];
u32 bfSize;
u16 bfReserved1;
u16 bfReserved2;
u32 bfOffBits;
};
struct BM_Info
{
u32 biSize;
s32 biWidth;
s32 biHeight;
u16 biPlanes;
u16 biBitCount;
u32 biCompression;
u32 biSizeImage;
s32 biXPelsPerMeter;
s32 biYPelsPerMeter;
u32 biClrUsed;
u32 biClrImportant;
};
struct RGB_Pixel
{
u8 B;
u8 G;
u8 R;
};
struct BM_Header BH;
struct BM_Info BI;
struct RGB_Pixel RGB;
int Width = 800;
int Height = 600;
int BitDepth = 24;
FILE* fp;
void init_BM_Header()
{
BH.bfType[0] = 'B';
BH.bfType[1] = 'M';
BH.bfSize = Width * Height * (BitDepth / 8) + sizeof(BH) + sizeof(BI);
BH.bfReserved1 = 0;
BH.bfReserved2 = 0;
BH.bfOffBits = sizeof(BH) + sizeof(BI);
}
void init_BM_Info()
{
BI.biSize = sizeof(BI);
BI.biWidth = Width;
BI.biHeight = 0 - Height;
BI.biPlanes = 1;
BI.biBitCount = BitDepth;
BI.biCompression = 0;
BI.biSizeImage = Width * Height * (BitDepth / 8);
BI.biXPelsPerMeter = 2834;
BI.biYPelsPerMeter = 2834;
BI.biClrUsed = 0;
BI.biClrImportant = 0;
}
int check(const char* name, int value, int normal)
{
printf("%-14s == %-14d", name, value);
if(value == normal)
{
printf("[OK]\n");
return 1;
}
else
{
printf("[NG] (=> %d)\n", normal);
printf("[STOP] Bad value of `%s`, abort.\n", name);
exit(-1);
return 0;
}
}
void show_types()
{
check("sizeof(u8)", sizeof(u8), 1);
check("sizeof(u16)", sizeof(u16), 2);
check("sizeof(u32)", sizeof(u32), 4);
check("sizeof(s32)", sizeof(s32), 4);
check("sizeof(BH)", sizeof(BH), 14);
check("sizeof(BI)", sizeof(BI), 40);
check("sizeof(RGB)", sizeof(RGB), 3);
}
int main()
{
int i;
int j;
init_BM_Header();
init_BM_Info();
show_types();
printf("\n运行环境正常。正写出位图。\n");
printf("bfSize = %d\n", BH.bfSize);
fp = fopen("D:\\Test1.BMP", "wb+");
fwrite(&BH, sizeof(BH), 1, fp);
fwrite(&BI, sizeof(BI), 1, fp);
for(i=0;i<Height;i++)
{
for(j=0;j<Width;j++)
{
RGB.R = 255 - 255 * j * i / Width / Height;
RGB.G = 255 * j / Width;
RGB.B = 255 * i / Height;
fwrite((void *)(&RGB), sizeof(RGB), 1, fp);
}
}
check("ftell(fp)", ftell(fp), BH.bfSize);
fclose(fp);
printf("程序正常结束。\n");
return 0;
}
运行结果是生成一个800×600的24位RGB真彩色图片: