Extending CPictureHolder for loading BMP, JPG, etc.

Environment: VC6 (earlier probably ok too), Win2K/95/98

This class extends the MFC CPictureHolder class to include

* better support for enhanced metafiles

* access to picture handles

* loading from files, blocks etc

Simply include the .h and .cpp into your project and use it
as you would CPictureHolder.

You can also use this instead of the CBitmap class (but with
code changes, of course).

And remember that CPictureHolder has a Render method to draw
pictures, and it support transparency for GIF’s etc.

I build this with various versions of VC6. I don’t see why
it wouldn’t work on other recent versions.

NOTE 1: I would usually have made many of these memeber functions
const. However, CPictureHolder doesn’t use any consts, and so I would
have to have done lots of (potentially unsafe) const casts in my code.

NOTE 2: chensu says that OldLoadPicture/IPicture has problems with palettes.
I haven’t looked at his code yet, but if so, I will (with his permission)
update this code to include whatever fixes he added to better support
palettes

NOTE 3: I havn’t included support for icons in here. It would be trivial to
add so I’ll leave it as an excercise for the reader 🙂

NOTE 4: It is also trivial to support directly loading a picture from a
resource file. In this case one would load the raw picture data from
the resource into a global block and then call OleLoadPictureFromGlobal.
I might later extend this class to include an OldLoadPictureFromResource
member (of someone else can do so and post it here if they like)

Header File – PictureHolderEx.h


// PictureHolderEx.h: interface for the CPictureHolderEx class.
//
///////////////////////////////////////////////////////////////

#pragma once

#include

class CPictureHolderEx : public CPictureHolder {
public:
// Constructors (including copy and assign!!)
CPictureHolderEx();
CPictureHolderEx(const CPictureHolderEx& holder);
CPictureHolderEx& operator=(const CPictureHolderEx& from);

// Creation
BOOL CreateFromEnhMetafile(HENHMETAFILE hemf,
BOOL bTransferOwnership);

// Handles to picture objects
OLE_HANDLE GetHandle();

// Do we have a picture? what type?
inline bool HasPicture()
{ return NULL != m_pPict; }

inline bool IsBitmap()
{ return GetType() == PICTYPE_BITMAP; }

inline bool IsMetafile()
{ return GetType() == PICTYPE_METAFILE; }

inline bool IsEnhMetafile()
{ return GetType() == PICTYPE_ENHMETAFILE; }

// Allow use of a CPictureHolderEx what an HBITMAP etc
// could be used
inline operator HBITMAP()
{ return IsBitmap() ? (HBITMAP)GetHandle() : NULL; }
inline operator HMETAFILE() { return IsMetafile() ?
(HMETAFILE)GetHandle() : NULL; }
inline operator HENHMETAFILE() { return IsEnhMetafile() ?
(HENHMETAFILE)GetHandle() : NULL; }

// Load from file etc
bool OleLoadPictureFromFile(LPCTSTR lpszName);
bool OleLoadPictureFromCFile(CFile& file);
bool OleLoadPictureFromGlobal(HGLOBAL hGlobal);
bool OleLoadPictureFromStream(LPSTREAM lpStream);

// File extensions allowed
static const LPCTSTR c_FileExtensions[];
static const int c_nFileExtensions;
};

Implementation File – PictureHolderEx.cpp

// PictureHolderEx.cpp: implementation of
// the CPictureHolderEx class.
//
///////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PictureHolderEx.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// copied from MFC source
#ifndef RELEASE
#define RELEASE(lpUnk)
do { if ((lpUnk) != NULL) { (lpUnk)->Release();
(lpUnk) = NULL; } } while (0)
#endif

///////////////////////////////////////////////////////////////
// Statics
///////////////////////////////////////////////////////////////

const LPCTSTR CPictureHolderEx::c_FileExtensions[] = {
".BMP",".RLE",".DIB",".GIF",".JPG",".WMF",".EMF"
};

const int CPictureHolderEx::c_nFileExtensions =
sizeof(CPictureHolderEx::c_FileExtensions)
/ sizeof(*CPictureHolderEx::c_FileExtensions);

///////////////////////////////////////////////////////////////
// Construction/Destruction
///////////////////////////////////////////////////////////////

CPictureHolderEx::CPictureHolderEx()
: CPictureHolder()
{
// nothing to do
}

CPictureHolderEx::CPictureHolderEx(const CPictureHolderEx& holder)
: CPictureHolder() // there is no copy c'tor for CPictureHolder
{
// copy and bump up the reference count
// so the IPicture knows it has an extra pointer
m_pPict = holder.m_pPict;
if (m_pPict) m_pPict->AddRef();
}

