Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Bridge Pattern - Bridging the gap between Interface and Implementation

, 8 Jan 2001
This article discusses the Bridge Pattern, what it is, why and when it is needed.
bridge.zip
Bridge.clw
Bridge.mak
Bridge.mdp
res
BridgeDoc.ico
Bridge.ico
Bridge.dsp
Bridge.opt
Bridge.dsw
Bridge.bmp
// ImageImp.cpp : implementation of the CImageImp and it subclasses
//
// NOTE : This file uses some of the techniques described in DIBLOOK sample application 
// supplied with MFC, for handling bitmap images

#include "stdafx.h"
#include "ImageImp.h"

// Predefined constants and macros
#define IS_WIN30_DIB(lpbi)  ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
#define PALVERSION				0x300

// CImageImp - Implementation

IMPLEMENT_DYNAMIC( CImageImp, CObject )

CImageImp::CImageImp()
{
	// Step 1 - Initialize data members
	m_pImage				= NULL;
	m_lNormalWidth		= 0;
	m_lNormalHeight	= 0;
}

CImageImp::~CImageImp()
{
	// Step 1 - Delete objects
	if( m_pImage != NULL )
	{
		free( m_pImage );
	}
}

// CWinImp - Implementation

IMPLEMENT_DYNCREATE( CWinImp, CImageImp )

CWinImp::CWinImp() : CImageImp()
{
	// Step 1 - Initialize structure members
	m_pBmi				= NULL;
	m_pPalette			= NULL;
}

CWinImp::~CWinImp()
{
	// Step 1 - Delete dynamically allocated objects
	if( m_pBmi != NULL )
	{
		free( m_pBmi );
		m_pBmi = NULL;
	}
	if( m_pImage != NULL )
	{
		free( m_pImage );
		m_pImage = NULL;
	}
	if( m_pPalette != NULL )
	{
		delete m_pPalette;
	}
}

INT CWinImp::InitImageInfo( LPSTR lpBmi )
{
	// Step 1 - Check if m_pBmi is already initialized
	if( m_pBmi != NULL )
	{
		return SUCCESS;
	}
	// Step 2 - Get the no. of colors from BITMAPINFOHEADER
	INT nNumColors = GetNumColors( lpBmi );
	// Step 3 - Allocate required memory for the bitmap info structure
	// and to load the color table ( RGBQUAD )
	m_pBmi = ( BYTE * ) calloc( 1, sizeof( BITMAPINFOHEADER ) +
							( nNumColors * sizeof( RGBQUAD ) ) );
	if( m_pBmi == NULL )
	{
		return FAILURE;
	}
	// Step 4 - Copy the header onto the allocated bitmap info pointer
	memcpy( m_pBmi, lpBmi, sizeof( BITMAPINFOHEADER ) );
	return SUCCESS;
}

INT CWinImp::GetNumColors( LPSTR lpBitmapInfoHeader )
{
	// Step 1 - Check and set lpBmi
	LPCSTR lpBmi = lpBitmapInfoHeader;

	if( lpBmi == NULL )
	{
		if( m_pBmi == NULL )
		{
			return FAILURE;
		}
		lpBmi = ( LPSTR ) m_pBmi;
	}

	if( IS_WIN30_DIB( lpBmi ) )
	{
		DWORD dwClrUsed;

		dwClrUsed = ( ( LPBITMAPINFOHEADER ) lpBmi )->biClrUsed;
		if( dwClrUsed != 0 )
		{
			return ( INT )dwClrUsed;
		}
	}

	//  Step 2 - Calculate the number of colors in the color table based on
	//  the number of bits per pixel for the DIB.
	WORD wBitCount = 0;
	if( IS_WIN30_DIB( lpBmi ) )
	{
		wBitCount = ( ( LPBITMAPINFOHEADER ) lpBmi )->biBitCount;
	}
	else
	{
		wBitCount = ( ( LPBITMAPCOREHEADER ) lpBmi )->bcBitCount;
	}


	// Step 3 - Return number of colors based on bits per pixel
	switch( wBitCount )
	{
		case 1:
			return 2;

		case 4:
			return 16;

		case 8:
			return 256;

		default:
			return 0;
	}
}

LPSTR CWinImp::GetColorTable()
{
	// Step 1 - Check if m_pBmi is initialized
	if( m_pBmi == NULL )
	{
		return NULL;
	}
	// Step 2 - Check the no. of colors and return the ColorTable pointer
	if( GetNumColors() == 0 )
	{
		return NULL;
	}
	// Step 3 - Return the address to the start of color table
	return ( LPSTR ) m_pBmi + sizeof( BITMAPINFOHEADER );
}

