Character-Recognition Application for BREW "Recog" -4/4-
Building the Bitmap Class
Bitmap Class Motivation
A reusable Bitmap class is made to allow applications like Recog to easily read bitmaps.
Bitmap Class Header File
- Bitmap.hpp - #if !defined(__BITMAP_HPP) #define __BITMAP_HPP #include <SophiaFramework.hpp> SFMTYPEDEFCLASS(Bitmap) class Bitmap { private: SFBBitmapSmp _pbitmap; // Pointer for bitmap SFBDIBSmp _pdib; // Pointer for bitmap in DIB format SFCError GetDib(Void); // Get bitmap in DIB format SFCError Copy(BitmapConstRef bitmap); // Copy bitmap public: // Constructor 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); // Destructor // Read bitmap from file SFCError LoadBitmap(ACharConstPtr file); SFCError LoadBitmap(WCharConstPtr file); SFCError LoadBitmap(SFXAnsiStringConstRef file); SFCError LoadBitmap(SFXWideStringConstRef file); // Read bitmap from resource 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); // Create copy of bitmap SFCError Create(SFBBitmapSmpConstRef pbitmap); // Substitute operator BitmapConstRef operator =(SFBBitmapSmpConstRef pbitmap); BitmapConstRef operator =(BitmapConstRef bitmap); // Get color information of the image SFXRGBColor GetPixel(SFXPixelConstRef pixel) const; SFXRGBColor GetPixel(SInt16 x, SInt16 y) const { return GetPixel(SFXPixel(x, y)); } SFXSize GetSize(Void) const; // Get size of the bitmap UInt16 GetWidth(Void) const; // Get width of the bitmap UInt16 GetHeight(Void) const; // Get height of the bitmap UInt08 GetDepth(Void) const; // Get color depth of the bitmap }; #endif
The Constructor, the LoadBitmap and LoadResBitmap functions are all designed to read bitmaps from files.
The GetDib Function: Generate DIB from DDB
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; }
These are the important points of the previous code.
SFBDIBPtr pdib; error = _pbitmap->QueryInterface(AEECLSID_BITMAP, reinterpret_cast<VoidHandle>(&pdib));
_pbitmap is a member variable of the SFBBitmapSmp class. The DIB is generated by calling SFBBitmap::QueryInterface with AEECLSID_BITMAP as the first argument, and a pointer to a pointer (which points to the DIB) as a second argument.
The responsibility for releasing the DIB prior to application termination is left to the user, but fortunately it is automatically handled by using SophiaFramework UNIVERSE's "smart" pointers.
_pdib.Attach(pdib);
The preceding line is used to make the smart pointer _pdib manage the pdib generated by the SFBBitmap::QueryInterface function.
To avoid numerous ill-timed function calls associated with the smart pointer, the object can be released manually with the smart pointer's "Release" member function.
The DIB generated by SFBBitmap::QueryInterface is independent from the original bitmap. So when the original bitmap is modified, a new DIB needs to be generated.
The GetPixel Function: Get Pixel Color
This table shows the relationship between members of the IDIB structure ( explained in section 3 ) and their corresponding SFBDIB class member functions.
IDIB Structure | SFBDIB Class |
---|---|
cx | GetWidth(Void) |
cy | GetHeight(Void) |
nDepth | GetDepth(Void) |
nPitch | GetPitch(Void) |
pBmp | GetBuffer(Void) |
The data of point ( x, y ) is stored in the [ x * nDepth ] bit, counting from [ pBmp + y * nPitch ].
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, equals bitsIndex / 8 // Get the head memory address where the // value of the selected point is stored // (Using bit operataions to speed things up) SInt08 localBitsIndex(8 - static_cast<SInt08>(bitsIndex & 7)); // bitsIndex & 7, equals bitsIndex % 8 // now, the target data can be found // (Using bit operataion to speed things up) SInt16 len(_pdib->GetDepth()); NativeColor color(0); BytePtr pcolor(reinterpret_cast<BytePtr>(&color)); SInt08 leftBits(8); // how many more bits can be inserted in pcolor UInt08 getbits; UInt16 mask; while (len > 0) { // getbits is assigned the smallest value between // len, localBitsIndex and leftBits. 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); }
The NativeColor of the target pixel is converted to a SFXRGBColor in this code.
The need to access the buffer bit by bit, makes this code a little complicated.