C# Windows 窗体 PictureBox:控件坐标和图像中像素位置之间的转换

C# WindowsForms PictureBox: Transformation between control coordinates and pixel position in image

我有一个带有 PictureBox 的控件。 PictureBox 显示图像(在缩放模式下,至少在这种特殊情况下)。我需要做两种事情:

显然,我需要在控制坐标和图像中像素的(行,列)之间进行某种坐标转换。我可能找到了第一个 (www.codeproject.com/Articles/20923/Mouse-Position-over-Image-in-a-PictureBox),但反之则不然。有什么想法吗?

我可以建议 "workaround":您不要在 PictureBox 上绘制线条等,而是使用其 Graphics 在位图本身上绘制。那么就可以只使用图像坐标(行,列),不需要从控件转换为图像。反过来(从鼠标点击到行和列),如你所说,已解决,可以使用。

在尝试在位图上绘制图形元素而不是在包含 PictureBox 上绘制图形元素后,我发现这种方法很笨拙:它带来的问题多于它解决的问题。我回到了 TaW 的提议( 函数 SetImageScale(PictureBox pbox, out RectangleF rectImage, out float zoom)。)

如果您知道 rectImage 矩形(TaW 代码中的 ImgArea),那么两种转换(到控件的坐标以及图像的列和行)都非常简单:

    /// <summary>
    /// Converts coordinates of a point from the picture box grid into column and row of its image.
    /// </summary>
    /// <param name="pb">The PictureBox.</param>
    /// <param name="ptControl">The point in picture box coordinates (X, Y).</param>
    /// <returns>Point in image coordinates (column, row).</returns>
    private Point ToImageCoordinates(PictureBox pb, Point ptControl)
    {
        if (pb.Image == null)
        {
            return new Point(Int32.MinValue, Int32.MinValue);
        }

        float deltaX    = ptControl.X - rectImage.Left;
        float deltaY    = ptControl.Y - rectImage.Top;

        int column      = (int)(deltaX * (pb.Image.Width / rectImage.Width) + 0.5);
        int row         = (int)(deltaY * (pb.Image.Height / rectImage.Height) + 0.5);

        return new Point(column, row);
    }

    /// <summary>
    /// Converts coordinates of a point from the grid (column, row) into the coordinate system of the picture box.
    /// </summary>
    /// <param name="pb">The PictureBox.</param>
    /// <param name="ptImage">The point in image coordinates (column, row).</param>
    /// <returns>Point in control coordinates (X, Y).</returns>
    private PointF ToControlCoordinates(PictureBox pb, Point ptImage)
    {
        if (pb.Image == null)
        {
            return new Point(Int32.MinValue, Int32.MinValue);
        }

        float deltaX    = ptImage.X * (rectImage.Width / pb.Image.Width);
        float deltaY    = ptImage.Y * (rectImage.Height / pb.Image.Height);

        return new PointF(deltaX + rectImage.Left, deltaY + rectImage.Top);
    }

这些功能已经过测试,似乎可以正常工作。

记住:这些转换仅在 PictureBox 处于 Zoom 模式时有效。