Cropping a Displayed Image and Copying It to a Bitmap (Visual C++ 4.0)

Take the following steps to add code that lets you select an area with a mouse, crop the display to show only that area, and trim the bitmap to match the selected area. (This example uses both cropping and trimming, so that you can see the difference.)

1. Start with the project that you created in Loading and Displaying an Image.

2. Go to the Project WorkSpace and click the FileView tab.

3. Edit TUTORDLG.H and insert the following lines in the definition of CTutorDlg after DECLARE_MESSAGE_MAP():

BOOL Cropping;   //The state when the mouse is used for cropping
float StartX;     //Starting X position in screen pixels
float StartY;     //Starting Y position in screen pixels
float EndX;       //Ending X position in screen pixels
float EndY;       //Ending Y position in screen pixels

4. Go to the Project Workspace and click the ResourceView tab.

5. Double-click Dialog and double-click IDD_TUTOR_DIALOG to bring up the application's dialog box.

6. image\btncmd.gif Add a new button to use for activating a selection mode. To do this, select the button control on the Controls toolbar. Then, click and drag to position the button on the dialog box.

7. Double-click the button and change IDC_BUTTON1 to IDC_SELECT. Also, set the Caption to &Select.

8. image\btncmd.gif Add another button to use for trimming the bitmap. To do this, select the button control on the Controls toolbar. Then, click and drag to position the button on the dialog box.

9. Double-click the button and change IDC_BUTTON1 to IDC_TRIM. Also, set the Caption to &Trim.

10. Press Ctrl-F4 to close all windows back to the Project Workspace.

11. Start the Class Wizard and add code for the Select button. To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CTutorDlg.

c. In the Object IDs list box, select IDC_SELECT.

d. In the Messages list box, select BN_CLICKED.

e. Click the Add function button. Choose OK for the default function name (OnSelect).

f. Click the Edit Code button to start entering the code.

12. Enter new code as follows:

void CTutorDlg::OnSelect() 
{
  // TODO: Add your control notification handler code here
  // Initialize cropping so that you can do it more than once
  if( Cropping )
  {
    // Set the clipping area to match the image.
    m_Lead1.SetDstClipRect( m_Lead1.GetDstLeft(), m_Lead1.GetDstTop(), m_Lead1.GetDstWidth(), m_Lead1.GetDstHeight() );
    // Display the image
    m_Lead1.ForceRepaint();
  }
  // Set a global variable to let other events know that you are cropping
  Cropping = TRUE;

  // Set the pointer to a crosshair
  m_Lead1.SetMousePointer(2);
}

13. Add code for the Trim button. To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. In the Class name combo box, select CTutorDlg.

b. In the Object IDs list box, select IDC_TRIM.

c. In the Messages list box, select BN_CLICKED.

d. Click the Add function button. Choose OK for the default function name (OnTrim).

e. Click the Edit Code button to start entering the code.

14. Enter new code as follows:

void CTutorDlg::OnTrim() 
{
  float   XFactor, YFactor, 
      NewTop, NewLeft, NewWidth, NewHeight;
  // TODO: Add your control notification handler code here
  m_Lead1.SetMousePointer(11); // hourglass
  // Use the clipping rectangle// s percentage offsets in the image rectangle
  // to determine the trimmed rectangle in the bitmap.
  // Using percentages allows for the possibility that the image is zoomed.
  XFactor = m_Lead1.GetBitmapWidth() / m_Lead1.GetDstWidth();
  YFactor = m_Lead1.GetBitmapHeight() / m_Lead1.GetDstHeight();
  NewTop = (m_Lead1.GetDstClipTop() - m_Lead1.GetDstTop()) * YFactor;
  NewLeft = (m_Lead1.GetDstClipLeft() - m_Lead1.GetDstLeft()) * XFactor;
  NewWidth = m_Lead1.GetDstClipWidth() * XFactor;
  NewHeight = m_Lead1.GetDstClipHeight() * YFactor;

  // Make sure display rectangles are automatically adjusted.
  m_Lead1.SetAutoSetRects(TRUE);
  // Trim the bitmap. This changes the size of the image and 
  // both the source and destination clipping rectangles
  m_Lead1.Trim(NewLeft, NewTop, NewWidth, NewHeight);
  // Turn off scroll bars to make sure we use the full client area.
  m_Lead1.SetAutoScroll(FALSE);
  // Set the image display size to match the LEAD control
  // The source rectangle matches the smaller bitmap.
  // Making the destination rectangle bigger, the paint will fill the LEAD control
  m_Lead1.SetDstRect(0.0f, 0.0f, m_Lead1.GetScaleWidth(), m_Lead1.GetScaleHeight() );
  m_Lead1.SetDstClipRect( 0.0f, 0.0f, m_Lead1.GetScaleWidth(), m_Lead1.GetScaleHeight() );
  // Display the image
  m_Lead1.ForceRepaint();
  m_Lead1.SetMousePointer(0); // Default
}

15. To add the code for LEAD mouse events, do the following:

a. Press Ctrl-W to go to the MFC ClassWizard.

b. In the Class Name combo box, select CTutorDlg.

c. In the Object IDs list box, select IDC_LEAD1.

d. Continue with the remaining steps for each mouse event.

16. In the MFC ClassWizard, double-click the MouseDown event and add code as follows:

void CTutorDlg::OnMouseDownLead1(short Button, short Shift, long X, long Y)
{
  // Save the starting position 
  if( Cropping && Button == 1 )
  {
    StartX = (float)X; 
    StartY = (float)Y;
    // Make the rubberband invisible until the mouse moves
    m_Lead1.SetRubberBandVisible(FALSE);
  }
}

17. In the MFC ClassWizard, double-click the MouseMove event and add code as follows:

void CTutorDlg::OnMouseMoveLead1(short Button, short Shift, long X, long Y)
{
  if( Cropping && Button == 1 )
  {
    float rbX, rbY, rbWidth, rbHeight;
    // Get the current mouse position
    EndX = (float)X;
    EndY = (float)Y;
    // Determine the origin of the rubberband rectangle, 
    // regardless of which way the mouse moves.
    if( EndX > StartX )
      rbX = StartX;
    else
      rbX = EndX;

    if( EndY > StartY )
      rbY = StartY;
    else
      rbY = EndY;

    // Determine the height and width of the rubberband rectangle
    rbHeight = (float)fabs((double)StartY - EndY);
    rbWidth = (float)fabs((double)StartX - EndX);
    // Set the rubberband rectangle 
    m_Lead1.SetRubberBandRect( rbX, rbY, rbWidth, rbHeight );
      // Alternatively, you could use the following properties to set the
      // rubberband rectangle:
      // m_Lead1.SetRubberBandHeight(rbHeight);
      // m_Lead1.SetRubberBandLeft(rbX);
      // m_Lead1.SetRubberBandTop(rbY);
      // m_Lead1.SetRubberBandWidth(rbWidth);

    // Make the rubberband rectangle visible
    m_Lead1.SetRubberBandVisible(TRUE);
  }
}

18. In the MFC ClassWizard, double-click the MouseUp event and add code as follows:

void CTutorDlg::OnMouseUpLead1(short Button, short Shift, long X, long Y)
{
  if( Cropping && Button == 1 )
  {
  float CropLeft, CropTop, CropWidth, CropHeight;
  // Get the current mouse position
  EndX = (float)X;
  EndY = (float)Y;
  // Get the origin of the clipping rectangle.
  // Allow for different mouse drag directions
  if( StartX < EndX )
    CropLeft = StartX;
  else
     CropLeft = EndX;

  if( StartY < EndY )
    CropTop = StartY;
  else
     CropTop = EndY;

  // Get the height and width of the cropped area
  CropWidth = (float)fabs((double)EndX - StartX);
  CropHeight = (float)fabs((double)EndY - StartY);

  // Crop and repaint the image
  m_Lead1.SetDstClipRect(CropLeft, CropTop, CropWidth, CropHeight);
  m_Lead1.ForceRepaint();
  m_Lead1.SetRubberBandVisible(FALSE);
  m_Lead1.SetMousePointer(0); // Default
  }
}

19. Press Ctrl-Home to go to the top of the current file (tutorDlg.cpp), and add the following to the list of include files:

#include <math.h>

20. Rebuild and run the application.