在缩放模式 Picturebox 中平移矩形位置导致负 Y 坐标
Translating Rectangle Position in Zoom Mode Picturebox Results in Negative Y Coordinate
我正在使用以下 class 参考 -
将位图中的矩形选择转换为在 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 containerSize, SizeF imageSize)
{
PointF selectionTrueOrigin = TranslateZoomPosition(selectionRect.Location, containerSize, imageSize);
float scaleFactor = GetScaleFactor(containerSize, imageSize);
SizeF selectionTrueSize = new SizeF(selectionRect.Width / scaleFactor, selectionRect.Height / scaleFactor);
return new RectangleF(selectionTrueOrigin, selectionTrueSize);
}
public RectangleF TranslateSelectionToZoomedSel(RectangleF selectionRect, SizeF containerSize, 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 containerSize, 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, SizeF imageSize)
{
float scaleFactor = GetScaleFactor(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)
- 如何获取缩放图片框内图片的偏移量(左上角)
然后在图像上有一个矩形(原始大小),这是计算缩放图片框上矩形大小和位置的方法:
- 使用垂直和水平比例缩小矩形
- 使用缩放图片框的图像偏移来偏移结果。
以下是两种方法:
- GetRectangeOnImage:在缩放后的图片框上有矩形,returns原始图像上的矩形
- GetRectangeOnPictureBox: 在原始图像上有一个矩形,returns在缩放后的图片框上有一个矩形。
代码:
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",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var imageRect = (Rectangle)method.Invoke(p, 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;
}
我正在使用以下 class 参考 -
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 containerSize, SizeF imageSize)
{
PointF selectionTrueOrigin = TranslateZoomPosition(selectionRect.Location, containerSize, imageSize);
float scaleFactor = GetScaleFactor(containerSize, imageSize);
SizeF selectionTrueSize = new SizeF(selectionRect.Width / scaleFactor, selectionRect.Height / scaleFactor);
return new RectangleF(selectionTrueOrigin, selectionTrueSize);
}
public RectangleF TranslateSelectionToZoomedSel(RectangleF selectionRect, SizeF containerSize, 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 containerSize, 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, SizeF imageSize)
{
float scaleFactor = GetScaleFactor(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)
- 如何获取缩放图片框内图片的偏移量(左上角)
然后在图像上有一个矩形(原始大小),这是计算缩放图片框上矩形大小和位置的方法:
- 使用垂直和水平比例缩小矩形
- 使用缩放图片框的图像偏移来偏移结果。
以下是两种方法:
- GetRectangeOnImage:在缩放后的图片框上有矩形,returns原始图像上的矩形
- GetRectangeOnPictureBox: 在原始图像上有一个矩形,returns在缩放后的图片框上有一个矩形。
代码:
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",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var imageRect = (Rectangle)method.Invoke(p, 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;
}