Home > Products > SophiaFramework UNIVERSE > Character-Recognition Application for BREW "Recog"

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
cxGetWidth(Void)
cyGetHeight(Void)
nDepthGetDepth(Void)
nPitchGetPitch(Void)
pBmpGetBuffer(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.