c言語はbmp形式のピクチャの作成と読み取りを実現する(24ビットカラーフォーマットのみ)

39184 ワード

bmpピクチャファイルフォーマットといえば、ネット上で簡単に検索できますが、ここでは説明しません.本稿では、bmpピクチャファイル操作のコードを共有することを目的としています.なお、以下のコードは、24ビットカラー(すなわち、3バイトの1画素)またはその解像度以上のピクチャファイルフォーマットのみをサポートする.
他の言うことはすべてコード注釈の中にあります.直接コードをつけます.
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