c言語はbmp形式のピクチャの作成と読み取りを実現する(24ビットカラーフォーマットのみ)
bmpピクチャファイルフォーマットといえば、ネット上で簡単に検索できますが、ここでは説明しません.本稿では、bmpピクチャファイル操作のコードを共有することを目的としています.なお、以下のコードは、24ビットカラー(すなわち、3バイトの1画素)またはその解像度以上のピクチャファイルフォーマットのみをサポートする.
他の言うことはすべてコード注釈の中にあります.直接コードをつけます.
bmp.c
bmp.h
main.c
コンパイル
他の言うことはすべてコード注釈の中にあります.直接コードをつけます.
bmp.c
#include
#include
#include
#include
//
#define Bmp_FileHeader_Size 14 // sizeof(Bmp_FileHeader)
typedef struct{
uint8_t bfType[2]; // : "BM"/bmp, "BA"/.. , ...
uint32_t bfSize; //
uint16_t bfReserved1; // : 0
uint16_t bfReserved2; // : 0
uint32_t bfOffbits; //
}Bmp_FileHeader;
//
#define Bmp_Info_Size 40
typedef struct{
uint32_t biSize; //
uint32_t biWidth; // ,
int32_t biHeight; // , ( )
uint16_t biPlanes; // , 1
uint16_t biBitCount; // : 1, 4, 8, 16, 24, 42
uint32_t biCompression; // : 0/BI_BGB ,
// 1/BI_RLE8 8 , 8
// 2/BI_RLE4 4 , 4
// 3/BI_BITFIELDS , 16/32
// 4/BI_JPEG jpeg ,
// 5/BI_PWG pwg ,
uint32_t biSizeImage; // , BI_BGB 0
int32_t biXPelsPerMeter;// , / ,
int32_t biYPelsPerMeter;// , / ,
uint32_t biClrUsed; // ( 0 )
uint32_t biClrImportant;//
}Bmp_Info;
// : bmp
// : filePath: ,
// picMaxSize: ,
// width: ,
// height: ,
// per: ,
// : ( , )
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per)
{
FILE *fp;
Bmp_FileHeader bf;
Bmp_Info bi;
int perW, perWCount;
int ret;
int i, j, picCount, totalSize;
int overLineBytesNum;
unsigned int overLineBytesSum; // overLineBytesNum : 0 // 4 , 0,
unsigned char buffHeader[512], *data, *pic;
//
if(filePath == NULL)
return NULL;
//
if((fp = fopen(filePath, "rb")) < 0)
{
printf("bmp_get : open file %s failed\r
", filePath);
return NULL;
}
//Bmp_FileHeader
if(fread(buffHeader, 1, Bmp_FileHeader_Size, fp) <= 0)
{
printf("bmp_get : read Bmp_FileHeader failed\r
");
fclose(fp);
return NULL;
}
bf.bfType[0] = buffHeader[0]; bf.bfType[1] = buffHeader[1];
bf.bfSize = buffHeader[2] + ((buffHeader[3]&0xFF)<<8) + ((buffHeader[4]&0xFF)<<16) + ((buffHeader[5]&0xFF)<<24);
bf.bfOffbits = buffHeader[10] + ((buffHeader[11]&0xFF)<<8) + ((buffHeader[12]&0xFF)<<16) + ((buffHeader[13]&0xFF)<<24);
//printf("bmp_get : bfType/%s, bfSize/%d, bfOffbits/%d\r
", bf.bfType, bf.bfSize, bf.bfOffbits);
if(bf.bfType[0] != 'B' || bf.bfType[1] != 'M')
{
printf("bmp_get : bmp type err, bfType must be \"BM\"\r
");
fclose(fp);
return NULL;
}
//Bmp_Info
if(bf.bfOffbits - Bmp_FileHeader_Size < Bmp_Info_Size || fread(buffHeader, 1, Bmp_Info_Size, fp) <= 0)
{
printf("bmp_get : read Bmp_Info failed\r
");
fclose(fp);
return NULL;
}
bi.biSize = buffHeader[0] + ((buffHeader[1]&0xFF)<<8) + ((buffHeader[2]&0xFF)<<16) + ((buffHeader[3]&0xFF)<<24);
bi.biWidth = buffHeader[4] + ((buffHeader[5]&0xFF)<<8) + ((buffHeader[6]&0xFF)<<16) + ((buffHeader[7]&0xFF)<<24);
bi.biHeight = buffHeader[8] | ((buffHeader[9]&0xFF)<<8) | ((buffHeader[10]&0xFF)<<16) | ((buffHeader[11]&0xFF)<<24);
bi.biPlanes = buffHeader[12] + ((buffHeader[13]&0xFF)<<8);
bi.biBitCount = buffHeader[14] + ((buffHeader[15]&0xFF)<<8);
bi.biCompression = buffHeader[16] + ((buffHeader[17]&0xFF)<<8) + ((buffHeader[18]&0xFF)<<16) + ((buffHeader[19]&0xFF)<<24);
bi.biSizeImage = buffHeader[20] + ((buffHeader[21]&0xFF)<<8) + ((buffHeader[22]&0xFF)<<16) + ((buffHeader[23]&0xFF)<<24);
bi.biXPelsPerMeter = buffHeader[24] | ((buffHeader[25]&0xFF)<<8) | ((buffHeader[26]&0xFF)<<16) | ((buffHeader[27]&0xFF)<<24);
bi.biYPelsPerMeter = buffHeader[28] | ((buffHeader[29]&0xFF)<<8) | ((buffHeader[30]&0xFF)<<16) | ((buffHeader[31]&0xFF)<<24);
bi.biClrUsed = buffHeader[32] + ((buffHeader[33]&0xFF)<<8) + ((buffHeader[34]&0xFF)<<16) + ((buffHeader[35]&0xFF)<<24);
bi.biClrImportant = buffHeader[36] + ((buffHeader[37]&0xFF)<<8) + ((buffHeader[38]&0xFF)<<16) + ((buffHeader[39]&0xFF)<<24);
//perW
if(bi.biBitCount >= 8)
perW = bi.biBitCount/8;
else
perW = 1;
//
//totalSize = bf.bfSize - bf.bfOffbits;
//
overLineBytesNum = 4- bi.biWidth*(bi.biBitCount/8)%4;
if(overLineBytesNum == 4)
overLineBytesNum = 0;
if(bi.biHeight < 0)
{
totalSize = bi.biWidth*(-bi.biHeight)*(bi.biBitCount/8);
overLineBytesSum = overLineBytesNum*(-bi.biHeight);
}else
{
totalSize = bi.biWidth*bi.biHeight*(bi.biBitCount/8);
overLineBytesSum = overLineBytesNum*bi.biHeight;
}
//printf("bmp_get : biSize/%d, biWidth/%d, biHeight/%d, biPlanes/%d, biBitCount/%d, biCompression/%d, biSizeImage/%d, biXPelsPerMeter/%d, biYPelsPerMeter/%d, biClrUsed/%d, biClrImportant/%d, overLineBytesNum/%d, overLineBytesSum/%d, totalSize/%d\r
", bi.biSize, bi.biWidth, bi.biHeight, bi.biPlanes, bi.biBitCount, bi.biCompression, bi.biSizeImage, bi.biXPelsPerMeter, bi.biYPelsPerMeter, bi.biClrUsed, bi.biClrImportant, overLineBytesNum, overLineBytesSum, totalSize);
//
if(fseek(fp, bf.bfOffbits, 0) < 0)
{
printf("bmp_get : lseek failed\r
");
fclose(fp);
return NULL;
}
//
data = (unsigned char *)calloc(1, totalSize + overLineBytesSum + perW); // 1 ,
if((ret = fread(data, 1, totalSize + overLineBytesSum, fp)) != (totalSize + overLineBytesSum))
{
if(ret <= 0)
{
printf("bmp_get : read data failed\r
");
free(data);
fclose(fp);
return NULL;
}
}
//close
fclose(fp);
//
pic = (unsigned char *)calloc(1, totalSize);
memset(pic, 0, totalSize);
//
if(bi.biHeight > 0) // // + +
{
for(i = 0, picCount = totalSize; i < totalSize + overLineBytesSum && picCount >= 0; )
{
picCount -= bi.biWidth*perW;
for(j = 0, perWCount = perW - 1; j < bi.biWidth*perW && i < totalSize + overLineBytesSum && picCount >= 0; j++)
{
pic[picCount + perWCount] = data[i++];
if(--perWCount < 0)
perWCount = perW - 1;
if(perWCount == perW - 1)
picCount += perW;
}
picCount -= bi.biWidth*perW;
i += overLineBytesNum;
}
}
else // //
{
for(i = 0, j = 0, picCount = 0, perWCount = perW - 1; i < totalSize + overLineBytesSum && picCount < totalSize; )
{
pic[picCount + perWCount] = data[i++];
if(--perWCount < 0)
perWCount = perW - 1;
if(perWCount == perW - 1)
picCount += perW;
if(++j == bi.biWidth*perW)
{
j = 0;
i += overLineBytesNum;
}
}
}
//free
free(data);
// , ,
if(picMaxSize)
*picMaxSize = totalSize;
if(width)
*width = bi.biWidth;
if(height)
{
if(bi.biHeight > 0)
*height = bi.biHeight;
else
*height = -bi.biHeight;
}
if(per)
*per = perW;
return pic;
}
// : bmp
// : filePath: ,
// data: ,
// width: ,
// height: ,
// per: ,
// : bmp , -1
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per)
{
FILE *fp;
int fileSize, fileSize2, count, headSize;
unsigned char *bmpData, *p;
int perWCount;
int i, j, picCount;
int overLineBytesNum;
unsigned int overLineBytesSum = 0;// overLineBytesNum : 0 // 4 , 0,
//
if(width < 0)
{
printf("bmp_create : width < 0 , err !!\r
");
return -1;
}
//
if((fp = fopen(filePath, "wb+")) < 0)
{
printf("bmp_create : create %s err\r
", filePath);
return -1;
}
//
overLineBytesNum = width*per%4;
if(overLineBytesNum == 4)
overLineBytesNum = 0;
headSize = Bmp_FileHeader_Size + Bmp_Info_Size;
if(height < 0)
{
overLineBytesNum = overLineBytesNum*(-height);
fileSize2 = width*(-height)*per;
}
else
{
overLineBytesNum = overLineBytesNum*height;
fileSize2 = width*height*per;
}
fileSize = headSize + fileSize2;
bmpData = (unsigned char *)calloc(1, fileSize + overLineBytesNum);
//
count = 0;
//
bmpData[count++] = 'B'; //bfType
bmpData[count++] = 'M';
bmpData[count++] = (unsigned char)((fileSize>>0)&0xFF); //bfSize
bmpData[count++] = (unsigned char)((fileSize>>8)&0xFF);
bmpData[count++] = (unsigned char)((fileSize>>16)&0xFF);
bmpData[count++] = (unsigned char)((fileSize>>24)&0xFF);
count++; //
count++;
count++;
count++;
bmpData[count++] = (unsigned char)((headSize>>0)&0xFF); //bfOffbits
bmpData[count++] = (unsigned char)((headSize>>8)&0xFF);
bmpData[count++] = (unsigned char)((headSize>>16)&0xFF);
bmpData[count++] = (unsigned char)((headSize>>24)&0xFF);
bmpData[count++] = (unsigned char)((Bmp_Info_Size>>0)&0xFF); //biSize
bmpData[count++] = (unsigned char)((Bmp_Info_Size>>8)&0xFF);
bmpData[count++] = (unsigned char)((Bmp_Info_Size>>16)&0xFF);
bmpData[count++] = (unsigned char)((Bmp_Info_Size>>24)&0xFF);
bmpData[count++] = (unsigned char)((width>>0)&0xFF); //biWidth
bmpData[count++] = (unsigned char)((width>>8)&0xFF);
bmpData[count++] = (unsigned char)((width>>16)&0xFF);
bmpData[count++] = (unsigned char)((width>>24)&0xFF);
bmpData[count++] = (unsigned char)((height>>0)&0xFF); //biHeight
bmpData[count++] = (unsigned char)((height>>8)&0xFF);
bmpData[count++] = (unsigned char)((height>>16)&0xFF);
bmpData[count++] = (unsigned char)((height>>24)&0xFF);
bmpData[count++] = 0x01; //biPlanes
bmpData[count++] = 0x00;
bmpData[count++] = 24; //biBitCount
bmpData[count++] = 0;
bmpData[count++] = 0; //biCompression
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = (unsigned char)((fileSize2>>0)&0xFF); //biSizeImage
bmpData[count++] = (unsigned char)((fileSize2>>8)&0xFF);
bmpData[count++] = (unsigned char)((fileSize2>>16)&0xFF);
bmpData[count++] = (unsigned char)((fileSize2>>24)&0xFF);
bmpData[count++] = 0; //biXPelsPerMeter
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0; //biYPelsPerMeter
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0; //biClrUsed
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0; //biClrImportant
bmpData[count++] = 0;
bmpData[count++] = 0;
bmpData[count++] = 0;
//
p = &bmpData[count];
if(height >= 0) // // + +
{
for(i = 0, picCount = fileSize2; i < fileSize2 + overLineBytesSum && picCount >= 0; )
{
picCount -= width*per;
for(j = 0, perWCount = per - 1; j < width*per && i < fileSize2 + overLineBytesSum && picCount >= 0; j++)
{
p[i++] = data[picCount + perWCount];
if(--perWCount < 0)
perWCount = per - 1;
if(perWCount == per - 1)
picCount += per;
}
picCount -= width*per;
i += overLineBytesNum;
}
}
else // //
{
for(i = 0, j = 0, picCount = 0, perWCount = per - 1; i < fileSize2 + overLineBytesSum && picCount < fileSize2; )
{
p[i++] = data[picCount + perWCount];
if(--perWCount < 0)
perWCount = per - 1;
if(perWCount == per - 1)
picCount += per;
if(++j == width*per)
{
j = 0;
i += overLineBytesNum;
}
}
}
//
fileSize = fwrite(bmpData, 1, fileSize, fp);
free(bmpData);
fclose(fp);
//sync();
return fileSize;
}
bmp.h
#ifndef _BMP_H
#define _BMP_H
//bmp
//filePath :
//picMaxSize : , NULL
//width : ( ), NULL
//height : ( ), NULL
//per : , NULL
// : , ,
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per);
// bmp
//filePath :
//data :
//width : ( )
//height : ( )
//per :
// : .bmp , 0
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per);
#endif
main.c
#include
#include //malloc free
#include "bmp.h"
// 100* 50* 3 RGB
#define BMP_WIDTH 100
#define BMP_HEIGHT 50
#define BMP_PERW 3
// , , ;
// ,
// [x,y] , buff[y][x][..]
unsigned char buff[BMP_HEIGHT][BMP_WIDTH][BMP_PERW];
//
unsigned char *buff2;
int width, height, perW, picSize;
// , , ,
typedef unsigned char MyMap[BMP_WIDTH][BMP_PERW];
MyMap *buff3;
int main(int argc, char *argv[])
{
int x,y;
//---------- ----------
//
for(x = 0; x < BMP_WIDTH/2; x++)
{
for(y = 0; y < BMP_HEIGHT; y++)
{
buff[y][x][0] = 0xff;
buff[y][x][1] = 0;
buff[y][x][2] = 0;
}
}
//
for(x = BMP_WIDTH/2; x < BMP_WIDTH; x++)
{
for(y = 0; y < BMP_HEIGHT; y++)
{
buff[y][x][0] = 0;
buff[y][x][1] = 0xff;
buff[y][x][2] = 0;
}
}
//
bmp_create("test.bmp", (unsigned char *)buff, BMP_WIDTH, BMP_HEIGHT, BMP_PERW);
//---------- ----------
buff2 = bmp_get("test.bmp", &picSize, &width, &height, &perW); // , NULL
if(buff2) // NULL
{
printf("bmp get success ! picSize/%d, width/%d, height/%d, perW/%d\r
", picSize, width, height, perW);
if(width == BMP_WIDTH && height == BMP_HEIGHT && perW == BMP_PERW)
{
buff3 = (MyMap *)buff2; // ,
//
for(x = 0; x < width/2; x++)
{
for(y = 0; y < height/2; y++)
{
buff3[y][x][0] = 0xff;
buff3[y][x][1] = 0xff;
buff3[y][x][2] = 0xff;
}
}
//
for(x = width/2; x < width; x++)
{
for(y = height/2; y < height; y++)
{
buff3[y][x][0] = 0;
buff3[y][x][1] = 0;
buff3[y][x][2] = 0;
}
}
//
bmp_create("test2.bmp", buff2, width, height, perW);
}
// ! ! ! bmp_get() ,
free(buff2);
}
return 0;
}
コンパイル
gcc -o m main.c bmp.c -Wall