You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PictureBox绘制极小裁剪矩形时Height负数报错的解决方法

解决极小矩形绘制与裁剪时的Height负数异常问题

问题根源

出现负数Height的核心原因是:鼠标向初始点击点的左上方向拖动时,生成的Rectangle未正确调整坐标逻辑,导致矩形的起始Y值大于底部Y值(或起始X大于右侧X),进而使Height/Width为负;或是虽然Size用了绝对值,但矩形起始坐标错误,后续处理时触发异常。


解决方案

1. 新增矩形标准化方法

实现一个工具方法,确保任何传入的矩形都是左上角为最小坐标点、宽高为正的有效矩形:

private Rectangle NormalizeRectangle(Rectangle rect)
{
    int x = Math.Min(rect.X, rect.Right);
    int y = Math.Min(rect.Y, rect.Bottom);
    int width = Math.Abs(rect.Width);
    int height = Math.Abs(rect.Height);
    return new Rectangle(x, y, width, height);
}

2. 修正裁剪方法CropAtRect

在裁剪前先标准化矩形,同时调整验证逻辑允许极小尺寸(如1x1像素),并确保矩形完全约束在图像范围内:

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

    // 标准化矩形,消除负数宽高或反向坐标
    Rectangle normalizedRect = NormalizeRectangle(r);

    // 允许极小矩形(至少1x1),避免误判有效区域
    if (normalizedRect.Width < 1 || normalizedRect.Height < 1)
    {
        MessageBox.Show("Please draw a valid rectangle (at least 1x1 pixel).", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    // 将矩形约束在图像范围内
    int x = Math.Max(normalizedRect.X, 0);
    int y = Math.Max(normalizedRect.Y, 0);
    int width = Math.Min(normalizedRect.Width, b.Width - x);
    int height = Math.Min(normalizedRect.Height, b.Height - y);

    // 再次验证约束后的尺寸有效性
    if (width < 1 || height < 1)
    {
        MessageBox.Show("Selected area is outside the image.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
    }

    Bitmap cropped = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(cropped))
    {
        g.DrawImage(b, new Rectangle(0, 0, width, height), new Rectangle(x, y, width, height), GraphicsUnit.Pixel);
    }

    return cropped;
}

3. 修正鼠标移动时的矩形绘制逻辑

确保拖动鼠标时,实时生成的矩形始终是正确方向,避免绘制与最终裁剪用的矩形不一致:

private void pictureBoxImageToCrop_MouseMove(object sender, MouseEventArgs e)
{
    if (drawnRectangles.Count > 0 && e.Button == MouseButtons.Left)
    {
        var lastRect = drawnRectangles.Last();
        // 直接计算正确矩形:取坐标最小值为左上角,宽高为坐标差的绝对值
        int left = Math.Min(lastRect.Location.X, e.X);
        int top = 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(left, top, width, height);
        pictureBoxImageToCrop.Invalidate();
    }
}

4. 调整MouseDown的初始化逻辑

确保初始矩形的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,
        Rect = new Rectangle(e.Location, Size.Empty), // 初始化空矩形
        DrawingColor = Color.LightGreen,
        PenSize = 3f
    };

    drawnRectangles.Add(newRect);
}

内容的提问来源于stack exchange,提问作者Sharper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 00:55:55