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

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. Add the following private member variables to your main form:

private boolean m_bCropping = false ;  // The state when the mouse is used for cropping
private int m_nStartX = 0 ;  // Starting X position in screen pixels
private int m_nStartY = 0 ;  // Starting Y position in screen pixels
private int m_nEndX = 0;  // Ending X position in screen pixels
private int m_nEndY = 0;  // Ending Y position in screen pixels

3. image\btncmd.gif Select the CommandButton control; then add the control to your main form. Put the control at the top of the form to keep it away from the image.

4. In the Properties box, change the Button control's Text property to Select Rectangle.

5. Add the following code to the Button control's Click event. In online help, you can use the Edit pull-down menu to copy the block of code.

private void button1_click(Object source, Event e)
{
   // Initialize cropping so that you can do it more than once
   if( m_bCropping )
   {
      // Set the clipping area to match the image.
      LEAD1.SetDstClipRect( LEAD1.getDstLeft(), LEAD1.getDstTop(), LEAD1.getDstWidth(), LEAD1.getDstHeight() );

      // Display the image
      LEAD1.ForceRepaint();
   }

   // Set the member variable to let other events know that you are cropping
   m_bCropping = true;

   // Set the pointer to a crosshair
   LEAD1.setMousePointer( (short) 2 );
}

6. In the LEAD1 control's mouseDown event, add the following code. In online help, you can use the Edit pull-down menu to copy the block of code.

private void LEAD1_mouseDown(Object source, MouseEvent e)
{
   // Save the starting position 
   m_nStartX = e.x;
   m_nStartY = e.y;

   // Make the rubberband invisible until the mouse moves
   LEAD1.setRubberBandVisible( false );
}

7. In the LEAD1 control's mouseMove event, add the following code. In online help, you can use the Edit pull-down menu to copy the block of code.

private void LEAD1_mouseMove(Object source, MouseEvent e)
{
   if( m_bCropping && e.button == 1 )
   {
      // Get the current mouse position
      m_nEndX = e.x;
      m_nEndY = e.y;

      // Determine the origin of the rubberband rectangle, regardless of which way the mouse moves.
      int rbX, rbY;
      if( m_nEndX > m_nStartX )
         rbX = m_nStartX;
      else
         rbX = m_nEndX;

      if( m_nEndY > m_nStartY )
         rbY = m_nStartY;
      else
         rbY = m_nEndY;

      // Determine the height and width of the rubberband rectangle
      int rbHeight = Math.abs( m_nStartY - m_nEndY );
      int rbWidth = Math.abs( m_nStartX - m_nEndX );

      // Set the rubberband rectangle 
      LEAD1.SetRubberBandRect( rbX, rbY, rbWidth, rbHeight );

      // Alternatively, you could use the following methods to set the
      // rubberband rectangle.
      // LEAD1.setRubberBandHeight( rbHeight );
      // LEAD1.setRubberBandLeft( rbX );
      // LEAD1.setRubberBandTop( rbY );
      // LEAD1.setRubberBandWidth( rbWidth );

      // Make the rubberband rectangle visible
      LEAD1.setRubberBandVisible( true );
   }
}

8. In the LEAD1 control's mouseUp event, add the following code. In online help, you can use the Edit pull-down menu to copy the block of code.

private void LEAD1_mouseUp(Object source, MouseEvent e)
{
   if( m_bCropping )
   {
      // Get the current mouse position
      m_nEndX = e.x;
      m_nEndY = e.y;

      // Get the origin of the clipping rectangle.
      // Allow for different mouse drag directions
      int nCropLeft, nCropTop;
      if( m_nStartX < m_nEndX )
         nCropLeft = m_nStartX;
      else
         nCropLeft = m_nEndX;

      if( m_nStartY < m_nEndY )
         nCropTop = m_nStartY;
      else
         nCropTop = m_nEndY;

      // Get the height and width of the cropped area
      int nCropWidth = Math.abs( m_nEndX - m_nStartX );
      int nCropHeight = Math.abs( m_nEndY - m_nStartY );

      // Crop and repaint the image
      LEAD1.SetDstClipRect( nCropLeft, nCropTop, nCropWidth, nCropHeight );
      LEAD1.ForceRepaint();
      LEAD1.setRubberBandVisible( false );
      LEAD1.setMousePointer( (short) 0 );  // Default
   }
}

9. image\btncmd.gif Select the Button control; then add another control to your main form. Put the control at the top of the form to keep it away from the image.

10. In the Properties box, change the Button control's Text property to Trim. This button will be used to trim the bitmap in memory and redisplay the bitmap.

11. Add the following code to the Button control's Click event. In online help, you can use the Edit pull-down menu to copy the block of code.

private void button2_click(Object source, Event e)
{
   setCursor( Cursor.WAIT );  // 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.
   float fXFactor = LEAD1.getBitmapWidth() / LEAD1.getDstWidth();
   float fYFactor = LEAD1.getBitmapHeight() / LEAD1.getDstHeight();
   int nNewTop = (int) ( ( LEAD1.getDstClipTop() - LEAD1.getDstTop() ) * fYFactor );
   int nNewLeft = (int) ( ( LEAD1.getDstClipLeft() - LEAD1.getDstLeft() ) * fXFactor );
   int nNewWidth = (int) ( LEAD1.getDstClipWidth() * fXFactor );
   int nNewHeight = (int) ( LEAD1.getDstClipHeight() * fYFactor );

   // Make sure display rectangles are automatically adjusted.
   LEAD1.setAutoSetRects( true );

   // Trim the bitmap.
   LEAD1.Trim( nNewLeft, nNewTop, nNewWidth, nNewHeight );

   // Size and redisplay the control, using the new bitmap size.
   // Set the variables used for preserving the aspect ratio.
   // Allow for a border of 1/8 of the form size.
   // The units of measure do not matter, since we are calculating proportions.
   int nHeightFactor = (int) LEAD1.getBitmapHeight();
   int nWidthFactor = (int) LEAD1.getBitmapWidth();
   int nHeightAllowed = getSize().y - ( getSize().y / 4 );
   int nWidthAllowed = getSize().x - ( getSize().x / 4 );

   // Center the LEAD control on the form, preserving the aspect ratio.
   // Check to see if using the maximum width will make the image too tall.
   // Set the dimensions based on the result.
   if( ( ( nWidthAllowed * nHeightFactor ) / nWidthFactor ) < nHeightAllowed )
   {
      LEAD1.setLeft( getSize().x / 8 );
      LEAD1.setWidth( nWidthAllowed );
      LEAD1.setHeight( ( LEAD1.getWidth() * nHeightFactor) / nWidthFactor );
      LEAD1.setTop( ( getSize().y - LEAD1.getHeight() ) / 2 );
   }
   else
   {
      LEAD1.setTop( getSize().y / 8 );
      LEAD1.setHeight( nHeightAllowed );
      LEAD1.setWidth( ( LEAD1.getHeight() * nWidthFactor) / nHeightFactor );
      LEAD1.setLeft( ( getSize().x - LEAD1.getWidth() ) / 2 );
   }

   // Turn off scroll bars to make sure we use the full client area.
   LEAD1.setAutoScroll( false );

   // Set the image display size to match the LEAD control
   LEAD1.SetDstRect( 0, 0, LEAD1.getScaleWidth(), LEAD1.getScaleHeight() );
   LEAD1.SetDstClipRect( 0, 0, LEAD1.getScaleWidth(), LEAD1.getScaleHeight() );

   // Display the image
   LEAD1.ForceRepaint();

   setCursor( Cursor.DEFAULT );  // Default
}

12. Run your program to test it.