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);
}




Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

  • A global data storage provider whose business is booming needed a best-in-class data center to serve as the backbone of its technical operations going forward—and it needed it delivered within a year.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds