DeveloperLV
DeveloperLV

Reputation: 1781

Cropping Image is not cropping correctly

I have followed a YouTube Tutorial on how to create a cropping image application.

Goal:

My Goal is simply load a screenshot image into PictureBox1.

Then mark an area with a Red Rectangle to crop and display into PictureBox2.

Here is the code:

public partial class Form18 : Form
{
    Rectangle Rect;

    Point LocationXY;
    Point LocationX1Y1;

    bool IsMouseDown = false;




    public Form18()
    {
        InitializeComponent();
    }


    private void Form18_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        //Clipboard image
        pictureBox1.Image = Clipboard.GetImage();
    }


    private void picturebox1_MouseDown(object sender, MouseEventArgs e)
    {
        IsMouseDown = true;
        LocationXY = e.Location;
    }

    private void picturebox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (IsMouseDown == true)
        {
            LocationX1Y1 = e.Location;

            Refresh();
        }
    }

    private void picturebox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (IsMouseDown == true)
        {
            LocationX1Y1 = e.Location;

            IsMouseDown = false;

            if (Rect != null)
            {
                Bitmap bit = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);

                Bitmap cropImg = new Bitmap(Rect.Width, Rect.Height);

                Graphics g = Graphics.FromImage(cropImg);
                g.DrawImage(bit, 0, 0, Rect, GraphicsUnit.Pixel);
                pictureBox2.Image = cropImg;
            }
        }
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (Rect != null)
        {
            e.Graphics.DrawRectangle(Pens.Red, GetRect());
        }
    }
    private Rectangle GetRect()
    {
        Rect = new Rectangle();

        Rect.X = Math.Min(LocationXY.X, LocationX1Y1.X);

        Rect.Y = Math.Min(LocationXY.Y, LocationX1Y1.Y);

        Rect.Width = Math.Abs(LocationXY.X - LocationX1Y1.X);

        Rect.Height = Math.Abs(LocationXY.Y - LocationX1Y1.Y);

        return Rect;
    }

}

Output:

And here is the output output:

On the left hand side - you can see the screenshot input and on the right hand side - you can see the cropped image.

I do not understand - the rectangle marked in Red does not crop the image correctly? - it shows different area of the screenshot image.

Where is the going wrong?

Screenshot

Upvotes: 2

Views: 276

Answers (2)

user10216583
user10216583

Reputation:

Instead of flooding the memory with disposable Graphics and Bitmap objects in the MouseUp event of the PictureBox1, handle the Paint event of PictureBox2 and use the supported Graphics object to draw, and just use the e.Graphics.DrawImage overload to pass the source and destination rectangles.

//...
private Point LocationXY;
private Point LocationX1Y1;

private void button1_Click(object sender, EventArgs e)
{
    if (Clipboard.ContainsImage())
    {
        pictureBox1.Image?.Dispose();
        pictureBox1.Image = Clipboard.GetImage();
    }
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Left)
        LocationXY = e.Location;
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        LocationX1Y1 = e.Location;
        pictureBox1.Invalidate();
    }
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Left)
    {
        LocationX1Y1 = e.Location;

        pictureBox1.Invalidate();
        pictureBox2.Invalidate();
    }
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (MouseButtons == MouseButtons.Left)
        e.Graphics.DrawRectangle(Pens.Red, GetRect());
}

private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
    var src = GetRect();

    if (src == Rectangle.Empty) return;

    var des = new Rectangle(0, 0, src.Width, src.Height);

    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    e.Graphics.CompositingQuality = CompositingQuality.HighQuality;

    e.Graphics.DrawImage(pictureBox1.Image,
        des, src, GraphicsUnit.Pixel);
}

private Rectangle GetRect()
{
    return new Rectangle(
        Math.Min(LocationXY.X, LocationX1Y1.X),
        Math.Min(LocationXY.Y, LocationX1Y1.Y),
        Math.Abs(LocationXY.X - LocationX1Y1.X),
        Math.Abs(LocationXY.Y - LocationX1Y1.Y)
        );
}
//...

Use the following to get the cropped image:

//...
private Bitmap GetCroppedImage()
{
    var src = GetRect();

    if (src == Rectangle.Empty) return null;

    var des = new Rectangle(0, 0, src.Width, src.Height);
    var b = new Bitmap(src.Width, src.Height);

    using (var g = Graphics.FromImage(b))
    {
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.CompositingQuality = CompositingQuality.HighQuality;

        g.DrawImage(pictureBox1.Image, des, src, GraphicsUnit.Pixel);
    }
    return b;
}
//...

Then you can save it like:

private void Save()
{
    using (var d = new SaveFileDialog())
    {
        d.Filter = "PNG|*.png|JPEG|*.jpeg;*.jpg|BMP|*.bmp";

        if (d.ShowDialog() != DialogResult.OK) return;

        using (var b = GetCroppedImage())
        {
            if (b == null) return;

            ImageFormat f;

            switch (d.FilterIndex)
            {
                case 2:
                    f = ImageFormat.Jpeg;
                    break;
                case 3:
                    f = ImageFormat.Bmp;
                    break;
                default:
                    f = ImageFormat.Png;
                    break;
            }

            b.Save(d.FileName, f);
        }
    }
}

SOQ60819266

Upvotes: 4

AJITH
AJITH

Reputation: 1175

Setting the SizeMode to Normal may not crop the image with the following code

Bitmap bit = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
Bitmap cropImg = new Bitmap(Rect.Width, Rect.Height);

The cropping will be relative to the Picturebox width and height.

Change the new Bitmap line to the following

Bitmap bit = new Bitmap(pictureBox1.Image, pictureBox1.Image.Width, pictureBox1.Image.Height);
Bitmap cropImg = new Bitmap(Rect.Width, Rect.Height);

OR Set the SizeMode of the picturebox to StretchImage

this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;

Upvotes: 0

Related Questions