Search code examples
c#imagecropmousedowndrawrectangle

Crop code is offset to the right and not the on the mouse position


I have been working on a cropping form for my database management system. However there is an annoying caveat, the rectangle that is drawn is offset to the right and isn't starting on the mouse position when I press down the left mouse button.

This is my code. I would appreciate it if you can tell me where I messed up.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace Student_File
{

    public partial class fUpload : Form
    {
        public fUpload()
        {
            InitializeComponent();
        }
        private Bitmap OriginalImage;

        // True when we're selecting a rectangle.
        private bool IsSelecting = false;

        // The area we are selecting.
        private int X0, Y0, X1, Y1;
        private void BtnUpload_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog1 = new OpenFileDialog())
            {
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    lblFileName.Text = Path.GetFileName(openFileDialog1.FileName);
                    pictureBoxOriginal.Image = Image.FromFile(openFileDialog1.FileName);
                    OriginalImage = (Bitmap)pictureBoxOriginal.Image;
                }
            }
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            pictureBoxCropped.Image.Save(@""+ Environment.CurrentDirectory +"Temp/Temp.Jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
        }

        private void pb1_MouseUp(object sender, MouseEventArgs e)
        {
            // Do nothing it we're not selecting an area.
            if (!IsSelecting) return;
            IsSelecting = false;

            // Display the original image.
            pictureBoxOriginal.Image = OriginalImage;

            // Copy the selected part of the image.
            int wid = Math.Abs(X0 - X1);
            int hgt = Math.Abs(Y0 - Y1);
            if ((wid < 1) || (hgt < 1)) return;

            Bitmap area = new Bitmap(wid, hgt);
            using (Graphics gr = Graphics.FromImage(area))
            {
                Rectangle source_rectangle =
                    new Rectangle(Math.Min(X0, X1), Math.Min(Y0, Y1),
                        wid, hgt);
                Rectangle dest_rectangle =
                    new Rectangle(0, 0, wid, hgt);
                gr.DrawImage(OriginalImage, dest_rectangle,
                    source_rectangle, GraphicsUnit.Pixel);
            }
            // Display the result.
            pictureBoxCropped.Image = area;
        }

        private void pb1_MouseDown(object sender, MouseEventArgs e)
        {
            IsSelecting = true;

            // Save the start point.
            X0 = e.X;
            Y0 = e.Y;
        }

        private void pb1_MouseMove(object sender, MouseEventArgs e)
        {
            // Do nothing it we're not selecting an area.
            if (!IsSelecting) return;

            // Save the new point.
            X1 = e.X;
            Y1 = e.Y;

            // Make a Bitmap to display the selection rectangle.
            Bitmap bmp = new Bitmap(OriginalImage);

            // Draw the rectangle.
            using (Graphics gr = Graphics.FromImage(bmp))
            {
                gr.DrawRectangle(Pens.Red,
                    Math.Min(X0, X1), Math.Min(Y0, Y1),
                    Math.Abs(X0 - X1), Math.Abs(Y0 - Y1));
            }

            // Display the temporary bitmap.
            pictureBoxOriginal.Image = bmp;
        }
        
    }
}

Solution

  • You need to get the offset from the form

    PropertyInfo imageRectProperty = typeof(PictureBox).GetProperty("ImageRectangle",                               BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance);
    var value = imageRectProperty.GetValue(pictureBoxOriginal, null);
    if (value == null)
        return;
    Rectangle rectangle = (Rectangle)value;
    
    if (rectangle.Contains(e.Location))
    {
        // this is your coordinate on image, not on form
        var y = e.Y - rectangle.Y;
        var x = e.X - rectangle.X;
    }
    

    Picture