C語言讀取BMP檔案(同時支援Linux和Windows)
阿新 • • 發佈:2018-12-17
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; }