Streaming IPicture object

Sample Image

Environment: VC++ 5.0-6.0, NT 4.0,Win2000, Win95/98

I really like the IPicture object. This COM object works very fine. However, I had some problem when I was trying to use it in a Document-View architecture. The main problem is implementation of serialization. To resolve this problem I built two classes.

The first class called CPictureObj. This class is responsible for drawing the picture. The second class, CPictureObjList, is a collection of picture objects. By using both of these classes it is easy to implement the following functionality:

  • Load one or more images into document (*.bmp, *.jpeg, *.ico,etc...)
  • Scale images(Zoom In, Zoom Out)
  • Move images by cursor
  • Alignment
  • Save/Load images to/from compound document file.

Classes

class CPictureObj  :  
           public CPictureHolder, public CObject
{
  DECLARE_SERIAL(CPictureObj);
public:
  CPictureObj();
  CPictureObj(const CRect position);
  virtual ~CPictureObj();
  void RemoveAndDestroy();

  virtual void Copy( CPictureObj &right);
  virtual HRESULT WriteToStream(IStream* pStream);
  virtual HRESULT ReadFromStream(IStream* pStream);
  
// Attributes
public:
  HorzAlign GetHorzAlign( void ) const;
  void      SetHorzAlign( HorzAlign eHorzAlign );
  VertAlign GetVertAlign( void ) const;
  void      SetVertAlign( VertAlign eVertAlign );
  BOOL      GetSelected( void ) const;
  void      SetSelected( BOOL bValue );
  void      SetVisible(BOOL bValue);
  BOOL      GetVisible();
  CRect     GetPosition();
  void      SetPosition(const CRect pos);
  CRect     GetStartRect();
  void      SetStartRect(const CRect pos);
  CString   GetPathName();
  void      SetPathName(const CString pathname);

  OLE_HANDLE GetHandle();
  CSize      GetSize();          // in himetric
  CSize      GetSize(CDC*pDC);   // in pixel
  CSize      GetSize(CWnd*pWnd); // in pixel
  BOOL       IsValidPicture();

// Operations
public:

  BOOL Load(LPCTSTR szFile);
  BOOL CreateFromFile(const CPoint pt);
  void ReleasePicture();
  void MoveTo(const CRect& position, CWnd* pView);

  // Drawing picture
  void Draw(CDC* pDC);
  void Draw(CDC* pDC, CRect& rcBounds);
  void Draw(CDC* pDC, const CRect& 
            rcPosition, const CRect& rcBounds);
  void DrawTracker(CDC* pDC);
  void DrawTracker(CDC* pDC, const CRect& rect);
  void ZoomIn();
  void ZoomOut();

protected:

  void CalcZoom();
  void SetZoomToPosition();

protected:

  HorzAlign m_eHorizAlign;
  VertAlign m_eVertAlign;
  BOOL      m_bSelected;
  BOOL      m_bVisible;
  CRect     m_rcPosition; // in pixels
  CRect     m_startRect;  // in pixels
  int       m_trackerStyle;
  int       m_zoomX,m_zoomY;

  // Not serialized
  CString   m_strPathName;

};

class CPictureObjList : public CTypedPtrList{CObList, CPictureObj*}
{
public:
  ~CPictureObjList();

  void RemoveAndDestroy();
  void DeselectAll();

  CSize ComputeMaxSize();           // in himetric
  CSize ComputeMaxSize(CDC* pDC);   // in pixel
  CSize ComputeMaxSize(CWnd* pWnd); // in pixel
  CRect GetRect();                  // in pixel

  CPictureObj* FindSelected();
  CPictureObj* ObjectAt(const CPoint& pt);
  bool Remove(CPictureObj* pObj);
  void Draw(CDC* pDC);

  // Streaming
  HRESULT WriteToStream(IStream* pStream);
  HRESULT ReadFromStream(IStream* pStream);
  BOOL WriteToStorage(LPSTORAGE lpRootStg);
  BOOL ReadFromStorage(LPSTORAGE lpRootStg);

};

Using the classes.

For use streaming picture create your document object derived from COleDocument.

class CYourDoc : public COleDocument

Define inside of document object the picture collection like here:

CPictureObjList  m_objects;

Now, you can insert picture by simple way:

CPictureObj* pObj =  new CPictureObj;
pObj->CreateFromFile(CPoint(10,10));
m_objects.AddHead(pObj);

Also, you can load picture directly from the file:

CPictureObj* pObj =  new CPictureObj;
pObj->Load("MyFile.jpg");
m_objects.AddHead(pObj);

For scaling picture you can use ZoomIn, ZoomOut member functions:

CPictureObj* pObj = m_objects.FindSelected();
if(pObj)
{
    pObj->ZoomIn();
}

Moving the selected picture is easy:

CPoint delta = point - c_last;
CPictureObj* pSel = m_objects.FindSelected();
if(pSel)
{
  CRect position = pSel->GetPosition();
  position += delta;
  pSel->MoveTo(position, this);
}

Drawing collection of pictures is also easy:

GetDocument()->m_objects.Draw(pDC);

Implementation of picture serialization you can get from here:

void CYourDoc::Serialize(CArchive& ar)
{
 CWaitCursor wait;
 COleDocument::Serialize(ar);
 if (ar.IsStoring())
 {
    m_objects.WriteToStorage(m_lpRootStg); 
 }
 else
 { 
    m_objects.ReadFromStorage(m_lpRootStg);
    m_objects.DeselectAll();
 }
}

Downloads

Download demo project - 150 Kb
Download source - 6.48 Kb