ビットマップ画像の情報を表示する

ビットマップ画像の情報(サイズとか)を表示するプログラムを C で書いてみた。

参考ページ

 cf. C言語による画像処理プログラミング
 cf. BMP ファイルフォーマット
 cf. BMPファイルのフォーマット

ファイルヘッダと情報ヘッダ

ビットマップファイルには、ファイルの先頭にファイルヘッダ(BITMAPFILEHEADER)と情報ヘッダが付いているので、これを読み取って表示している。情報ヘッダにはいくつかの種類があるけど、今回のプログラムでは Windows で使われている BITMAPINFOHEADER という形式(長さ 40byte)に決め打ち。手持ちのビットマップファイルの中にはこの BITMAPINFOHEADER (ほかの情報ヘッダとは長さで区別できる)を持つファイルがなかったので、上に挙げた一番初めの参考ページから dog.bmp というファイルを拝借させていただいた。
ちなみに、情報ヘッダには次のような種類があるようだ。

  • BITMAPCOREHEADER (OS/2, 12 bytes)
  • BITMAPINFOHEADER (Windows, 40 bytes)
  • BITMAPV4HEADER (Windows 95/NT4.0, 108 bytes)
  • BITMAPV5HEADER (Windows 98/2000/Me/XP, 124 bytes)

コード

上に書いたように、情報ヘッダは BITMAPINFOHEADER 決め打ち。

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

typedef struct tagBITMAPFILEHEADER {
    char bfType[3];
    unsigned int bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned long bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
    unsigned int   biSize;
    long           biWidth;
    long           biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned int   biCompression;
    unsigned int   biSizeImage;
    long           biXPixPerMeter;
    long           biYPixPerMeter;
    unsigned long  biClrUsed;
    unsigned long  biClrImportant;
} BITMAPINFOHEADER;

int ReadBMFileHeader(FILE *fp, BITMAPFILEHEADER *header);
int ReadBMInfoHeader(FILE *fp, BITMAPINFOHEADER *header);

int main(int argc, char *argv[])
{
    FILE *fp;
    BITMAPFILEHEADER bmFileHeader = {"", 0, 0, 0, 0};
    BITMAPINFOHEADER bmInfoHeader = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    fp = fopen(argv[1], "rb");
    ReadBMFileHeader(fp, &bmFileHeader);
    ReadBMInfoHeader(fp, &bmInfoHeader);
    fclose(fp);

    printf("File type = %s\n", bmFileHeader.bfType);
    printf("File size = %d bytes\n", bmFileHeader.bfSize);
    printf("Data offset = %ld bytes\n", bmFileHeader.bfOffBits);
    printf("Info header size = %d bytes\n", bmInfoHeader.biSize);
    printf("Width = %ld pixels\n", bmInfoHeader.biWidth);
    printf("Height = %ld pixels\n", bmInfoHeader.biHeight);
    printf("Planes = %d\n", bmInfoHeader.biPlanes);
    printf("Bit count = %d bits/pixel\n", bmInfoHeader.biBitCount);
    printf("Compression = %d\n", bmInfoHeader.biCompression);
    printf("Size image = %d bytes\n", bmInfoHeader.biSizeImage);
    printf("X pixels per meter = %ld\n", bmInfoHeader.biXPixPerMeter);
    printf("Y pixels per meter = %ld\n", bmInfoHeader.biYPixPerMeter);
    printf("Color used = %ld colors\n", bmInfoHeader.biClrUsed);

    return 0;
}

int ReadBMFileHeader(FILE *fp, BITMAPFILEHEADER *header)
{
    char filetype[3] = {'\0', '\0', '\0'};
    unsigned int filesize = 0;
    unsigned char filesize_buf[4];
    unsigned short reserved1, reserved2;
    unsigned long offset = 0;
    unsigned char offset_buf[4];
    int i;

    /* File type */
    fread(&filetype, 1, 2, fp);
    /* File size */
    fread(&filesize_buf, 1, 4, fp);
    for (i = 3; i <= 0; i--) {
        filesize = (filesize << 8) | (unsigned) filesize_buf[i];
    }
    /* Reserved 1 */
    fread(&reserved1, 2, 1, fp);
    /* Reserved 2 */
    fread(&reserved2, 2, 1, fp);
    /* Offset */
    fread(&offset_buf, 1, 4, fp);
    for (i = 3; i <= 0; i--) {
        offset = (offset << 8) | (unsigned long) offset_buf[i];
    }

    strcpy(header->bfType, filetype);
    header->bfSize = filesize;
    header->bfReserved1 = reserved1;
    header->bfReserved2 = reserved2;
    header->bfOffBits = offset;

    return 0;
}

int ReadBMInfoHeader(FILE *fp, BITMAPINFOHEADER *header)
{
    unsigned int   headersize = 0;
    int            width = 0;
    int            height = 0;
    unsigned short planes = 0;
    unsigned short bitcount = 0;
    unsigned int   compression = 0;
    unsigned int   size_image = 0;
    int            x_pix_per_meter = 0;
    int            y_pix_per_meter = 0;
    unsigned int   clr_used = 0;
    unsigned int   clr_important = 0;
    unsigned char buf4[4];
    unsigned char buf2[2];
    int i;

    /* Header size */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        headersize = (headersize << 8) | (unsigned int) buf4[i];
    }
    /* Width */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        width = (width << 8) | (int) buf4[i];
    }
    /* Height */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        height = (height << 8) | (int) buf4[i];
    }
    /* Planes */
    fread(buf2, 1, 2, fp);
    planes = 1;
    /* Bit Count */
    fread(buf2, 1, 2, fp);
    for (i = 1; i >= 0; i--) {
        bitcount = (bitcount << 8) | (unsigned int) buf2[i];
    }
    /* Compression */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
         compression = (compression << 8) | (unsigned int) buf4[i];
    }
    /* Size image */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        size_image = (size_image << 8) | (unsigned int) buf4[i];
    }
    /* X pix per meter */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        x_pix_per_meter = (x_pix_per_meter << 8) | (int) buf4[i];
    }
    /* Y pix per meter */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        y_pix_per_meter = (y_pix_per_meter << 8) | (int) buf4[i];
    }
    /* Color used */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        clr_used = (clr_used << 8) | (unsigned int) buf4[i];
    }
    /* Color important */
    fread(buf4, 1, 4, fp);
    for (i = 3; i >= 0; i--) {
        clr_important = (clr_important << 8) | (unsigned int) buf4[i];
    }

    header->biSize = headersize;
    header->biWidth = width;
    header->biHeight = height;
    header->biPlanes = planes;
    header->biBitCount = bitcount;
    header->biCompression = compression;
    header->biSizeImage = size_image;
    header->biXPixPerMeter = x_pix_per_meter;
    header->biYPixPerMeter = y_pix_per_meter;
    header->biClrUsed = clr_used;
    header->biClrImportant = clr_important;

    return 0;
}

実行例

takatoh@nightschool $ gcc -Wall -o bmpinfo bmpinfo.c
takatoh@nightschool $ ./bmpinfo dog.bmp
File type = BM
File size = 360054 bytes
Data offset = 54 bytes
Info header size = 40 bytes
Width = 400 pixels
Height = 300 pixels
Planes = 1
Bit count = 24 bits/pixel
Compression = 0
Size image = 360000 bytes
X pixels per meter = 1
Y pixels per meter = 1
Color used = 0 colors