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
// Image.cpp : implementation of the CImage 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 "Image.h"
#include "ImageImp.h"
#include <io.h>
#include <direct.h>

// #define for DIB header marker
#define DIB_HEADER_MARKER	((WORD) ('M' << 8) | 'B')

// CImage - Implementation
CImage::CImage()
{
	// Do nothing constructor
}

CImage::~CImage()
{
}

INT CImage::GetImageWidth()
{
	// Step 1 - Return the width of the image, from the image info class
	ASSERT( m_pImageImp != NULL );
	return m_pImageImp->m_lNormalWidth;
}

INT CImage::GetImageHeight()
{
	// Step 1 - Return the height of the image, from the image info class
	ASSERT( m_pImageImp != NULL );
	return m_pImageImp->m_lNormalHeight;
}

INT CImage::Show( CWnd * pWnd, WPARAM wParam )
{
	// Step 1 - Check and delegate this method to m_pImageImp
	ASSERT( m_pImageImp != NULL );
	return m_pImageImp->PaintImage( pWnd, ( CRect * ) wParam );
}

// CBmpImage - Implementation
CBmpImage::CBmpImage() : CImage()
{
	// Step 1 - Initialize 	m_pImageImp to NULL
	m_pImageImp = NULL;
}

CBmpImage::~CBmpImage()
{
	// Step 1 - Delete m_pImageImp if it is not NULL
	if( m_pImageImp != NULL )
	{
		delete m_pImageImp;
	}
}

