ビットマップ読み取りクラス公開
CannonCatや3DRPGプログラミング (C magazine)で、
ビットマップをマップデータとして使っているのを見て、
ひょっとしたらあると、便利かと思い公開。
地形パターンが少なければ、きっとビットマップの方が楽なはず。
24bit専用ですが、お好きに使ってくださいな♪
ヘッダ
#pragma once #include <iostream> #include <string> #include <fstream> using namespace std; typedef long LONG; typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned char BYTE; /*BITMAPFILEHEADER*/ struct BITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; }; /*BITMAPINFOHEADER*/ struct BITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; }; /* COLOR構造体 */ struct COLOR24 { BYTE r, g, b; }; const COLOR24 COLOR24_BLACK = {0, 0, 0}; const COLOR24 COLOR24_WHITE = {255, 255, 255}; const long BI_RGB = 0L; struct MY_BITMAP { BITMAPFILEHEADER bmf; BITMAPINFOHEADER bmi; }; /* * 24ビットBitmapクラス */ class CBitmap24 { private: int m_Width; int m_Height; MY_BITMAP m_Header; void *m_Buffer; COLOR24 m_OutColor; private: public: CBitmap24(void); CBitmap24(int width, int height); virtual ~CBitmap24(void); void InitHeader(); void Delete(); void Resize(int width, int height); void Copy(CBitmap24 *obj); void Load(string filename); void Save(string filename); int GetWidth() {return m_Width;}; int GetHeight() {return m_Height;}; MY_BITMAP *GetHeader() {return &m_Header;}; void SetHeader(MY_BITMAP *header) {m_Header = *header;}; void *GetBuffer() {return m_Buffer;}; void *GetPixelAddress(int x, int y); void *GetPixelAddressNC(int x, int y){return (BYTE *)m_Buffer + ((m_Width * y + x) * sizeof(COLOR24));}; void SetPixel(int x, int y, COLOR24 *color); COLOR24 GetPixel(int x, int y); COLOR24 GetOutColor() {return m_OutColor;}; void SetOutColor(COLOR24 color) {m_OutColor = color;}; };
cppファイル
#include ".\bitmap24.h" // ============================================================================ // デフォルトコンストラクタ // ============================================================================ CBitmap24::CBitmap24() { m_OutColor = COLOR24_WHITE; m_Buffer = NULL; Resize(8, 8); } // ============================================================================ // コンストラクタ // @param width, height サイズ // ============================================================================ CBitmap24::CBitmap24(int width, int height) { m_OutColor = COLOR24_WHITE; m_Buffer = NULL; Resize(width, height); } // ============================================================================ // デストラクタ // ============================================================================ CBitmap24::~CBitmap24(void) { Delete(); } // ============================================================================ // バッファの解放 // ============================================================================ void CBitmap24::Delete() { if(m_Buffer != NULL) { delete[] m_Buffer; m_Buffer = NULL; } } // ============================================================================ // サイズ変更 // @param width, height サイズ // ============================================================================ void CBitmap24::Resize(int width, int height) { Delete(); m_Width = width; m_Height = height; m_Buffer = new BYTE[sizeof(COLOR24) * m_Width * m_Height]; memset(m_Buffer, 0x00, sizeof(COLOR24) * m_Width * m_Height); InitHeader(); } // ============================================================================ // ヘッダ情報・バッファをコピーする // @param コピー元 // ============================================================================ void CBitmap24::Copy(CBitmap24 *obj) { // ヘッダ m_Header = *obj->GetHeader(); // バッファ m_Buffer = NULL; Resize(obj->GetWidth(), obj->GetHeight()); size_t memsize = sizeof(COLOR24) * obj->GetWidth() * obj->GetHeight(); memcpy(m_Buffer, obj->GetBuffer(), memsize); // 領域外の色 m_OutColor = obj->GetOutColor(); } // ============================================================================ // ピクセルのアドレスを返す // @param x, y 座標 // ============================================================================ void *CBitmap24::GetPixelAddress(int x, int y) { if(x < 0 || m_Width <= x || y < 0 || m_Height <= y) { return NULL; } return GetPixelAddressNC(x, y); } // ============================================================================ // ピクセルに色を設定する // @param x, y 座標 // @param color 色 // ============================================================================ void CBitmap24::SetPixel(int x, int y, COLOR24 *color) { COLOR24 *ptr = (COLOR24 *)GetPixelAddress(x, y); if(ptr == NULL) return; ptr->r = color->r; ptr->g = color->g; ptr->b = color->b; } // ============================================================================ // ピクセルの色を取得する // @param x, y 座標 // @return 色 // ============================================================================ COLOR24 CBitmap24::GetPixel(int x, int y) { COLOR24 *ptr = (COLOR24 *)GetPixelAddress(x, y); if(ptr == NULL) return m_OutColor; return *ptr; } // ============================================================================ // ヘッダ情報初期化 // ============================================================================ void CBitmap24::InitHeader() { MY_BITMAP *header = this->GetHeader(); header->bmf.bfType = char('B') | (char('M') << 8); header->bmf.bfSize = 14 + sizeof(BITMAPINFOHEADER) + (this->GetWidth() * this->GetHeight() * 3); header->bmf.bfReserved1 = 0; header->bmf.bfReserved2 = 0; header->bmf.bfOffBits = 14 + sizeof(BITMAPINFOHEADER); header->bmi.biSize = sizeof(BITMAPINFOHEADER); header->bmi.biWidth = this->GetWidth(); header->bmi.biHeight = this->GetHeight(); header->bmi.biPlanes = 1; header->bmi.biBitCount = 24; header->bmi.biCompression = BI_RGB; header->bmi.biClrImportant = 0; header->bmi.biSizeImage = 0; header->bmi.biXPelsPerMeter = 0; header->bmi.biYPelsPerMeter = 0; header->bmi.biClrUsed = 0; header->bmi.biClrImportant = 0; } // ============================================================================ // ビットマップ読み込み // @param filename ファイル名 // ============================================================================ void CBitmap24::Load(string filename) { ifstream ifs(filename.c_str(), ios::binary); if(!ifs) { throw "File Open Error"; } MY_BITMAP *header = this->GetHeader(); /* header infomation */ ifs.read((char*)&header->bmf.bfType, sizeof(header->bmf.bfType)); ifs.read((char*)&header->bmf.bfSize, sizeof(header->bmf.bfSize)); ifs.read((char*)&header->bmf.bfReserved1, sizeof(header->bmf.bfReserved1)); ifs.read((char*)&header->bmf.bfReserved2, sizeof(header->bmf.bfReserved2)); ifs.read((char*)&header->bmf.bfOffBits, sizeof(header->bmf.bfOffBits)); ifs.read((char*)&header->bmi.biSize, sizeof(header->bmi.biSize)); ifs.read((char*)&header->bmi.biWidth, sizeof(header->bmi.biWidth)); ifs.read((char*)&header->bmi.biHeight, sizeof(header->bmi.biHeight)); ifs.read((char*)&header->bmi.biPlanes, sizeof(header->bmi.biPlanes)); ifs.read((char*)&header->bmi.biBitCount, sizeof(header->bmi.biBitCount)); ifs.read((char*)&header->bmi.biCompression, sizeof(header->bmi.biCompression)); ifs.read((char*)&header->bmi.biSizeImage, sizeof(header->bmi.biSizeImage)); ifs.read((char*)&header->bmi.biXPelsPerMeter, sizeof(header->bmi.biXPelsPerMeter)); ifs.read((char*)&header->bmi.biYPelsPerMeter, sizeof(header->bmi.biYPelsPerMeter)); ifs.read((char*)&header->bmi.biClrUsed, sizeof(header->bmi.biClrUsed)); ifs.read((char*)&header->bmi.biClrImportant, sizeof(header->bmi.biClrImportant)); this->SetHeader(header); this->Resize(header->bmi.biWidth, header->bmi.biHeight); // Pixel BYTE *ptr = (BYTE *)this->GetPixelAddress(0, 0); int padding = 4 - (this->GetWidth() * sizeof(COLOR24) % 4); // 4の倍数でパディング COLOR24 padColor = {0, 0, 0}; for(int j = 0; j < this->GetHeight(); j++) { for(int i = 0; i < this->GetWidth(); i++) { for(int k = 2; k > -1; k--) { ifs.read((char *)&ptr[k], sizeof(BYTE)); } ptr += 3; } if(padding != 4) { for(int i = 0; i < padding; i++) { BYTE tmp; // 捨て変数 // パディング(空読み) ifs.read((char *)&tmp, sizeof(BYTE)); } } } ifs.close(); } // ============================================================================ // ビットマップ書き込み // @param filename ファイル名 // ============================================================================ void CBitmap24::Save(string filename) { ofstream ofs(filename.c_str(), ios::binary); if(!ofs) { throw "File Open Error"; } MY_BITMAP *header = this->GetHeader(); /* header infomation */ ofs.write((char*)&header->bmf.bfType, sizeof(header->bmf.bfType)); ofs.write((char*)&header->bmf.bfSize, sizeof(header->bmf.bfSize)); ofs.write((char*)&header->bmf.bfReserved1, sizeof(header->bmf.bfReserved1)); ofs.write((char*)&header->bmf.bfReserved2, sizeof(header->bmf.bfReserved2)); ofs.write((char*)&header->bmf.bfOffBits, sizeof(header->bmf.bfOffBits)); ofs.write((char*)&header->bmi.biSize, sizeof(header->bmi.biSize)); ofs.write((char*)&header->bmi.biWidth, sizeof(header->bmi.biWidth)); ofs.write((char*)&header->bmi.biHeight, sizeof(header->bmi.biHeight)); ofs.write((char*)&header->bmi.biPlanes, sizeof(header->bmi.biPlanes)); ofs.write((char*)&header->bmi.biBitCount, sizeof(header->bmi.biBitCount)); ofs.write((char*)&header->bmi.biCompression, sizeof(header->bmi.biCompression)); ofs.write((char*)&header->bmi.biSizeImage, sizeof(header->bmi.biSizeImage)); ofs.write((char*)&header->bmi.biXPelsPerMeter, sizeof(header->bmi.biXPelsPerMeter)); ofs.write((char*)&header->bmi.biYPelsPerMeter, sizeof(header->bmi.biYPelsPerMeter)); ofs.write((char*)&header->bmi.biClrUsed, sizeof(header->bmi.biClrUsed)); ofs.write((char*)&header->bmi.biClrImportant, sizeof(header->bmi.biClrImportant)); // Pixel BYTE *ptr = (BYTE *)this->GetPixelAddress(0, 0); int padding = 4 - (this->GetWidth() * sizeof(COLOR24) % 4); // 4の倍数でパディング for(int j = 0; j < this->GetHeight(); j++) { for(int i = 0; i < this->GetWidth(); i++) { for(int k = 2; k > -1; k--) { ofs.write((char *)&ptr[k], sizeof(BYTE)); } ptr += 3; } if(padding != 4) { for(int i = 0; i < padding; i++) { // パディング ofs.write((char *)&COLOR24_WHITE, sizeof(BYTE)); } } } ofs.close(); }
使い方
#include "Bitmap24.h" void main() { CBitmap24 bmp; try { bmp.Load("in.bmp"); bmp.Save("out.bmp"); } catch(...) { cout << "なんかエラー" << endl; } }
あと、GetPixel(x, y)で任意の座標にアクセスできますぜ、ダンナ。