CPictureHolderEx&
CPictureHolderEx::operator=(const CPictureHolderEx& from)
{
if (this != &from) {
// copy and bump up the reference count
// so the IPicture knows it has an extra pointer
// make sure we release the old picture too
IPicture* pPict = m_pPict;
m_pPict = from.m_pPict;
if (m_pPict) m_pPict->AddRef();
RELEASE(pPict);
}

return *this;
}

// based on ctlpict.cpp MFC code for CreateFromMetafile
BOOL CPictureHolderEx::CreateFromEnhMetafile(HENHMETAFILE hemf,
BOOL bTransferOwnership) {

RELEASE(m_pPict);
PICTDESC pdesc;
pdesc.cbSizeofstruct = sizeof(pdesc);
pdesc.picType = PICTYPE_ENHMETAFILE;
pdesc.emf.hemf = hemf;
return SUCCEEDED(::OleCreatePictureIndirect(&pdesc, IID_IPicture,
bTransferOwnership, (LPVOID*)&m_pPict));
}

///////////////////////////////////////////////////////////////
// Handles
///////////////////////////////////////////////////////////////

OLE_HANDLE CPictureHolderEx::GetHandle() {
OLE_HANDLE handle = NULL;
if (m_pPict != NULL) {
m_pPict->get_Handle(&handle);
}
return handle;
}

///////////////////////////////////////////////////////////////
// Load Picture
///////////////////////////////////////////////////////////////

bool CPictureHolderEx::OleLoadPictureFromFile(LPCTSTR lpszName) {
// check for an existing suffix
bool bLoaded = false;
CString filename(lpszName);
CString filenameonly = filename;
filenameonly.MakeUpper();
// lets see if the caller specified a file extension
bool bHadKnownExtn = false;
int l = filenameonly.GetLength();
if (l >= 4) {
CString right4 = filenameonly.Right(4);
if (right4[0] == '.') {
for (int isuffix = 0; isuffix < CPictureHolderEx::c_nFileExtensions; isuffix++) { if (right4 == CPictureHolderEx::c_FileExtensions[isuffix]) { filenameonly = filenameonly.Mid(l-4); bHadKnownExtn = true; break; } } } } CString foundfilename; { // if filename already had a valid extension, use the full name only
// otherwise lets try apending each of the possible extensions
int ifirstsuffix = bHadKnownExtn ? -1 : 0;
int nsuffix = bHadKnownExtn ? 0 :
CPictureHolderEx::c_nFileExtensions;
for (int isuffix = ifirstsuffix; isuffix < nsuffix; isuffix++) { if (isuffix < 0) { foundfilename = filename; } else { foundfilename = filenameonly; foundfilename += CPictureHolderEx::c_FileExtensions[isuffix]; } // is there a file with this name?
CFileStatus status;
if (! CFile::GetStatus(foundfilename,status)) continue;
// if so, then open file and load the picture from it
CFile file;
if (file.Open(foundfilename,CFile::modeRead|CFile::typeBinary))
{
bLoaded = OleLoadPictureFromCFile(file);
}
}
}
return bLoaded;
}

bool CPictureHolderEx::OleLoadPictureFromCFile(CFile& file) {
// get the length of the file
// if -1 then the file isn't valid
DWORD dwSize = file.GetLength();
if (-1 == dwSize) return false;

// alloc global memory based on file size
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
ASSERT(NULL != hGlobal);
if (NULL == hGlobal) return false;

// lock it and get a pointer
LPVOID pvData = ::GlobalLock(hGlobal);
ASSERT(NULL != pvData);
if (NULL == pvData) return false;

// read file and store in the global memory
DWORD dwBytesRead = file.ReadHuge(pvData,dwSize);
ASSERT(dwBytesRead == dwSize);
if (! dwBytesRead) return false;

// finished with handle for now ..
// but keep the block we read in
// so we can read from for OleLoadPicture below
::GlobalUnlock(hGlobal);

bool bLoaded = OleLoadPictureFromGlobal(hGlobal);

::GlobalFree(hGlobal);

return bLoaded;
}

bool CPictureHolderEx::OleLoadPictureFromGlobal(HGLOBAL hGlobal) {
if (! hGlobal) return false;

// create IStream* from global memory
// (the TRUE means deleted on release)
LPSTREAM lpStream = NULL;
{
HRESULT hr = ::CreateStreamOnHGlobal(hGlobal, FALSE, &lpStream);
ASSERT(SUCCEEDED(hr) && lpStream);
if (! SUCCEEDED(hr) || ! lpStream) return false;
}

// load the picture from the stream
bool bLoaded = OleLoadPictureFromStream(lpStream);

RELEASE(lpStream);

return bLoaded;
}

bool CPictureHolderEx::OleLoadPictureFromStream(LPSTREAM lpStream) {
// simply call ::OleLoadPicture to read it in
if (! lpStream) return false;

HRESULT hr = ::OleLoadPicture(lpStream, 0, FALSE,
IID_IPicture, (LPVOID*)&m_pPict);

return SUCCEEDED(hr);
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read