1

What I want to do is basically cropping a rectangle from an image. However, it should satisfy some special cases:

  1. I want to crop an angled rectangle on image.
  2. I don't want to rotate the image and crop a rectangle :)
  3. If cropping exceeds the image size, I don't want to crop an empty background color.

I want to crop from back of the starting point, that will end at starting point when rectangle size completed. I know I couldn't explain well so if I show what I want visually:

enter image description here

The blue dot is the starting point there, and the arrow shows cropping direction. When cropping exceeds image borders, it will go back to the back of the starting point as much as, when the rectangle width and height finished the end of the rectangle will be at starting point.

Besides this is the previous question I asked:

In this question, I couldn't predict that a problem can occur about image dimensions so I didn't ask for it. But now there is case 3. Except case three, this is exactly same question. How can I do this, any suggestions?

Community
  • 1
  • 1
user1125953
  • 585
  • 2
  • 7
  • 18
  • 1
    Why dont you want to rotate the image and crop that? This obviously shouldnt be visible, just make a copy of your original image. – TJHeuvel Jan 09 '12 at 08:32
  • Add some more Resize steps, the explanation is still complex. – CodingBarfield Jan 09 '12 at 08:42
  • @TJHeuvel I couldn't understand what you said exactly. Rotating the image changes the sizes so the position of starting point is also changed. That's why I don't want to rotate the image – user1125953 Jan 09 '12 at 08:45
  • @CodingBarfield what do you mean by "Resize steps". The explanation may be complex but I don't know how can I be more clear. If you have specific questions, please ask so that I can try to explain more. – user1125953 Jan 09 '12 at 08:49
  • @user1125953 Add an example image including all the steps so we understand what you're looking for. – CodingBarfield Jan 09 '12 at 10:24
  • 1
    @CodingBarfield I will give a point, width, height and angle of rotation information of the rectangle, and of course the image. The code should crop the rectangle from the image. And if it exceeds the size of image, it will continue to crop as I explained before. For example, think of the image I gave; I will give the position of blue dot, and angle (lets say 45 degrees). the code will crop that part. I am able to do it right now but I want to modify it. The problem is the way I am cropping now does not let me to do case 3. So I want a process that I am able to do that. – user1125953 Jan 09 '12 at 11:09
  • 1
    is this the desired result from your example? http://dl.dropbox.com/u/2817180/example.jpg – Rotem Jan 09 '12 at 12:48

1 Answers1

1

What needs to be done is to add offsets to the matrix alignment. In this case I am taking one extra length of the rectangle from each side (total 9 rectangles) and offsetting the matrix each time.

Notice that it is necessary to place offset 0 (the original crop) last, otherwise you will get the wrong result.

Also note that if you specify a rectangle that is bigger than the rotated picture you will still get empty areas.

public static Bitmap CropRotatedRect(Bitmap source, Rectangle rect, float angle, bool HighQuality)
{
    int[] offsets = { -1, 1, 0 }; //place 0 last!
    Bitmap result = new Bitmap(rect.Width, rect.Height);
    using (Graphics g = Graphics.FromImage(result))
    {
        g.InterpolationMode = HighQuality ? InterpolationMode.HighQualityBicubic : InterpolationMode.Default;
        foreach (int x in offsets)
        {
            foreach (int y in offsets)
            {
                using (Matrix mat = new Matrix())
                {
                    //create the appropriate filler offset according to x,y
                    //resulting in offsets (-1,-1), (-1, 0), (-1,1) ... (0,0)
                    mat.Translate(-rect.Location.X - rect.Width * x, -rect.Location.Y - rect.Height * y);
                    mat.RotateAt(angle, rect.Location);
                    g.Transform = mat;
                    g.DrawImage(source, new Point(0, 0));
                }
            }
        }
    }
    return result;
}

To recreate your example:

Bitmap source = new Bitmap("C:\\mjexample.jpg");
Bitmap dest = CropRotatedRect(source, new Rectangle(86, 182, 87, 228), -45, true);
Rotem
  • 21,452
  • 6
  • 62
  • 109
  • There is still some weird results for my pictures in my data set. But it is my responsibility to develop it accordingly. The idea is great by the way :). Thank you very much @Rotem – user1125953 Jan 09 '12 at 13:43