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 ビット色に統一されていますので、バイト単位しか扱わないようにするともっと簡単になります。











