Bitmap読み書き
下記記事にて、Windows標準ライブラリで画像を読み書きする方法を記述しました。
GDI+ --- 画像ファイル読み書き - 何でもプログラミング
Bitmapであれば更に何のライブラリも必要なく簡単に読み書きできます。
ちょっとした画像関係の動作確認レベルの時に便利です。
今回は24bitBitmapを読み書きしてみます。
ヘッダ構造体
Bitmapファイルのヘッダ部分をまとめた構造体です。
コンパイラが勝手にパディングを入れないよう、pshpack2、poppackで挟んでいます。(VisualC++専用)
#include <pshpack2.h> struct BitmapHeader { unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; unsigned int biSize; int biWidth; int biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned int biCompression; unsigned int biSizeImage; int biXPixPerMeter; int biYPixPerMeter; unsigned int biClrUsed; unsigned int biClrImporant; }; #include <poppack.h>
読み込み
Bitmapの画像データは、幅が4Byteの倍数になるよう格納されています。
今回はデータを詰めて取り出すよう実装しています。
void LoadBitmap24(std::string path, int* width, int* height, std::vector<unsigned char>* pixels) { std::ifstream file(path, std::ios::binary); assert(file.is_open()); BitmapHeader header; file.read((char*)&header, sizeof(header)); int w = header.biWidth; int h = header.biHeight; int step = ToBitmapStep(3 * w); std::vector<unsigned char> originalPixels(step * h); file.read((char*)originalPixels.data(), originalPixels.size()); pixels->resize(3 * w * h); for (int i = 0; i < h; ++i) memcpy(pixels->data() + i * 3 * w, originalPixels.data() + i * step, 3 * w); *width = w; *height = h; } int ToBitmapStep(int step) { int paddings[] = { 0, 3, 2, 1 }; return step + paddings[step % 4]; }
書き込み
ヘッダの内容は、ほとんど決められた値になっています。
画像データを、幅が4Byteの倍数になるよう調整して書き出しています。
void SaveBitmap24(std::string path, int width, int height, const unsigned char* pixels) { std::ofstream file(path, std::ios::binary); assert(file.is_open()); int step = ToBitmapStep(3 * width); BitmapHeader header; header.bfType = 0x4d42; // "BM" header.bfSize = step * height + 54; header.bfReserved1 = 0; header.bfReserved2 = 0; header.bfOffBits = 54; header.biSize = 40; header.biWidth = width; header.biHeight = height; header.biPlanes = 1; header.biBitCount = 24; header.biCompression = 0; header.biSizeImage = 0; header.biXPixPerMeter = 0; header.biYPixPerMeter = 0; header.biClrUsed = 0; header.biClrImporant = 0; file.write((char*)&header, sizeof(header)); std::vector<unsigned char> bmpPixels(step * height); for (int i = 0; i < height; ++i) memcpy(bmpPixels.data() + i * step, pixels + i * 3 * width, 3 * width); file.write((char*)bmpPixels.data(), bmpPixels.size()); }
動作確認
Bitmapを読み込んで、赤青反転の後にBitmap保存をしてみます。
int main() { int width, height; std::vector<byte> pixels; LoadBitmap24("parrots.bmp", &width, &height, &pixels); for (int i = 0; i < width * height; ++i) std::swap(pixels[3 * i], pixels[3 * i + 2]); SaveBitmap24("output.bmp", width, height, pixels.data()); return 0; }