BOOL CWinImp::CreateImagePalette()
{
	LPLOGPALETTE		lpPal			= NULL;		// pointer to a logical palette
	HANDLE				hLogPal		= 0;			// handle to a logical palette
	HPALETTE				hPal			= NULL;		// handle to a palette
	INT					nIndex		= 0;        // loop index
	INT					nNumColors	= 0;			// number of colors in color table
	BOOL					bResult		= FALSE;		// result to the caller
	
	// Step 1 - Check if palette is already created
	if( m_pPalette != NULL )
	{
		return TRUE;
	}
   
	// Step 2 - Get the number of colors in the bitmap
   nNumColors = GetNumColors();
	if( nNumColors == FAILURE )
	{
		return FALSE;
	}

   if( nNumColors != 0 )
   {
		// Step 3 - Allocate CPalette object
		m_pPalette = new CPalette;
		if( m_pPalette == NULL )
		{
			return FALSE;
		}
		// Step 4 - Allocate memory block for logical palette 
		hLogPal = ::GlobalAlloc( GHND, sizeof( LOGPALETTE )
									+ sizeof( PALETTEENTRY )
									* nNumColors  );

		// Step 5 - If not enough memory, clean up and return NULL
		if( hLogPal == 0 )
		{
			return FALSE;
		}

		lpPal = ( LPLOGPALETTE ) ::GlobalLock( ( HGLOBAL ) hLogPal );

		// Step 6 - Set version and number of palette entries 
		lpPal->palVersion		= PALVERSION;
		lpPal->palNumEntries = ( WORD )nNumColors;

		// Step 7 - Use Color table to create the palette 
		BYTE	* pColorTable	= ( BYTE * ) GetColorTable();
		INT	nColorIndex		= 0;
		for( nIndex = 0; nIndex < nNumColors; nIndex++ )
		{
			lpPal->palPalEntry[ nIndex ].peBlue		= pColorTable[ nColorIndex ++ ];
			lpPal->palPalEntry[ nIndex ].peGreen	= pColorTable[ nColorIndex ++ ];
			lpPal->palPalEntry[ nIndex ].peRed		= pColorTable[ nColorIndex ++ ];
			lpPal->palPalEntry[ nIndex ].peFlags	= 0;
			// Increment nColorIndex by one to skip the reserved byte in the color table
			nColorIndex++;
		}
		// Step 8 - Create the palette and get handle to it
		bResult = m_pPalette->CreatePalette( lpPal );
		::GlobalUnlock( ( HGLOBAL ) hLogPal );
		::GlobalFree( ( HGLOBAL ) hLogPal );
	}

	// Step 9 - Return bResult
	return bResult;
}

BOOL CWinImp::PaintImage( CWnd * pWnd, CRect * lpDCRect )
{
	LPSTR    lpBMPBits;           // Pointer to BMP bits
	BOOL     bSuccess = FALSE;    // Success/fail flag
	HPALETTE hPal		= NULL;     // Our BMP's palette
	HPALETTE hOldPal	= NULL;     // Previous palette
	CRect		ImageRect( 0, 0, m_lNormalWidth, m_lNormalHeight );
	CDC		* pDC;

	// Step 1 - Get Device context
	pDC		= pWnd->GetDC();	
		
	// Step 2 - Get a pointer to the beginning of the bit
	lpBMPBits = ( LPSTR ) m_pImage;
	
	// Step 3 - Get Imageture's palette, then select it into DC
	if( m_pPalette != NULL )
	{
		hPal = (HPALETTE) m_pPalette->m_hObject;

		// Select as background since we have
		// already realized in forground if needed
		hOldPal = ::SelectPalette( pDC->m_hDC, hPal, TRUE );
		RealizePalette( pDC->m_hDC );
	}

	// Step 4 - Make sure to use the stretching mode best for color Imagetures 
	::SetStretchBltMode( pDC->m_hDC, COLORONCOLOR );

	// Step 5 - Determine whether to call StretchDIBits() or SetDIBitsToDevice() 
	if( ( lpDCRect->Width() == ImageRect.Width() ) &&
	   ( lpDCRect->Height() == ImageRect.Height() ) )
	{
		bSuccess = ::SetDIBitsToDevice( pDC->m_hDC,			// hDC
								   lpDCRect->left,					// DestX
								   lpDCRect->top,						// DestY
								   lpDCRect->Width(),				// nDestWidth
									lpDCRect->Height(),				// nDestHeight
								   ImageRect.left,					// SrcX
								   ( int ) m_lNormalHeight -
									ImageRect.top -
									ImageRect.Height(),				// SrcY
								   0,										// nStartScan
								   m_lNormalHeight,					// nNumScans
								   lpBMPBits,							// lpBits
									( LPBITMAPINFO ) m_pBmi,		// lpBitsInfo
								   DIB_RGB_COLORS );					// wUsage
	}
	else
	{
		bSuccess = ::StretchDIBits( pDC->m_hDC,			   // hDC
									lpDCRect->left,					// DestX
									lpDCRect->top,                // DestY
									lpDCRect->Width(),				// nDestWidth
									lpDCRect->Height(),				// nDestHeight
									ImageRect.left,					// SrcX
									ImageRect.top,						// SrcY
									ImageRect.Width(),				// wSrcWidth
									ImageRect.Height(),				// wSrcHeight
									lpBMPBits,                    // lpBits
									( LPBITMAPINFO ) m_pBmi,		// lpBitsInfo
									DIB_RGB_COLORS,               // wUsage
									SRCCOPY );							// dwROP
	}
	// Step 6 - Reselect old palette
	if( hOldPal != NULL )
	{
		::SelectPalette( pDC->m_hDC, hOldPal, TRUE );
	}
	// Step 7 - Return status after releasing the DC
	pWnd->ReleaseDC( pDC );
   return bSuccess;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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

Share

About the Author

T. Kulathu Sarma

Switzerland Switzerland
Kulathu Sarma is working as a Technology Manager for GoldAvenue, a company based in Geneva, Switzerland and responsible for supporting e-business initiatives of GoldAvenue in B2B and B2C Sectors. He has been programming in C/C++ for 9 years and actively working on Patterns for the past 5 years.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150128.1 | Last Updated 9 Jan 2001
Article Copyright 2001 by T. Kulathu Sarma
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid