Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A C++ OCX for drawing pictures on any window of your Application

0.00/5 (No votes)
7 Nov 2002 1  
The control overwrites the windows event handler to overtake the paint event.

Introduction

This OCX gives you the possibility to zoom any picture you like on any window of (at least) your application. There are three major parts, namely loading the desired picture, re-direction of the Windows Event Handler and drawing the picture.

Windows NT, Windows 2000 and Windows XP do only allow an application to overwrite the Windows event handler of an own window. The example is more or less self explaining. The picture is loaded using OleLoadPicture(). The picture will be drawn using the Windows standard graphic API function strechblt().

To supersede the Windows event handler, SetWindowLong() is used.

Details

The drawing routine

The main drawing is done within the ondraw method. In case that the OCX should draw on other windows than itself, it will call ondraw directly.

As the OCX is generated using MFC, the method header is standard and has been automatically generated:

void CPictureZoomCtrl::OnDraw(
  CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

PictureZoom is using a flag to identify whether a picture has already been loaded or not:

  if (m_bNoPicture)
    return;

The first step is to create a compatible DC which needs to hold the picture:

  CDC mdc; // memory DC

  mdc.CreateCompatibleDC(pdc);
  CBitmap* pOld = mdc.SelectObject(&m_Picture);

To prevent disturbing colors when drawing a stretched or shrunken picture, set the color mode properly:

  pdc->SetStretchBltMode(COLORONCOLOR);
  mdc.SetStretchBltMode(COLORONCOLOR);

In order to work with the picture, we needs its dimension:

  m_Picture.UnrealizeObject();
  BITMAP BM;
  m_Picture.GetBitmap(&BM);

The next parts are a little tricky as we need to discern between 3 ways of displaying the picture. The first is to draw it without keeping the aspect ratio of the original picture:

  if (!m_bAspectRatio)
    pdc->StretchBlt(0, 0, rcBounds.Width(), 
      rcBounds.Height(),&mdc, 0, 0, 
      BM.bmWidth, BM.bmHeight, SRCCOPY);

The next block differs between the other two cases:

  else
  {
    double Strech = double(rcBounds.Width()) / double(BM.bmWidth);
    int iHeight = Strech * BM.bmHeight;
    int iWidth = Strech * BM.bmWidth;

    int yMove = ((iHeight - rcBounds.Height()) / 2) / Strech;

The first of these other two cases is that the picture needs to be cut at the top and bottom to draw it in a zoomed way over the whole given window. The first step to do so is to calculate the upper left corner on the source (unscaled!) bitmap:

    if (yMove >= 0)
    {
      // Strech for width

      int xp = -m_xAdd;
      int yp = yMove - m_yAdd;

      if (xp < 0)
        xp = 0;

      if (yp < 0)
        yp = 0;

      if (xp > iWidth - rcBounds.Width())
        xp = iWidth - rcBounds.Width();

      if (yp > (iHeight - rcBounds.Height()) / Strech)
        yp = (iHeight - rcBounds.Height()) / Strech;

Now as I was a little unsatisfied with center-only display of pictures, I decided to allow some alignment-settings as well:

      if (m_Align == TOP)
        yp = 0;
      else if (m_Align == BOTTOM)
        yp = (iHeight - rcBounds.Height()) / Strech;

      m_xAdd = -xp;
      m_yAdd = yMove - yp;

The last step in case one is to simply blit the Source-Rectangle on the target window using strechblt():

      // Blit only on the rectangle that is invalid

      CRect SourceRect((rcInvalid.left * BM.bmWidth) / 
        rcBounds.Width() + xp, 
        (rcInvalid.top * (rcBounds.Height() / Strech)) / 
        rcBounds.Height() + yp, 
        (rcInvalid.right * BM.bmWidth) / rcBounds.Width() 
        + xp, (rcInvalid.bottom * (rcBounds.Height() / 
        Strech)) / rcBounds.Height() + yp);
      pdc->StretchBlt(rcInvalid.left, rcInvalid.top, 
        rcInvalid.Width(), rcInvalid.Height(),&mdc, 
        SourceRect.left, SourceRect.top, 
        SourceRect.right - SourceRect.left, 
        SourceRect.bottom - SourceRect.top, SRCCOPY);
    }

The second case is more or less equal to the step before. The only difference is that the picture will now be truncated on the left and right hand-sides. This happens, when the window on which to draw has a proportion less than 1 (seen as width against height).

    else
    {
      Strech = double(rcBounds.Height()) / double(BM.bmHeight);
      int iHeight = Strech * BM.bmHeight;
      int iWidth = Strech * BM.bmWidth;

      int xMove = ((iWidth - rcBounds.Width()) / 2) / Strech;
      int xp = xMove - m_xAdd;
      int yp = -m_yAdd;

      if (xp < 0)
        xp = 0;

      if (yp < 0)
        yp = 0;

      if (xp > (iWidth - rcBounds.Width()) / Strech)
        xp = (iWidth - rcBounds.Width()) / Strech;

      if (yp > iHeight - rcBounds.Height())
        yp = iHeight - rcBounds.Height();

Again, I decided to allow some alignment (to the left or right border of the window):

      if (m_Align == LEFT)
        xp = 0;
      else if (m_Align == RIGHT)
        xp = (iWidth - rcBounds.Width()) / Strech;

      m_xAdd = xMove - xp;
      m_yAdd = -yp;

      // Blit only on the rectangle that is invalid

      CRect SourceRect((rcInvalid.left * 
        rcBounds.Width()/Strech) / rcBounds.Width() + 
        xp, (rcInvalid.top * BM.bmHeight) / rcBounds.Height() 
        + yp, (rcInvalid.right * rcBounds.Width()/Strech) 
        / rcBounds.Width() + xp, (rcInvalid.bottom * BM.bmHeight) 
        / rcBounds.Height() + yp);
      pdc->StretchBlt(rcInvalid.left, rcInvalid.top, 
        rcInvalid.Width(), rcInvalid.Height(),&mdc, 
        SourceRect.left, SourceRect.top, 
        SourceRect.right - SourceRect.left, 
        SourceRect.bottom - SourceRect.top, SRCCOPY);
    }
  }

The last step of drawing is to free all used resources:

  mdc.SelectObject(pOld);
  mdc.DeleteDC();
}

This article will be continued in the next days as soon as there is more time between work and studies.

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