最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to crop image rectangle if the rectangle is very small? - Stack Overflow

programmeradmin1浏览0评论

the problem is that if i draw very small rectangle to crop on picturebox mouse down, move, up events then i see in the CropAtRect method that the r.Height is negative like -180 and therefore it throws exception.

if i draw big enough rectangle on the picturebox then everything is fine.

the question then is how can i draw also very small rectangles and crop them?

private Bitmap CropAtRect(Bitmap b, Rectangle r)
{
    // Ensure bitmap is valid
    if (b == null)
    {
        MessageBox.Show("No image is loaded.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    // Ensure rectangle is valid
    if (r == Rectangle.Empty || r.Width <= 0 || r.Height <= 0)
    {
        MessageBox.Show("Invalid rectangle dimensions.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    if (r.X < 0) r.X = 0;
    if (r.Y < 0) r.Y = 0;
    if (r.Right > b.Width) r.Width = b.Width - r.X;
    if (r.Bottom > b.Height) r.Height = b.Height - r.Y;

    Bitmap cropped = new Bitmap(r.Width, r.Height);
    using (Graphics g = Graphics.FromImage(cropped))
    {
        g.DrawImage(b, new Rectangle(0, 0, r.Width, r.Height), r, GraphicsUnit.Pixel);
    }

    return cropped;
}

the mouse events and paint codes:

private void pictureBoxImageToCrop_Paint(object sender, PaintEventArgs e)
{
    if (checkBoxDrawBorder.Checked)
    {
        ControlPaint.DrawBorder(e.Graphics, pictureBoxImageToCrop.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
    }

    foreach (var rect in drawnRectangles)
    {
        using (Pen pen = new Pen(rect.DrawingColor, rect.PenSize))
        {
            e.Graphics.DrawRectangle(pen, rect.Rect);
        }
    }
}

private void pictureBoxImageToCrop_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left) return;

    if (pictureBoxImageToCrop.Image == null)
    {
        MessageBox.Show("Please load an image first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    if (string.IsNullOrEmpty(selectedCroppedImagesSavedPath))
    {
        MessageBox.Show("Please select a folder to save cropped images.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    DrawingRectangle newRect = new DrawingRectangle()
    {
        Location = e.Location,
        Size = Size.Empty,
        DrawingColor = Color.LightGreen,
        PenSize = 3f
    };

    drawnRectangles.Add(newRect);
}

private void pictureBoxImageToCrop_MouseMove(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0 && e.Button == MouseButtons.Left)
    {
        var lastRect = drawnRectangles.Last();
        lastRect.Size = new Size(Math.Abs(lastRect.Location.X - e.X), Math.Abs(lastRect.Location.Y - e.Y));
        pictureBoxImageToCrop.Invalidate();
    }
}

private void pictureBoxImageToCrop_MouseUp(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0)
    {
        var lastRect = drawnRectangles.Last();
        rectImage = CropAtRect((Bitmap)pictureBoxImageToCrop.Image, lastRect.Rect);
        SaveCroppedImage(lastRect);
        isMouseUp = true;
        drawnRectangles.Remove(lastRect);
        pictureBoxCroppedImages.Invalidate();
    }
}

the problem is that if i draw very small rectangle to crop on picturebox mouse down, move, up events then i see in the CropAtRect method that the r.Height is negative like -180 and therefore it throws exception.

if i draw big enough rectangle on the picturebox then everything is fine.

the question then is how can i draw also very small rectangles and crop them?

private Bitmap CropAtRect(Bitmap b, Rectangle r)
{
    // Ensure bitmap is valid
    if (b == null)
    {
        MessageBox.Show("No image is loaded.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    // Ensure rectangle is valid
    if (r == Rectangle.Empty || r.Width <= 0 || r.Height <= 0)
    {
        MessageBox.Show("Invalid rectangle dimensions.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    if (r.X < 0) r.X = 0;
    if (r.Y < 0) r.Y = 0;
    if (r.Right > b.Width) r.Width = b.Width - r.X;
    if (r.Bottom > b.Height) r.Height = b.Height - r.Y;

    Bitmap cropped = new Bitmap(r.Width, r.Height);
    using (Graphics g = Graphics.FromImage(cropped))
    {
        g.DrawImage(b, new Rectangle(0, 0, r.Width, r.Height), r, GraphicsUnit.Pixel);
    }

    return cropped;
}

the mouse events and paint codes:

private void pictureBoxImageToCrop_Paint(object sender, PaintEventArgs e)
{
    if (checkBoxDrawBorder.Checked)
    {
        ControlPaint.DrawBorder(e.Graphics, pictureBoxImageToCrop.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
    }

    foreach (var rect in drawnRectangles)
    {
        using (Pen pen = new Pen(rect.DrawingColor, rect.PenSize))
        {
            e.Graphics.DrawRectangle(pen, rect.Rect);
        }
    }
}

private void pictureBoxImageToCrop_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left) return;

    if (pictureBoxImageToCrop.Image == null)
    {
        MessageBox.Show("Please load an image first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    if (string.IsNullOrEmpty(selectedCroppedImagesSavedPath))
    {
        MessageBox.Show("Please select a folder to save cropped images.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }

    DrawingRectangle newRect = new DrawingRectangle()
    {
        Location = e.Location,
        Size = Size.Empty,
        DrawingColor = Color.LightGreen,
        PenSize = 3f
    };

    drawnRectangles.Add(newRect);
}

private void pictureBoxImageToCrop_MouseMove(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0 && e.Button == MouseButtons.Left)
    {
        var lastRect = drawnRectangles.Last();
        lastRect.Size = new Size(Math.Abs(lastRect.Location.X - e.X), Math.Abs(lastRect.Location.Y - e.Y));
        pictureBoxImageToCrop.Invalidate();
    }
}

private void pictureBoxImageToCrop_MouseUp(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0)
    {
        var lastRect = drawnRectangles.Last();
        rectImage = CropAtRect((Bitmap)pictureBoxImageToCrop.Image, lastRect.Rect);
        SaveCroppedImage(lastRect);
        isMouseUp = true;
        drawnRectangles.Remove(lastRect);
        pictureBoxCroppedImages.Invalidate();
    }
}
Share edited Mar 7 at 23:18 Sharper asked Mar 7 at 22:46 SharperSharper 695 bronze badges 2
  • 2 Take the registration of mouse movement coordinates from here: How to use the Paint event to draw shapes at mouse coordinates -- You haven't posted the code that generates the Rectangle – Jimi Commented Mar 7 at 23:07
  • @Jimi i see the link now , i will check it. – Sharper Commented Mar 7 at 23:18
Add a comment  | 

1 Answer 1

Reset to default 0

The issue occurs because when drawing very small rectangles, the Height or Width of the Rectangle can become negative, leading to an exception in the CropAtRect method. This happens when the mouse is dragged in an upward or leftward direction, causing the MouseDown coordinates to be greater than the MouseUp coordinates.

Solution:

Ensure Rectangle Always Has Positive Width & Height
Modify MouseMove so that the rectangle's top-left corner always has the smallest X and Y values, and the width and height are always positive.

Fix Rectangle Dimensions in MouseMove
Update your MouseMove event like this:

private void pictureBoxImageToCrop_MouseMove(object sender, MouseEventArgs e)  
{  
    if (drawnRectangles.Count > 0 && e.Button == MouseButtons.Left)  
    {  
        var lastRect = drawnRectangles.Last();  
          
        int x = Math.Min(lastRect.Location.X, e.X);  
        int y = Math.Min(lastRect.Location.Y, e.Y);  
        int width = Math.Abs(lastRect.Location.X - e.X);  
        int height = Math.Abs(lastRect.Location.Y - e.Y);  
  
        lastRect.Rect = new Rectangle(x, y, width, height);  
  
        pictureBoxImageToCrop.Invalidate();  
    }  
}  

Correct the Rectangle Before Passing to CropAtRect
Before calling CropAtRect in MouseUp, ensure that the rectangle always has valid coordinates:

private void pictureBoxImageToCrop_MouseUp(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0)
    {
        var lastRect = drawnRectangles.Last();

        // Ensure valid rectangle dimensions
        int x = Math.Min(lastRect.Rect.Left, lastRect.Rect.Right);
        int y = Math.Min(lastRect.Rect.Top, lastRect.Rect.Bottom);
        int width = Math.Abs(lastRect.Rect.Width);
        int height = Math.Abs(lastRect.Rect.Height);
        Rectangle validRect = new Rectangle(x, y, width, height);

        rectImage = CropAtRect((Bitmap)pictureBoxImageToCrop.Image, validRect);
        SaveCroppedImage(lastRect);
        isMouseUp = true;
        drawnRectangles.Remove(lastRect);
        pictureBoxCroppedImages.Invalidate();
    }
}

发布评论

评论列表(0)

  1. 暂无评论