ビットマップ画像の情報(サイズとか)を表示するプログラムを 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