在缩放模式 Picturebox 中平移矩形位置导致负 Y 坐标

问题描述

我正在使用以下类 Ref - Translate Rectangle Position in Zoom Mode Picturebox 将位图中的矩形选择转换为在 UI 中的图片框上绘制的帧控件。

public class ZoomFactor
{
    public ZoomFactor() { }

    public PointF TranslateZoomPosition(PointF coordinates,Sizef containerSize,Sizef imageSize)
    {
        PointF imageOrigin = TranslateCoordinatesOrigin(coordinates,containerSize,imageSize);
        float scaleFactor = GetScaleFactor(containerSize,imageSize);
        return new PointF(imageOrigin.X / scaleFactor,imageOrigin.Y / scaleFactor);
    }

    public RectangleF TranslateZoomSelection(RectangleF selectionRect,Sizef imageSize)
    {
        PointF selectionTrueOrigin = TranslateZoomPosition(selectionRect.Location,imageSize);

        Sizef selectionTrueSize = new Sizef(selectionRect.Width / scaleFactor,selectionRect.Height / scaleFactor);
        return new RectangleF(selectionTrueOrigin,selectionTrueSize);
    }

    public RectangleF TranslateSelectionToZoomedSel(RectangleF selectionRect,Sizef imageSize)
    {
        float scaleFactor = GetScaleFactor(containerSize,imageSize);
        RectangleF zoomedSelectionRect = new
            RectangleF(selectionRect.X * scaleFactor,selectionRect.Y * scaleFactor,selectionRect.Width * scaleFactor,selectionRect.Height * scaleFactor);

        PointF imageScaledOrigin = GetimageScaledOrigin(containerSize,imageSize);
        zoomedSelectionRect.Location = new PointF(zoomedSelectionRect.Location.X + imageScaledOrigin.X,zoomedSelectionRect.Location.Y + imageScaledOrigin.Y);
        return zoomedSelectionRect;
    }

    public PointF TranslateCoordinatesOrigin(PointF coordinates,Sizef imageSize)
    {
        PointF imageOrigin = GetimageScaledOrigin(containerSize,imageSize);
        return new PointF(coordinates.X - imageOrigin.X,coordinates.Y - imageOrigin.Y);
    }

    public PointF GetimageScaledOrigin(Sizef containerSize,Sizef imageSize)
    {
        Sizef imageScaleSize = GetimageScaledSize(containerSize,imageSize);
        return new PointF((containerSize.Width - imageScaleSize.Width) / 2,(containerSize.Height - imageScaleSize.Height) / 2);
    }

    public Sizef GetimageScaledSize(Sizef containerSize,imageSize);
        return new Sizef(imageSize.Width * scaleFactor,imageSize.Height * scaleFactor);

    }
    internal float GetScaleFactor(Sizef scaled,Sizef original)
    {
        return (original.Width > original.Height) ? (scaled.Width / original.Width)
                                                  : (scaled.Height / original.Height);
    }
}

// Using the Class
RectangleF BitmapRect = ZoomHelper.TranslateSelectionToZoomedSel(ResizedRect,new Sizef(pBox_preview.Width,pBox_preview.Height),bit.Size);

这适用于大多数输入,但当提供以下输入时,返回的 Y 坐标为负且缩放错误

ResizedRect --> {X = 37 Y = 2 Width = 227 Height = 308} 

PictureBoxSize ---> Sizef(603,423)

imagesize --->  (311,310)

The returned rectangle is this 
{X = 71.73955 Y = -85.15273 Width = 440.131836 Height = 597.1833}

Y 坐标为负。

解决方法

我实际上并没有尝试过你的代码,所以这只是一个偶然的机会: 也许,在您的函数 GetScaleFactor 中,您不想比较 original.Width > original.Height 而是 original.Width/original.Height > scaled.Width/scaled.Height

,

你知道:

  • 如何计算缩放图片框的缩放系数(scale)。
  • 如何获取缩放图片框中的图像偏移量(左上角)。

然后在图像上有一个矩形(原始大小),这就是如何计算缩放图片框上的矩形大小和位置:

  1. 使用垂直和水平比例缩小矩形
  2. 使用缩放图片框的图像偏移来偏移结果。

这里有两种方法:

  • GetRectangeOnImage:在放大的图片框上有矩形,它返回原始图像上的矩形
  • GetRectangeOnPictureBox:具有原始图像上的矩形,它返回缩放后的图片框上的矩形。

代码:

public RectangleF GetRectangeOnImage(PictureBox p,Rectangle rectOnPictureBox)
{
    var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",System.Reflection.BindingFlags.NonPublic | 
        System.Reflection.BindingFlags.Instance);
    var imageRect = (Rectangle)method.Invoke(p,new object[] { p.SizeMode });
    if (p.Image == null)
        return rectOnPictureBox;
    var cx = (float)p.Image.Width / (float)imageRect.Width;
    var cy = (float)p.Image.Height / (float)imageRect.Height;
    rectOnPictureBox.Offset(-imageRect.X,-imageRect.Y);
    return new RectangleF(rectOnPictureBox.X * cx,rectOnPictureBox.Y * cy,rectOnPictureBox.Width * cx,rectOnPictureBox.Height * cy);
}
public RectangleF GetRectangeOnPictureBox(PictureBox p,Rectangle rectOnImage)
{
    var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",new object[] { p.SizeMode });
    if (p.Image == null)
        return rectOnImage;
    var cx = (float)p.Image.Width / (float)imageRect.Width;
    var cy = (float)p.Image.Height / (float)imageRect.Height;
    var r2 = new RectangleF(rectOnImage.X / cx,rectOnImage.Y / cy,rectOnImage.Width / cx,rectOnImage.Height / cy);
    r2.Offset(imageRect.X,imageRect.Y);
    return r2;
}