C言語でBMPファイルの読み書きを行う
bmpはBitMap(ビットマップ)の略称であり、すべてのwindows上の画像表示の基礎でもある.すべてのピクチャフォーマットは、最終的な表示を行うにはbmpに変換する必要があります.だから、bmpファイルの読み書きは、非常に重要になります.しかし,MFCクラス,C#ライブラリ関数,OpenCV,OpenGLなどのライブラリ関数を用いてbmpファイルの読み書きを行う人が多い.考えてみれば、DSPやFPGAなどの組み込み機器でbmpファイルの読み書きを行うには、膨大なMFC、Cクラスライブラリをインストールすることはできませんよね?実は、私たちはこれらの煩雑なクラスライブラリとAPI関数を完全に捨てることができて、C言語を利用して、いくつかの関数を書くだけで、bmpファイルの読み書きを完全に実現することができます.本文の意図はここにある.
完全なbmpビットマップファイルは、ファイル情報ヘッダ、ビットマップ情報ヘッダ、RGB色アレイの3つの部分に分けることができます(この3つの部分について詳しくは、私の別の文章を参照してください:http://blog.csdn.net/carson2005/article/details/6227047).ファイルヘッダには主に「BMPファイルかどうか」、ファイルのサイズなどの情報が含まれている.ビットマップ情報ヘッダには、主にbmpファイルのビットマップ幅、高さ、ビットプレーン、チャネル数などの情報が含まれています.RGB色のアレイには、私たちが必要とするbmpビットマップの画素データが含まれています.なお、bmpビットマップのカラーアレイ部分では、画素データの格納は左下隅を原点としている.すなわち、bmpピクチャを開いてパソコンの画面に表示すると、実際に記憶されているとき、このピクチャの左下隅の画素はまずbmpファイルに記憶されます.その後、左から右、下から上の順に画素データの記憶を順次行う.もし、3チャネルのビットマップデータを格納しています(つまり我々が一般的に言うカラーマップ)では、B 0 G 0 R 0 B 1 G 1 R 1 B 2 G 2 R 2…の順に記憶されているとともに、4バイト揃えの問題も考慮されている.OK、これらの基本概念を理解し、自分でプログラミングしてbmpファイルの読み書き関数を実現することは難しくないと信じている.ここで、C言語のバージョンを提供し、参考に供するだけで、間違いがあれば、指摘を歓迎する.
完全なbmpビットマップファイルは、ファイル情報ヘッダ、ビットマップ情報ヘッダ、RGB色アレイの3つの部分に分けることができます(この3つの部分について詳しくは、私の別の文章を参照してください:http://blog.csdn.net/carson2005/article/details/6227047).ファイルヘッダには主に「BMPファイルかどうか」、ファイルのサイズなどの情報が含まれている.ビットマップ情報ヘッダには、主にbmpファイルのビットマップ幅、高さ、ビットプレーン、チャネル数などの情報が含まれています.RGB色のアレイには、私たちが必要とするbmpビットマップの画素データが含まれています.なお、bmpビットマップのカラーアレイ部分では、画素データの格納は左下隅を原点としている.すなわち、bmpピクチャを開いてパソコンの画面に表示すると、実際に記憶されているとき、このピクチャの左下隅の画素はまずbmpファイルに記憶されます.その後、左から右、下から上の順に画素データの記憶を順次行う.もし、3チャネルのビットマップデータを格納しています(つまり我々が一般的に言うカラーマップ)では、B 0 G 0 R 0 B 1 G 1 R 1 B 2 G 2 R 2…の順に記憶されているとともに、4バイト揃えの問題も考慮されている.OK、これらの基本概念を理解し、自分でプログラミングしてbmpファイルの読み書き関数を実現することは難しくないと信じている.ここで、C言語のバージョンを提供し、参考に供するだけで、間違いがあれば、指摘を歓迎する.
chenLeeCV.h
#ifndef CHENLEECV_H
#define CHENLEECV_H
typedef struct
{
//unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} ClBitMapFileHeader;
typedef struct
{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} ClBitMapInfoHeader;
typedef struct
{
unsigned char rgbBlue; //
unsigned char rgbGreen; //
unsigned char rgbRed; //
unsigned char rgbReserved; //
} ClRgbQuad;
typedef struct
{
int width;
int height;
int channels;
unsigned char* imageData;
}ClImage;
ClImage* clLoadImage(char* path);
bool clSaveImage(char* path, ClImage* bmpImg);
#endif
chenLeeCV.cpp
#include "chenLeeCV.h"
#include <stdio.h>
#include <stdlib.h>
ClImage* clLoadImage(char* path)
{
ClImage* bmpImg;
FILE* pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int channels = 1;
int width = 0;
int height = 0;
int step = 0;
int offset = 0;
unsigned char pixVal;
ClRgbQuad* quad;
int i, j, k;
bmpImg = (ClImage*)malloc(sizeof(ClImage));
pFile = fopen(path, "rb");
if (!pFile)
{
free(bmpImg);
return NULL;
}
fread(&fileType, sizeof(unsigned short), 1, pFile);
if (fileType == 0x4D42)
{
//printf("bmp file!
");
fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
");
printf("bmp :
");
printf(" :%d
", bmpFileHeader.bfSize);
printf(" :%d
", bmpFileHeader.bfReserved1);
printf(" :%d
", bmpFileHeader.bfReserved2);
printf(" :%d
", bmpFileHeader.bfOffBits);*/
fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
");
printf("bmp
");
printf(" :%d
", bmpInfoHeader.biSize);
printf(" :%d
", bmpInfoHeader.biWidth);
printf(" :%d
", bmpInfoHeader.biHeight);
printf(" :%d
", bmpInfoHeader.biPlanes);
printf(" :%d
", bmpInfoHeader.biBitCount);
printf(" :%d
", bmpInfoHeader.biCompression);
printf(" :%d
", bmpInfoHeader.biSizeImage);
printf("X :%d
", bmpInfoHeader.biXPelsPerMeter);
printf("Y :%d
", bmpInfoHeader.biYPelsPerMeter);
printf(" :%d
", bmpInfoHeader.biClrUsed);
printf(" :%d
", bmpInfoHeader.biClrImportant);
printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
");*/
if (bmpInfoHeader.biBitCount == 8)
{
//printf(" ,
");
channels = 1;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
offset = (channels*width)%4;
if (offset != 0)
{
offset = 4 - offset;
}
//bmpImg->mat = kzCreateMat(height, width, 1, 0);
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 1;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);
step = channels*width;
quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);
fread(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad);
for (i=0; i<height; i++)
{
for (j=0; j<width; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height-1-i)*step+j] = pixVal;
}
if (offset != 0)
{
for (j=0; j<offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpInfoHeader.biBitCount == 24)
{
//printf("
");
channels = 3;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 3;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height);
step = channels*width;
offset = (channels*width)%4;
if (offset != 0)
{
offset = 4 - offset;
}
for (i=0; i<height; i++)
{
for (j=0; j<width; j++)
{
for (k=0; k<3; k++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height-1-i)*step+j*3+k] = pixVal;
}
//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
}
if (offset != 0)
{
for (j=0; j<offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
}
return bmpImg;
}
bool clSaveImage(char* path, ClImage* bmpImg)
{
FILE *pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int step;
int offset;
unsigned char pixVal = '\0';
int i, j;
ClRgbQuad* quad;
pFile = fopen(path, "wb");
if (!pFile)
{
return false;
}
fileType = 0x4D42;
fwrite(&fileType, sizeof(unsigned short), 1, pFile);
if (bmpImg->channels == 3)//24 , ,
{
step = bmpImg->channels*bmpImg->width;
offset = step%4;
if (offset != 4)
{
step += 4-offset;
}
bmpFileHeader.bfSize = bmpImg->height*step + 54;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height*step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
for (i=bmpImg->height-1; i>-1; i--)
{
for (j=0; j<bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+1];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i*bmpImg->width*3+j*3+2];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset!=0)
{
for (j=0; j<offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpImg->channels == 1)//8 , ,
{
step = bmpImg->width;
offset = step%4;
if (offset != 4)
{
step += 4-offset;
}
bmpFileHeader.bfSize = 54 + 256*4 + bmpImg->width;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54 + 256*4;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 8;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height*step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 256;
bmpInfoHeader.biClrImportant = 256;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256);
for (i=0; i<256; i++)
{
quad[i].rgbBlue = i;
quad[i].rgbGreen = i;
quad[i].rgbRed = i;
quad[i].rgbReserved = 0;
}
fwrite(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad);
for (i=bmpImg->height-1; i>-1; i--)
{
for (j=0; j<bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i*bmpImg->width+j];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset!=0)
{
for (j=0; j<offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
fclose(pFile);
return true;
}
Main.cpp
#include "stdafx.h"
#include "chenLeeCV.h"
int _tmain(int argc, _TCHAR* argv[])
{
ClImage* img = clLoadImage("c:/test.bmp");
bool flag = clSaveImage("c:/result.bmp", img);
if(flag)
{
printf("save ok...
");
}
while(1);
return 0;
}