Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / MFC
Article

Memory bitmap class CMemBm

Rate me:
Please Sign up or sign in to vote.
4.82/5 (9 votes)
23 Feb 2006 275.5K   9.3K   96   74
A simple class to make generic Windows bitmap operations easier.

An example of how to use this class for drawing transparent bitmap in a static control.

Introduction

Recently, I uploaded to CodeProject an article with source code for an MFC extension library that deals with Device-Dependent Bitmaps (DDB) and Device-Independent Bitmaps (DIB). Then, I began refurbishing my old skin frame classes and soon found that some people were not happy with MFC as it causes the size of applications and libraries to grow. Moreover, while working with skins, etc., I reviewed some of the DDB and DIB class concepts, and that gave rise to the CMemBm class which seamlessly implements several irritating Windows GDI routines, and at the same time is easy to use.

The CMemBm itself

First of all, the class' name is no longer CMemBm, in the year 2005 it became a member of the charting library called MChart, so from now on it will be MChMemBm :) hope that won't ruin anything. In addition, when it was used as a drawing canvas for charting on desktop, as well as CE devices, there was a need to make it more portable and serializable.

Well, in a nutshell "what's new"... I've found that in some cases, to augment serialization, for instance, the DDB functionality had apparent drawbacks, so MChMemBm was made DDB\DIB depending on MCH_USE_DDB. If the latter is defined somewhere above MChMemBm, for example, in a precompiled header, the class transparently becomes a 32 bpp DIB section wrapper, i.e. the programming interface remains the same, and a few new methods become available.

The new serialization method is:

void GetAsDIB(MByteString& refDIB) const;

where MByteString is an alias for std::string, it does not always work correctly in the DDB mode, but it is OK in DIB. It stores the image data as binary chunk exactly as it is in a raw bitmap file. The image filtering feature is available in the DIB mode:

typedef signed short MChFilter[9];
void ApplyFilter( const MChFilter& crefFilter );

It performs simple 3x3 matrix image filtering, like, it may be used to blur the image or find edges or whatever.

The CE GDI functionality is quite limited compared to desktop, so several methods like stretch drawing, transparent drawing, alpha drawing got excluded with another #define: UNDER_CE.

#if defined(_WIN32_WCE) && !defined(UNDER_CE)
    #define UNDER_CE _WIN32_WCE
#endif

This is a very simple class. Behind the scenes, it contains the memory DC handle and the bitmap handle, the latter being selected into the former. Let's take a closer look at the public class methods:

    /////////////////////construction/destruction, 
    // initialization and cleanup
    // create memory bitmap from source bitmap.
    // !REMEMBER! hbmSrc MUST NOT be selected into 
    // any DC before calling this function
    // or following will just create copy of 
    // hDC contents, not the hbmSrc.
    bool Create(HDC hDC, HBITMAP hbmSrc, int iLeft, int iTop,
        int iWidth, int iHeight, DWORD dwRop = SRCCOPY );
    // create memory bitmap from explicit data 
    // (default is monochrome bitmap)
    bool Create( HDC hDC, int iWidth, int iHeight,
            UINT cPlanes = 1, UINT cBitsPerPel = 1, 
            const void *lpvBits = NULL );
    //copy creation
    bool Create( const MChMemBm& bmSrc, DWORD dwRop = SRCCOPY );
    //create from bitmap resource by name
    bool Create( HINSTANCE hInst, LPCTSTR pszName );
    //create from bitmap resource by ID
    bool Create( HINSTANCE hInst, UINT nID )
        { return Create( hInst, MAKEINTRESOURCE(nID) ); };

    // default constructor
    MChMemBm(){ Initialize(); };
    // inplace constructor
    MChMemBm(HDC hDC, HBITMAP hbmSrc, int iLeft, int iTop,
        int iWidth, int iHeight, DWORD dwRop = SRCCOPY )
    {
        Initialize();
        Create(hDC, hbmSrc, iLeft, iTop, iWidth, iHeight, dwRop);
    };
    //copy constructor
    MChMemBm( const MChMemBm& bmSrc, DWORD dwRop = SRCCOPY )
    {
        Initialize();
        Create(bmSrc, dwRop);
    };
    // create memory bitmap from explicit data 
    // (default is monochrome bitmap)
    MChMemBm( HDC hDC, int iWidth, int iHeight,
            UINT cPlanes = 1, UINT cBitsPerPel = 1, 
            const void *lpvBits = NULL )
    {
        Initialize();
        Create( hDC, iWidth, iHeight, cPlanes, 
                            cBitsPerPel, lpvBits );
    };
    //construct from resource by name
    MChMemBm( HINSTANCE hInst, LPCTSTR pszName )
    {
        Initialize();
        Create(hInst, pszName);
    };
    //construct from resource by ID
    MChMemBm( HINSTANCE hInst, UINT nID )
    {
        Initialize();
        Create(hInst, nID);
    };
    virtual ~MChMemBm(){    Cleanup();    };

public:
    //cleanup object data
    void Cleanup();
    //get bitmap width
    int GetWidth() const;
    //get bitmap height
    int GetHeight() const;
    // get bits per pixel for our bitmap
    int GetBpp() const;
    // get color planes for our bitmap
    int GetPlanes() const;
    //return our memory dc with bitmap selected in it
    //(Blt operations - ready)
    operator HDC() const { return m_hdcImg; };
    //boolean validation operator !
    bool operator !() const { return !m_bCreated; };
    //perform pattern fill, adjusting brush 
    //origin if neccessary
    void Fill( HDC hDC, int iLeft, int iTop, int iWidth, 
                int iHeight, bool bAdjustBrushOrg = false, 
                DWORD dwRop = PATCOPY );
    //do 1-to-1 draw
    void Draw( HDC hDC, int iLeft, int iTop, 
                            DWORD dwRop = SRCCOPY ) const;
#ifndef UNDER_CE
    //perform draw (simple or stretched)
    void Draw( HDC hDC, int iLeft, int iTop, int iWidth, 
                 int iHeight, DWORD dwRop = SRCCOPY, 
                 int iStretchMode =    COLORONCOLOR ) const;
    //do transparent drawing using WinAPI or 
    //program emulated code
    void DrawTrans( HDC hDC, int iLeft, int iTop, 
       int iWidth, int iHeight,COLORREF crTransparent ) const;
    //do alpha blending draw (works only 
    //when _WIN32_WINDOWS > 0x0400 else do nothing)
    void DrawAlpha( HDC hDC, int iLeft, int iTop, int iWidth, 
      int iHeight, const BLENDFUNCTION& blendFunc ) const;
#endif
    //get as DIB, stuffed into byte array
    void GetAsDIB(MByteString& refDIB) const;
    //pixel manipulation
    COLORREF GetPixel(int iX, int iY) const;
    void SetPixel( int iX, int iY, COLORREF clPixel );
    //special effects support
#ifndef MCH_USE_DDB
    typedef signed short MChFilter[9];
    void ApplyFilter( const MChFilter& crefFilter );
#endif

All these methods are straightforward. I need to make a couple of notes on conditional compilation #defines. DrawAlpha and DrawTrans methods wrap the GDI functions TransparentBlt and AlphaBlend which reside in msimg32.dll. As far as I know, this DLL is not a part of Win95, it is included in the MS OSs starting from Win98 and WinNT 4.0 (with some service pack, I am not sure which NT4 SP is needed for this). You may want to compile the project with <SPAN CLASS="cpp-preprocessor">#define _WIN32_WINDOWS 0x0410 (I have put this define in stdafx.h in the demo project). It means that msimg32 will be automatically linked to membm.obj. In this case, both DrawAlpha and DrawTrans use the Windows API functions. If you find that this library is absent in your system, just #define _WIN32_WINDOWS 0x0400 and DrawTrans will use the appropriate code to draw the transparent bitmap, while DrawAlpha will do nothing.

Note: As I said, MChMemBm is no longer a stand-alone class, and so several additional defines\typedefs are required. I have put a part of them into stdafx.h, while the GDI wrapper helpers are provided in a separate header file, as they are in the MChart library. The following stub defines should be placed somewhere if you are planning to re-use the MChMemBm class functionality without changing the class code:

//define M_ASSERT that way, or make it alias of some existing 
//ASSERT macro if any
#include 
#ifndef NDEBUG
    #define M_ASSERT(x)    assert(x)
#else
    #define M_ASSERT(x)
#endif

//place it in percompiled header if you plan to make use of MChMemBm 
//class CE support
#if defined(_WIN32_WCE) && !defined(UNDER_CE)
    #define UNDER_CE _WIN32_WCE
#endif

//define this in precompiled header for CE compilation, as follows
#ifdef UNDER_CE
#if _WIN32_WCE < 0x500 && _MSC_VER > 1220 
// only needed for WM2003 builds under VS2005 
#pragma comment(lib, "ccrtrtti.lib") 
#endif
#endif

//undefine to use DDB functionality instead of DIB section
//#define MCH_USE_DDB

//the following are the necessary stubs 
//to make MChMemBm class stand-alone
//define stubs for MChart - specific types to compile standalone
#define MByteString    std::string
#define M_NUMBER_OF_ARRAY_ELEMENTS(a)    (sizeof(a)/sizeof(a[0]))
#define M_L(x)    _T(x)
//stringer macro
#define MCH_TO_STRING_(x)            # x
#define MCH_TO_STRING(x)    MCH_TO_STRING_(x)

struct MException
{
public:
    MException( LPCTSTR strMsg ) : m_strMsg(strMsg) {}
    static void Throw( LPCTSTR strMsg ) { throw MException( strMsg ); }

    LPCTSTR GetMsg() const { return m_strMsg.c_str(); }

protected:
    typedef std::basic_string StdStringT;
    StdStringT m_strMsg;
};

//define this somewhere before including MChGDIWrappers.h
class MChNonCopyableConcept
{
protected:
    MChNonCopyableConcept() {}
    ~MChNonCopyableConcept() {}

private:  
    MChNonCopyableConcept( const MChNonCopyableConcept& );
    const MChNonCopyableConcept& operator=( const MChNonCopyableConcept& );
};

Brief comments on the demo code

The demo sample is just a generic Win32 Windows application. Here is the implementation of the Paint function:

void CALLBACK Paint( HWND hWnd, HDC hDC )
{
    //get window application instance
    HINSTANCE hInst = (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE );
    CMemBm bmMem8( hInst, IDB_BMP8 );    //8 bpp bitmap(256 colors)
    CMemBm bmMem4( hInst, IDB_BMP4 ); //4 bpp bitmap(16 colors)
    CMemBm bmMem24( hInst, IDB_BMP24 ); //24 bpp bitmap(16M colors)
    CMemBm bmExplicit( hDC, iXSize, iYSize, 1, 32, 
      abBits ); //explicit creation of 24 bit bitmap
    CMemBm bmFile( hInst, _T("avatar.bmp"),
      TRUE ); //bitmap loading from file
    bmMem8.Draw( hDC, 20, 20 );
    bmMem4.Draw( hDC, 20, 70 );
    bmMem24.Draw( hDC, 20, 120 );

    //draw them transparently (assuming blue color is transparent)
    bmMem8.DrawTrans( hDC, 140, 20, 60, 30, RGB(0,0,255) );
    bmMem16.DrawTrans( hDC, 140, 70, 60, 30, RGB(0,0,255) );
    bmMem24.DrawTrans( hDC, 140, 120, 60, 30, RGB(0,0,255) );

    //capture part of this window's dc
    CMemBm bmSnap( hDC, NULL, 40, 40, 80, 80 );

    //draw this snapshot
    bmSnap.Draw( hDC, 20, 200 );

    //get screen snapshot, draw red line on it, 
    //and draw it in window's dc
    //cleanup previous snapshot contents
    bmSnap.Cleanup();

    //capture screen part
    bmSnap.Create(NULL, NULL, 40, 40, 80, 80 );

    //create red pen
    HPEN hPen = CreatePen( PS_SOLID, 1, RGB(255,0,0) );
    //select it on snapshot's dc
    HANDLE hOldPen = SelectObject(bmSnap, hPen);

    //draw diagonal line in the snapshot
    MoveToEx( bmSnap, 0, 0, NULL );
    LineTo( bmSnap, 80, 80 );

    //restore snapshot's dc pen
    SelectObject(bmSnap, hOldPen);

    //cleanup pen
    DeleteObject(hPen);

    //draw snapshot on window's dc
    bmSnap.Draw( hDC, 20, 300 );

    //window dc pattern filling with snapshot
    bmSnap.Fill( hDC, 200, 20, 200, 200, true );

    //test alpha blending: AC_SRC_OVER and 0 are mandatory so far,
    //128 = 50% opacity( 0 - 255), 0 - do not use bitmap's alpha channel
    BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 128, 0};

    //do alpha blend drawing
    bmSnap.DrawAlpha( hDC, 200, 250, 80, 80, blendFunc );
}

That's all. I hope you enjoyed this little class. In addition, in "downloads" section, I've placed a demo project that shows the possible use of this class in a custom-draw static control (inspired by Danny Shimony).

History

  • 13th Feb, 2006
    • major class update, class renamed (DDB|DIB wrapper made by conditionally compiling with #define MCH_USE_DDB, ported to CE), demo projects updated (To VS 2005).
  • 24th Nov, 2004
    • added minor changes allowing the bitmap to be loaded from a file. Updated the demo project and source.
  • 1st Sep, 2003
    • added demo project that explains how to dynamically load bitmap from a resource to the CMemBm class and use it as an image preview or window background.
  • 13th Jan, 2002
    • updated the source code, demo project and the demo EXE based on the recent bug fix.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Eko-Sfera
Russian Federation Russian Federation
Born in 05.20.1971, in Moscow.
Graduated from Moscow Physical Engineering Institute in 1993.
Gained PhD. in Phys. Math. sciences in 1998.
Programmer experience over 8 years.
Assembler(s), Pascal, VBasic, JScript, ANSI C, C++.
Microcontrollers, Serial communication, MSJet DB, MFC, ATL, COM.
MSDev Studio, Borland CBuilder.
Russian, English.

Married, with one child.

Comments and Discussions

 
GeneralRe: display of 2 dimension array Pin
Vsevolod22-Feb-02 2:40
professionalVsevolod22-Feb-02 2:40 
GeneralRe: display of 2 dimension array Pin
20-Mar-02 1:31
suss20-Mar-02 1:31 
GeneralRe: display of 2 dimension array Pin
JDeimos25-Nov-04 17:29
JDeimos25-Nov-04 17:29 
GeneralRe: display of 2 dimension array Pin
Vsevolod26-Nov-04 0:59
professionalVsevolod26-Nov-04 0:59 
GeneralMy contact info has been changed. Pin
Vsevolod8-Jan-02 21:14
professionalVsevolod8-Jan-02 21:14 
GeneralBitmap & Database Pin
28-Nov-01 3:37
suss28-Nov-01 3:37 
GeneralRe: Bitmap & Database Pin
Vsevolod8-Jan-02 3:34
professionalVsevolod8-Jan-02 3:34 
GeneralBUG: should release temporary DC Pin
Paul Groot28-Nov-01 0:37
Paul Groot28-Nov-01 0:37 
GeneralRe: BUG: should release temporary DC Pin
Vsevolod8-Jan-02 3:11
professionalVsevolod8-Jan-02 3:11 
GeneralI can't understand this raster operation... Pin
30-Aug-01 3:12
suss30-Aug-01 3:12 
QuestionHow to save an image as file Pin
10-Jul-01 1:42
suss10-Jul-01 1:42 
AnswerRe: How to save an image as file Pin
Vsevolod6-Aug-01 2:18
professionalVsevolod6-Aug-01 2:18 
GeneralGive me an idea ... Pin
Manikandan19-Mar-01 14:34
Manikandan19-Mar-01 14:34 
GeneralRe: Give me an idea ... Pin
Vsevolod20-Mar-01 0:49
professionalVsevolod20-Mar-01 0:49 
Generalsaving Pin
14-Mar-01 7:51
suss14-Mar-01 7:51 
GeneralRe: saving Pin
Vsevolod20-Mar-01 0:34
professionalVsevolod20-Mar-01 0:34 
Generalfrequent (re)allocation Pin
13-Mar-01 10:39
suss13-Mar-01 10:39 
GeneralRe: frequent (re)allocation Pin
13-Mar-01 22:02
suss13-Mar-01 22:02 
GeneralWin2000/Win98 required Pin
20-Feb-01 20:25
suss20-Feb-01 20:25 
GeneralRe: Win2000/Win98 required Pin
20-Feb-01 20:30
suss20-Feb-01 20:30 
Generalconditional compiles Pin
15-Feb-01 9:14
suss15-Feb-01 9:14 
GeneralRe: conditional compiles Pin
15-Feb-01 21:10
suss15-Feb-01 21:10 
GeneralRe: conditional compiles (use DelayLoad!) Pin
Ryan Schneider9-Apr-01 6:03
Ryan Schneider9-Apr-01 6:03 
GeneralRe: conditional compiles (use DelayLoad!) Pin
Maurizio Pisano17-Jun-02 14:07
Maurizio Pisano17-Jun-02 14:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.