BREW 文字認識アプリ "Recog"
Bitmap クラスの作成
Bitmap クラス作成の意図
ビットマップが読み込める Bitmap クラスを作成します。
Bitmap クラスのヘッダ ファイル
- Bitmap.hpp - #if !defined(__BITMAP_HPP) #define __BITMAP_HPP #include <SophiaFramework.hpp> SFMTYPEDEFCLASS(Bitmap) class Bitmap { private: SFBBitmapSmp _pbitmap; // ビットマップへのポインタ SFBDIBSmp _pdib; // DIB 形式のビットマップへのポインタ SFCError GetDib(Void); // DIB 形式のビットマップを取得する SFCError Copy(BitmapConstRef bitmap); // ビットマップをコピーする public: // コンストラクタ Bitmap(Void); Bitmap(ACharConstPtr file); Bitmap(WCharConstPtr file); Bitmap(SFXAnsiStringConstRef file); Bitmap(SFXWideStringConstRef file); Bitmap(ACharConstPtr resFile, UInt16 id); Bitmap(WCharConstPtr resFile, UInt16 id); Bitmap(SFXAnsiStringConstRef resFile, UInt16 id); Bitmap(SFXWideStringConstRef resFile, UInt16 id); Bitmap(SFBBitmapSmpConstRef pbitmap); Bitmap(BitmapConstRef bitmap); ~Bitmap(Void); // ディストラクタ // ファイルからのビットマップの読み込み SFCError LoadBitmap(ACharConstPtr file); SFCError LoadBitmap(WCharConstPtr file); SFCError LoadBitmap(SFXAnsiStringConstRef file); SFCError LoadBitmap(SFXWideStringConstRef file); // リソース ファイルからのビットマップの読み込み SFCError LoadResBitmap(ACharConstPtr resFile, UInt16 id); SFCError LoadResBitmap(WCharConstPtr resFile, UInt16 id); SFCError LoadResBitmap(SFXAnsiStringConstRef resFile, UInt16 id); SFCError LoadResBitmap(SFXWideStringConstRef resFile, UInt16 id); // ビットマップのコピーを作成 SFCError Create(SFBBitmapSmpConstRef pbitmap); // 代入演算子 BitmapConstRef operator =(SFBBitmapSmpConstRef pbitmap); BitmapConstRef operator =(BitmapConstRef bitmap); // 画素の色情報を取得 SFXRGBColor GetPixel(SFXPixelConstRef pixel) const; SFXRGBColor GetPixel(SInt16 x, SInt16 y) const { return GetPixel(SFXPixel(x, y)); } SFXSize GetSize(Void) const; // ビットマップの大きさを取得 UInt16 GetWidth(Void) const; // ビットマップの幅を取得 UInt16 GetHeight(Void) const; // ビットマップの高さを取得 UInt08 GetDepth(Void) const; // ビットマップの色深度を取得 }; #endif
コンストラクタ、LoadBitmap 関数、LoadResBitmap 関数は、何れもファイルからビットマップを読み込めます。
GetDib 関数 : DDB から DIB を作成する
SFCError Bitmap::GetDib(Void) { SFCError error(SFERR_NO_ERROR); _pdib.Release(); if(_pbitmap != null) { SFBDIBPtr pdib; error = _pbitmap->QueryInterface(AEECLSID_BITMAP, reinterpret_cast<VoidHandle>(&pdib)); if (error == SFERR_NO_ERROR) { _pdib.Attach(pdib); } else { _pbitmap.Release(); } } else { error = SFERR_FAILED; } return error; }
重要なのは、
SFBDIBPtr pdib; error = _pbitmap->QueryInterface(AEECLSID_BITMAP, reinterpret_cast<VoidHandle>(&pdib));
の 2 行です。
_pbitmap は SFBBitmapSmp 型のメンバ変数です。第 1 引数に AEECLSID_BITMAP を渡し、第 2 引数に作成した DIB へのポインタを保持する変数へのポインタを渡して SFBBitmap::QueryInterface 関数を呼び出すことで、DIB が作成されます。
スマート ポインタを使うと、不必要になった時点で SophiaFramework UNIVERSE が自動的に解放してくれて便利です。
今回のコードでは
_pdib.Attach(pdib);
として、SFBBitmap::QueryInterface 関数で作成した pdib をスマート ポインタの _pdib に管理させています。
勿論、スマート ポインタの Release メンバ関数を呼んで、明示的にオブジェクトの解放することも可能です。
元のビットマップを変更したい場合、SFBBitmap::QueryInterface 関数で新たに DIB を作成します。
GetPixel 関数 : 各画素の色を取得する
IDIB 構造体のメンバと SFBDIB クラスのメンバ関数の対応関係です。
IDIB 構造体のメンバ | SFBDIB クラスのメンバ |
---|---|
cx | GetWidth(Void) |
cy | GetHeight(Void) |
nDepth | GetDepth(Void) |
nPitch | GetPitch(Void) |
pBmp | GetBuffer(Void) |
画像上の点 (x, y) のデータの場所は、pBmp + y * nPitch から数えて x * nDepth ビット目なので、コーディングすると次のようになります。
SFXRGBColor Bitmap::GetPixel(SFXPixelConstRef pixel) const { if (_pdib == null) { return SFXRGBColor(0, 0, 0, 0); } UInt32 bitsIndex(_pdib->GetDepth()); bitsIndex *= pixel.GetX(); BytePtr p(_pdib->GetBuffer() + pixel.GetY() * _pdib->GetPitch() + (bitsIndex >> 3)); // bitsIndex >> 3 は bitsIndex / 8 と等価 // これで、指定された点の値が格納されている // 先頭のメモリ アドレスが取得できる // (高速化のためビット演算を使用) SInt08 localBitsIndex(8 - static_cast<SInt08>(bitsIndex & 7)); // bitsIndex & 7 は bitsIndex % 8 と等価 // これで p の下から何ビット目に // 目的のデータがあるのか取得できる // (高速化のためビット演算を使用) SInt16 len(_pdib->GetDepth()); NativeColor color(0); BytePtr pcolor(reinterpret_cast<BytePtr>(&color)); SInt08 leftBits(8); // pcolor にあと何ビット書き込めるか UInt08 getbits; UInt16 mask; while (len > 0) { // len と localBitsIndex と leftBits のうち最小のものを // getbits に代入 getbits = (localBitsIndex < leftBits) ? localBitsIndex : leftBits; if (getbits > len) { getbits = static_cast<UInt08>(len); } mask = static_cast<UInt16>(1 << localBitsIndex) - 1; *pcolor = (*pcolor << getbits) | ((static_cast<UInt08>(mask) & *p) >> ((getbits < localBitsIndex) ? (localBitsIndex - getbits) : 0)); len -= getbits; leftBits -= getbits; localBitsIndex -= getbits; if (localBitsIndex <= 0) { ++p; localBitsIndex = 8; } if (leftBits <= 0) { ++pcolor; leftBits = 8; } } return _pdib->NativeToColor(color); }
このコードでは、目的の画素の NativeColor を SFXRGBColor に変換しているだけです。
ビット単位でバッファにアクセスする汎用的な処理なので、煩雑なコードになっています。
※ 国内の端末はカメラの画像は 16 ビット色に統一されていますので、バイト単位しか扱わないようにするともっと簡単になります。