1. 程式人生 > >C語言讀取BMP檔案(同時支援Linux和Windows)

C語言讀取BMP檔案(同時支援Linux和Windows)

C語言讀取BMP檔案最關鍵的是要理解結構體對齊。一般情況下,C語言的結構體在記憶體中會按照4位元組(32位)或者8位元組(64位)對齊。BMP檔案的資料頭結構體按照位元組排列,而且不能對齊,所以需要用預編譯巨集設定不能對齊。

另外注意Linux下一般用UTF-8編碼,但是Windows下用GB2312,所以如果使用中文註釋會造成亂碼,在Windows下有奇怪的錯誤,因此跨平臺儘量避免中文註釋。

在Windows中,控制對齊的方法是:

#pragma pack(push,1)
#pragma pack(pop)

而在Linux的GCC中,控制對齊的方法是

typedef struct RGB_tag
{
	char B;
	char G;
	char R;
} __attribute__((packed)) RGB_t;

所以在結構體定義方面需要分開寫

bmptool.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef int int32_t;

#ifdef __GNUC__
typedef struct bmp_file_header_tag
{
	uint8_t type[2];
	uint32_t file_size;
	uint16_t resv1;
	uint16_t resv2;
	uint32_t data_offset; 
} __attribute__((packed)) bmp_file_header_t;

typedef struct bmp_info_tag
{
	uint32_t info_size;		// 40
	uint32_t width;			
	uint32_t height;
	uint16_t plane; 		// 1
	uint16_t bit_count; 	// 24, no palette
	uint32_t compression;	// 0
	uint32_t data_size;
	uint32_t x_res;			// 0
	uint32_t y_res; 		// 0
	uint32_t clr_used;		// 0
	uint32_t clr_important; // 0
} __attribute__((packed)) bmp_info_t;

typedef struct RGB_tag
{
	char B;
	char G;
	char R;
} __attribute__((packed)) RGB_t;

typedef struct RGBQUAD_tag
{ 
	char rgbBlue;
	char rgbGreen; 
	char rgbRed; 
	char rgbReserved;
}  RGBQUAD; 
#endif 

#ifdef _MSC_VER

#pragma pack(push,1)
typedef struct bmp_file_header_tag
{
	uint8_t type[2];   //0,1
	uint32_t file_size;//2,3,4,5
	uint16_t resv1;    //6,7
	uint16_t resv2;    //8,9
	uint32_t data_offset; //10,11,12,13
} bmp_file_header_t;

typedef struct bmp_info_tag
{
	uint32_t info_size;		// 40
	uint32_t width;			
	uint32_t height;
	uint16_t plane; 		// 1
	uint16_t bit_count; 	// 24, no palette
	uint32_t compression;	// 0
	uint32_t data_size;
	uint32_t x_res;			// 0
	uint32_t y_res; 		// 0
	uint32_t clr_used;		// 0
	uint32_t clr_important; // 0
} bmp_info_t;

typedef struct RGB_tag
{
	char B;
	char G;
	char R;
} RGB_t;

typedef struct RGBQUAD_tag
{ 
	char rgbBlue;
	char rgbGreen; 
	char rgbRed; 
	char rgbReserved;
}  RGBQUAD; 
#pragma pack(pop)
#endif

bmptool.c


int ReadBmp(char* bmpfile, int* width, int* height, int* bit, char* pBmpBuf)
{
	bmp_info_t head; 
	int bmpWidth;
	int bmpHeight;
	int biBitCount;
	int lineByte;
	int i = 0;
	FILE *fp=fopen(bmpfile,"rb");  
	if(fp==0) 
		return 0;
	//printf("size is %d\n", sizeof(bmp_file_header_t));
	fseek(fp, sizeof(bmp_file_header_t),0);  
	fread(&head, sizeof(bmp_info_t), 1,fp);    
	bmpWidth = head.width;  
	bmpHeight = head.height;  
	biBitCount = head.bit_count;    
	lineByte=(bmpWidth * biBitCount/8+3)/4*4;  
	if(biBitCount==8)
	{  
		RGBQUAD pColorTable[256] = {0};
		fread(pColorTable,sizeof(RGBQUAD),256,fp);  
	}  
	for(i = 0; i < bmpHeight; i++)
		fread(pBmpBuf+i*bmpWidth, 1, lineByte, fp);
  
	fclose(fp);  
	*width = bmpWidth;
	*height = bmpHeight;
	*bit = biBitCount;
  
	return 1; 
}

void CreateBmp(char* bytes, int width, int height, int bit, char* filename)
{
	int i, j;
	uint8_t pad[4] = { 0 };
	int count = bit / 8;
	int width2 = width * count;
	int width_new = (width*count+3)/4*4;
	int image_size = width_new * height;
	int header_size = sizeof(bmp_file_header_t) + sizeof(bmp_info_t);
	FILE* fp = NULL;
	
	bmp_file_header_t header = { 'B','M', image_size + header_size, 0, 0, header_size};
	bmp_info_t info = {sizeof(bmp_info_t), width, height, 1, bit, 0, image_size, 0,0, 0,0};
	RGBQUAD pColorTable[256] = {0};
	if (bit == 8)
	{
		header.file_size += 1024;
		header.data_offset += 1024;
	}
	fp = fopen(filename, "wb");
	fwrite(&header, sizeof(bmp_file_header_t), 1, fp);
	fwrite(&info, sizeof(bmp_info_t), 1, fp);
	if (bit == 8)
	{
		for (i = 0; i < 256; i++)
			memset(&pColorTable[i], i, sizeof(RGBQUAD));
		fwrite(pColorTable, 256*sizeof(RGBQUAD), 1, fp);
	}
	
	for (i = 0; i < height; i++)
	{
		fwrite(bytes + i*width2, 1, width2, fp);
		fwrite(&pad, 1, width_new-width2, fp);
	}
	
	fclose(fp);
}

void RGB2Gray(char* im, int width, int height)
{
	int i,j;
	int size = width * height;
	for (i = 0; i < size; i++)
		im[i] = (im[3*i] + im[3*i+1] + im[3*i+2])/3;
}