MoNoQLoREATOR さんが書きました:
ヘッダ部に構造体を使わないことに関してですが、情報を順番に書いていけば良いだけなのですから、わざわざ構造体を使わなくても良いのではないかと思います。
確かに順番にchar型配列にぶっこんで行っても正常に動作するプログラムを書くことができるでしょう。
ただその時はどういう意図があって書いたか分かるかもしれませんが、3か月後の自分が読んですぐに分かるでしょうか?(可読性の問題)
それに、読み込みの時に数値を指定したり、char型より大きい値を代入するときにmemsetを使用するのは煩わしいと思いませんか?(ユーザビリティーの問題)
構造体を利用するメリットとすれば。
名前でアクセスするので可読性が上がる。
配列にぶっこんで行く方法よりも名前を指定して代入するので安全であり、memsetをかます必要がないので楽である。
などなどいっぱいあります。
また今回のケースで言えば既に出来上がった構造体(BITMAPFILEHEADER, BITMAPINFOHEADER)があるのでそれを再利用した方がスマートで楽です。
取りあえず、次のプログラムとどっちが読みやすいですか?(関数化などをしているので単純に比較できないですが・・・)
ヘッダを作成している部分はInitBitmapFileHeaderとInitBitmapInfoHeaderです。特にこの二つの関数に注目して読んでみてください。(他は大して注目しなくて大丈夫です。)
コード:
#include <stdio.h>
#include <windows.h>
#define WIDTH 10
#define HEIGHT 10
typedef struct RGB
{
BYTE red, green, blue;
} RGB;
void InitBitmapFileHeader(BITMAPFILEHEADER *fileHeader, int width, int height);
void InitBitmapInfoHeader(BITMAPINFOHEADER *infoHeader, int width, int height);
void InitBitmapHeader(BITMAPFILEHEADER *fileHeader, BITMAPINFOHEADER *infoHeader, int width, int height);
void WriteBitmapHeader(FILE *fp, BITMAPFILEHEADER fileHeader, BITMAPINFOHEADER infoHeader);
void WriteBitmapLine(FILE *fp, RGB *rgb, int width);
void main()
{
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;
RGB rgb[WIDTH];
FILE *fp = fopen("outPut.bmp", "wb"); // 面倒くさいのでエラーチェックしていません。
int counter;
InitBitmapHeader(&fileHeader, &infoHeader, WIDTH, HEIGHT); // ヘッダを作成
WriteBitmapHeader(fp, fileHeader, infoHeader); // ヘッダを出力
// ビットマップデータを作成
for (counter = 0; counter < WIDTH; counter++)
{
rgb[counter].red = 255;
rgb[counter].green = 255;
rgb[counter].blue = 255;
}
// 10行分出力
for (counter = 0; counter < HEIGHT; counter++)
{
WriteBitmapLine(fp, rgb, WIDTH);
}
fclose(fp);
}
//
// BITMAPFILEHEADERを引数に従って初期化
////////////////////////////////////////////////////////////////////////////////
void InitBitmapFileHeader(BITMAPFILEHEADER *fileHeader, int width, int height)
{
int headerSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // BITMAPINFOHEADERと共に使用されることを前提
fileHeader->bfType = 'B' + 'M' * 0x100;
fileHeader->bfSize = width * height * 3 + headerSize;
fileHeader->bfReserved1 = fileHeader->bfReserved2 = 0;
fileHeader->bfOffBits = headerSize;
}
//
// BITMAPINFOHEADERを引数に従って初期化
////////////////////////////////////////////////////////////////////////////////
void InitBitmapInfoHeader(BITMAPINFOHEADER *infoHeader, int width, int height)
{
memset(infoHeader, 0, sizeof(BITMAPINFOHEADER));
infoHeader->biSize = 40;
infoHeader->biWidth = width;
infoHeader->biHeight = height;
infoHeader->biPlanes = 1;
infoHeader->biBitCount = 32; // true color(4byte)
}
//
// BITMAPFILEHEADERとBITMAPINFOHEADERを引数に従って初期化
////////////////////////////////////////////////////////////////////////////////
void InitBitmapHeader(BITMAPFILEHEADER *fileHeader, BITMAPINFOHEADER *infoHeader, int width, int height)
{
InitBitmapFileHeader(fileHeader, width, height);
InitBitmapInfoHeader(infoHeader, width, height);
}
//
// ビットマップヘッダをファイルに書き出す
////////////////////////////////////////////////////////////////////////////////
void WriteBitmapHeader(FILE *fp, BITMAPFILEHEADER fileHeader, BITMAPINFOHEADER infoHeader)
{
fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
}
//
// 一行分のRGBデータをファイルに出力
////////////////////////////////////////////////////////////////////////////////
void WriteBitmapLine(FILE *fp, RGB *rgb, int width)
{
int counter;
BYTE padding = 0;
for (counter = 0; counter < width; counter++)
{
fwrite(&rgb[counter].blue, sizeof(BYTE), 1, fp);
fwrite(&rgb[counter].green, sizeof(BYTE), 1, fp);
fwrite(&rgb[counter].red, sizeof(BYTE), 1, fp);
fwrite(&padding, sizeof(BYTE), 1, fp);
}
}