代碼演示簡單的BMP文件操作

這裏演示寫出。主要難點是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真彩色圖片:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章