Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get an image from a rectangle?

I'm making a program that's cropping images. I have two PictureBoxes and a Button named 'crop'. One picture box contains an image and when I select a rectangle in it and press 'Crop' the selected area appears in the other picture box; so the program is working when I press crop. The problem is: How can I get the image from crop area into picture box Image?

 Rectangle rectCropArea;
 Image srcImage = null;

 TargetPicBox.Refresh();
 //Prepare a new Bitmap on which the cropped image will be drawn
 Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Width, SrcPicBox.Height);
 Graphics g = TargetPicBox.CreateGraphics();

 g.DrawImage(sourceBitmap, new Rectangle(0, 0, TargetPicBox.Width, TargetPicBox.Height), 
 rectCropArea, GraphicsUnit.Pixel);

 //Good practice to dispose the System.Drawing objects when not in use.
 sourceBitmap.Dispose();

 Image x = TargetPicBox.Image;

The problem is that x = null and the image is showing in the picture box so how can I get the Image from this picture box into the Image variable ?

like image 788
user3742682 Avatar asked May 01 '15 08:05

user3742682


1 Answers

A couple of issues:

  • First and most important: You are being confused about the relationship between PictureBox.Image (a Property) and the Graphics you associate with the PictureBox's surface. The Graphics object you get from Control.CreateGraphics is only able to paint onto the surface of the control; usually not what you want; and even when you do, you usually want to do it in a Paint event using e.Graphics..

So, while your code seems to work, it only paints non-persistent pixels onto the surface. Minimize/maximize and you'll see what non-persistent means..!

To change a Bitmap bmp you need to associate it with a Grahics object like this:

Graphics g = Graphics.FromImage(bmp);

Now you can draw into it:

g.DrawImage(sourceBitmap, targetArea, sourceArea, GraphicsUnit.Pixel);

After that you can assign the Bitmap to the Image Property of the TargetPicBox..

Finally dispose of the Graphics, or better, put it into a using clause..

I am assuming that you have managed to give the rectCropArea meaningful values.

  • Also note that the way you copy the source bitmap has an error: If you want the full image, do use its Size (*), not the one of the PictureBox!!

  • And instead of creating a target rectangle, with the same error, simply use the TargetPicBox.ClientRectangle!

Here is an example code for the crop Button:

 // a Rectangle for testing
 Rectangle rectCropArea = new Rectangle(22,22,55,99);
 // see the note below about the aspect ratios of the two rectangles!!
 Rectangle targetRect = TargetPicBox.ClientRectangle;
 Bitmap targetBitmap = new Bitmap(targetRect.Width, targetRect.Height);
 using (Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image,
                              SrcPicBox.Image.Width, SrcPicBox.Image.Height) )
 using (Graphics g = Graphics.FromImage(targetBitmap))
        g.DrawImage(sourceBitmap, targetRect, rectCropArea, GraphicsUnit.Pixel);

 if (TargetPicBox.Image != null) TargetPicBox.Dispose();
 TargetPicBox.Image = targetBitmap;
  • Of course you should have prepared the Rectangle in the proper mouse events!
  • Here you would want to decide on the aspect ratio of the result; you probably don't want to distort the result! So you need to decide whether to crop the source cropping rectangle or whether to expand the target rectangle..!
  • Unless you are sure about the dpi resolution you should use SetResolution to make sure the new image has the same!

Note that since I assign targetBitmap to TargetPicBox.Image I must not dipose of it! Instead, before assigning a new Image, I first Dispose the old one..

like image 72
TaW Avatar answered Sep 22 '22 05:09

TaW