INT CBmpImage::Load( LPCSTR lpszFileName, CRuntimeClass * pRuntimeClass )
{
	BITMAPFILEHEADER	bmfHeader;
	BITMAPINFOHEADER	bmiHeader;
	BITMAPCOREHEADER	bmcHeader;
	DWORD					biSize		= 0;
	DWORD					dwFileSize	= 0;
	INT					nNumColors	= 0;
	BYTE					* pImage		= NULL;

	// Step 1 - Delete m_pImageImp if it is already allocated
	if( m_pImageImp != NULL )
	{
		delete m_pImageImp;
		m_pImageImp = NULL;
	}
	// Step 2 - Check if the file is present and Create a CFile object for the DIB file
	if( _access( lpszFileName, 00 ) == -1 )
	{
		return FAILURE; 
	}
	CFile dibFile( lpszFileName, CFile::modeRead );

	// Step 3 - Get length of DIB in bytes for use when reading
	dwFileSize = dibFile.GetLength();

	// Step 4 - Go read the DIB file header and check if it's valid.
	if( dibFile.Read( ( LPSTR ) & bmfHeader, sizeof( bmfHeader ) ) 
		!= sizeof( bmfHeader ) )
	{
		dibFile.Close();
		return FAILURE;
	}

	// Step 5 - Check if the header is valid
	if( bmfHeader.bfType != DIB_HEADER_MARKER )
	{
		dibFile.Close();
		return FAILURE;
	}

	// Step 6 - Read next sizeof( DWORD ) bytes to get the
	// size of bitmap info structure
	if( dibFile.Read( ( LPSTR ) & biSize, sizeof( DWORD ) ) 
		!= sizeof( DWORD ) )
	{
		dibFile.Close();
		return FAILURE;
	}
	
	// Step 7 - Seek to the starting position of the info header
	LONG lOffset = sizeof( DWORD );
	dibFile.Seek( - lOffset, CFile::current );

	// Step 8 - Check the type of bmp new windows or old windows / OS2
	BOOL bWin30DIB = ( biSize == sizeof( BITMAPINFOHEADER ) );

	// Step 9 - Read the bitmap info header or bitmap core header
	if( bWin30DIB == TRUE )
	{
		memset( & bmiHeader, 0, sizeof( BITMAPINFOHEADER ) );
		if( dibFile.Read( ( LPSTR ) & bmiHeader, sizeof( bmiHeader ) ) 
			!= sizeof( bmiHeader ) )
		{
			dibFile.Close();
			return FAILURE;
		}
	}
	else
	{
		memset( & bmcHeader, 0, sizeof( BITMAPCOREHEADER ) );
		if( dibFile.Read( ( LPSTR ) & bmcHeader, sizeof( bmcHeader ) ) 
			!= sizeof( bmcHeader ) )
		{
			dibFile.Close();
			return FAILURE;
		}
		// Step 10 - Populate bmiHeader using bmcHeader
		memset( & bmiHeader, 0, sizeof( BITMAPINFOHEADER ) );
		bmiHeader.biSize				= sizeof( BITMAPINFOHEADER ); 
		bmiHeader.biWidth				= bmcHeader.bcWidth; 
		bmiHeader.biHeight			= bmcHeader.bcHeight; 
		bmiHeader.biPlanes			= bmcHeader.bcPlanes; 
		bmiHeader.biBitCount			= bmcHeader.bcBitCount; 
		bmiHeader.biCompression		= BI_RGB; 
		// Size of the image is calculated
		bmiHeader.biSizeImage		= 
			( ( ( bmcHeader.bcPlanes * bmcHeader.bcBitCount * bmcHeader.bcWidth ) 
			+ 31 ) / 32 ) * 4 * bmcHeader.bcHeight; 
		bmiHeader.biXPelsPerMeter	= 0; 
		bmiHeader.biYPelsPerMeter	= 0; 
		bmiHeader.biClrUsed			= 0; 
		bmiHeader.biClrImportant	= 0; 
	}

	// Step 11 - Initialize image information, after creating image implementation object
	m_pImageImp = ( CImageImp * ) pRuntimeClass->CreateObject();
	if( m_pImageImp == NULL )
	{
		dibFile.Close();
		return FAILURE;
	}
	m_pImageImp->InitImageInfo( ( LPSTR ) & bmiHeader );

   // Step 12 - Get the get the number of colors in the DIB 
	nNumColors = m_pImageImp->GetNumColors();

	// Step 13 - Read the color table ( if present )
	if( nNumColors > 0 )
	{
		ReadColorEntries( nNumColors, & dibFile, bWin30DIB, m_pImageImp );
	}

	// Step 14 - Allocate memory to read the data portion
	DWORD dwPosition = dibFile.GetPosition();
	pImage = ( BYTE * ) calloc( 1, ( dwFileSize - dwPosition ) * sizeof( BYTE ) );
	if( pImage == NULL )
	{
		delete m_pImageImp;
		m_pImageImp = NULL;
		dibFile.Close();
		return FAILURE;
	}

	// Step 15 - Read the data from the current position till EOF
	if( dibFile.ReadHuge( ( LPSTR ) pImage, dwFileSize - dwPosition ) !=
		dwFileSize - dwPosition )
	{
		delete m_pImageImp;
		delete pImage;
		m_pImageImp = NULL;
		dibFile.Close();
		return FAILURE;
	}
	
	// Step 16 - Close dibFile
	dibFile.Close();
	
	// Step 17 - Populate other ImageInfo details
	m_pImageImp->m_pImage			= pImage;
	m_pImageImp->m_lNormalWidth	= bmiHeader.biWidth;
	m_pImageImp->m_lNormalHeight	= bmiHeader.biHeight;

	// Step 18 - Create Palette ( based on the no. of colors )
	if( nNumColors > 0 )
	{
		if( m_pImageImp->CreateImagePalette() == FALSE )
		{
			delete m_pImageImp;
			m_pImageImp = NULL;
			return FAILURE;
		}
	}
	return SUCCESS;
}

INT CBmpImage::ReadColorEntries( INT nNumColors, CFile * pFile, BOOL bWin30DIB, 
						 CImageImp * pImageInfo )
{
	INT	nDummy			= 0; 
	BYTE	* pColorTable	= ( BYTE * ) pImageInfo->GetColorTable();
	INT	nColorIndex		= 0;

	// Step 1 - Loop and read the color map into the table provided
	for( INT nIndex = 0; nIndex  < ( int ) nNumColors; nIndex++ )
	{
		pFile->Read( ( LPSTR ) & pColorTable[ nColorIndex ++ ], 1 );
		pFile->Read( ( LPSTR ) & pColorTable[ nColorIndex ++ ], 1 );
		pFile->Read( ( LPSTR ) & pColorTable[ nColorIndex ++ ], 1 );
		// Step 2 - Make the reserved byte in the color table as 0
		pColorTable[ nColorIndex ++ ] = 0;
		// Step 3 - For new windows style bitmap, skip 1 byte
		if( bWin30DIB )
		{
			pFile->Read( ( LPSTR ) & nDummy, 1 );
		}
	}
	return SUCCESS;
}

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
Web02 | 2.8.141223.1 | Last Updated 9 Jan 2001
Article Copyright 2001 by T. Kulathu Sarma
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid