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:
bool Create(HDC hDC, HBITMAP hbmSrc, int iLeft, int iTop,
int iWidth, int iHeight, DWORD dwRop = SRCCOPY );
bool Create( HDC hDC, int iWidth, int iHeight,
UINT cPlanes = 1, UINT cBitsPerPel = 1,
const void *lpvBits = NULL );
bool Create( const MChMemBm& bmSrc, DWORD dwRop = SRCCOPY );
bool Create( HINSTANCE hInst, LPCTSTR pszName );
bool Create( HINSTANCE hInst, UINT nID )
{ return Create( hInst, MAKEINTRESOURCE(nID) ); };
MChMemBm(){ Initialize(); };
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);
};
MChMemBm( const MChMemBm& bmSrc, DWORD dwRop = SRCCOPY )
{
Initialize();
Create(bmSrc, dwRop);
};
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 );
};
MChMemBm( HINSTANCE hInst, LPCTSTR pszName )
{
Initialize();
Create(hInst, pszName);
};
MChMemBm( HINSTANCE hInst, UINT nID )
{
Initialize();
Create(hInst, nID);
};
virtual ~MChMemBm(){ Cleanup(); };
public:
void Cleanup();
int GetWidth() const;
int GetHeight() const;
int GetBpp() const;
int GetPlanes() const;
operator HDC() const { return m_hdcImg; };
bool operator !() const { return !m_bCreated; };
void Fill( HDC hDC, int iLeft, int iTop, int iWidth,
int iHeight, bool bAdjustBrushOrg = false,
DWORD dwRop = PATCOPY );
void Draw( HDC hDC, int iLeft, int iTop,
DWORD dwRop = SRCCOPY ) const;
#ifndef UNDER_CE
void Draw( HDC hDC, int iLeft, int iTop, int iWidth,
int iHeight, DWORD dwRop = SRCCOPY,
int iStretchMode = COLORONCOLOR ) const;
void DrawTrans( HDC hDC, int iLeft, int iTop,
int iWidth, int iHeight,COLORREF crTransparent ) const;
void DrawAlpha( HDC hDC, int iLeft, int iTop, int iWidth,
int iHeight, const BLENDFUNCTION& blendFunc ) const;
#endif
void GetAsDIB(MByteString& refDIB) const;
COLORREF GetPixel(int iX, int iY) const;
void SetPixel( int iX, int iY, COLORREF clPixel );
#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
\typedef
s 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:
#include
#ifndef NDEBUG
#define M_ASSERT(x) assert(x)
#else
#define M_ASSERT(x)
#endif
#if defined(_WIN32_WCE) && !defined(UNDER_CE)
#define UNDER_CE _WIN32_WCE
#endif
#ifdef UNDER_CE
#if _WIN32_WCE < 0x500 && _MSC_VER > 1220
#pragma comment(lib, "ccrtrtti.lib")
#endif
#endif
#define MByteString std::string
#define M_NUMBER_OF_ARRAY_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
#define M_L(x) _T(x)
#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;
};
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 )
{
HINSTANCE hInst = (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE );
CMemBm bmMem8( hInst, IDB_BMP8 );
CMemBm bmMem4( hInst, IDB_BMP4 );
CMemBm bmMem24( hInst, IDB_BMP24 );
CMemBm bmExplicit( hDC, iXSize, iYSize, 1, 32,
abBits );
CMemBm bmFile( hInst, _T("avatar.bmp"),
TRUE );
bmMem8.Draw( hDC, 20, 20 );
bmMem4.Draw( hDC, 20, 70 );
bmMem24.Draw( hDC, 20, 120 );
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) );
CMemBm bmSnap( hDC, NULL, 40, 40, 80, 80 );
bmSnap.Draw( hDC, 20, 200 );
bmSnap.Cleanup();
bmSnap.Create(NULL, NULL, 40, 40, 80, 80 );
HPEN hPen = CreatePen( PS_SOLID, 1, RGB(255,0,0) );
HANDLE hOldPen = SelectObject(bmSnap, hPen);
MoveToEx( bmSnap, 0, 0, NULL );
LineTo( bmSnap, 80, 80 );
SelectObject(bmSnap, hOldPen);
DeleteObject(hPen);
bmSnap.Draw( hDC, 20, 300 );
bmSnap.Fill( hDC, 200, 20, 200, 200, true );
BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 128, 0};
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.
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.