winforms 在缩放模式下平移图片框中的矩形位置

du7egjpx  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(91)

我确定了图像中的矩形区域,并在PictureBox中将其显示给用户。
由于图像有时会非常大,我使用的是PictureBox,其SizeMode设置为Zoom
我使用以下代码来转换Rectangle(X,Y)坐标:

public Point TranslateZoomMousePosition(Point coordinates)
{
    // test to make sure our image is not null
    if (pictureBox5.Image == null) return coordinates;
    // Make sure our control width and height are not 0 and our 
    // image width and height are not 0
    if (pictureBox5.Width == 0 || pictureBox5.Height == 0 || pictureBox5.Image.Width == 0 || pictureBox5.Image.Height == 0) return coordinates;
    // This is the one that gets a little tricky. Essentially, need to check 
    // the aspect ratio of the image to the aspect ratio of the control
    // to determine how it is being rendered
    float imageAspect = (float)pictureBox5.Image.Width / pictureBox5.Image.Height;
    float controlAspect = (float)pictureBox5.Width / pictureBox5.Height;
    float newX = coordinates.X;
    float newY = coordinates.Y;
    if (imageAspect > controlAspect)
    {
        // This means that we are limited by width, 
        // meaning the image fills up the entire control from left to right
        float ratioWidth = (float)pictureBox5.Image.Width / pictureBox5.Width;
        newX *= ratioWidth;
        float scale = (float)pictureBox5.Width / pictureBox5.Image.Width;
        float displayHeight = scale * pictureBox5.Image.Height;
        float diffHeight = pictureBox5.Height - displayHeight;
        diffHeight /= 2;
        newY -= diffHeight;
        newY /= scale;
    }
    else
    {
        // This means that we are limited by height, 
        // meaning the image fills up the entire control from top to bottom
        float ratioHeight = (float)pictureBox5.Image.Height / pictureBox5.Height;
        newY *= ratioHeight;
        float scale = (float)pictureBox5.Height / pictureBox5.Image.Height;
        float displayWidth = scale * pictureBox5.Image.Width;
        float diffWidth = pictureBox5.Width - displayWidth;
        diffWidth /= 2;
        newX -= diffWidth;
        newX /= scale;
    }
    return new Point((int)newX, (int)newY);
}

在确定的位置添加框架控件:

pictureBox5.Controls.Clear();
var c = new FrameControl();
c.Size = new Size(myrect.Width, myrect.Height);
c.Location=TranslateZoomMousePosition(newPoint(myrect.Location.X,myrect.Location.Y));
pictureBox5.Controls.Add(c);

但是所确定的帧/矩形位置不正确。
我做错了什么?
更新:我正在尝试使用类似的代码将图像上的Rectangle转换为PictureBox上的Frame控件

public Rectangle GetRectangeOnPictureBox(PictureBox p, Rectangle selectionRect,Bitmap bit)
    {
        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 selectionRect;
        int cx = bit.Width / imageRect.Width;
        int cy = bit.Height / imageRect.Height;
        Rectangle trsRectangle = new Rectangle(selectionRect.X * cx, selectionRect.Y * cy, selectionRect.Width * cx, selectionRect.Height * cy);

        trsRectangle.Offset(imageRect.X, imageRect.Y);
        return trsRectangle;
    }

这将产生无效的结果。请咨询

ep6jt1vc

ep6jt1vc1#

您可以通过以下方式将图片框上的选定矩形转换为图像上的矩形:

public RectangleF GetRectangeOnImage(PictureBox p, Rectangle selectionRect)
{
    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 selectionRect;
    var cx = (float)p.Image.Width / (float)imageRect.Width;
    var cy = (float)p.Image.Height / (float)imageRect.Height;
    var r2 = Rectangle.Intersect(imageRect, selectionRect);
    r2.Offset(-imageRect.X, -imageRect.Y);
    return new RectangleF(r2.X * cx, r2.Y * cy, r2.Width * cx, r2.Height * cy);
}

注意:你可以在这里找到ImageRectangleFromSizeMode方法的源代码,并将其作为应用程序代码的一部分编写。

示例-裁剪具有SizeMode = Zoom的PictureBox的图像

例如,以下代码将裁剪图片框1的给定矩形,并将结果设置为图片框2的图像:

var selectedRectangle = new Rectangle(7, 30, 50, 40);
var result = GetRectangeOnImage(pictureBox1, selectedRectangle);
using (var bm = new Bitmap((int)result.Width, (int)result.Height))
{
    using (var g = Graphics.FromImage(bm))
        g.DrawImage(pictureBox1.Image, 0, 0, result, GraphicsUnit.Pixel);
    pictureBox2.Image = (Image)bm.Clone();
}

下面是输入图像:

这就是结果:

olqngx59

olqngx592#

一个专门的类,提供一些帮助工具来确定选择的缩放因子,并将选择坐标转换为缩放的Bitmap坐标。
此 * 版本 * 仅适用于缩放图像。

ZoomFactor类提供了这些方法
PointF TranslateZoomPosition(PointF Coordinates, SizeF ContainerSize, SizeF ImageSize)

返回容器内Point位置的PointF转换坐标到位图内的Point位置,在容器中缩放。

RectangleF TranslateZoomSelection(RectangleF Selection, SizeF ContainerSize, SizeF ImageSize)

返回一个RectangleF,表示在容器内创建的选择,转换为位图坐标。

RectangleF TranslateSelectionToZoomedSel(RectangleF SelectionRect, SizeF ContainerSize, SizeF ImageSize)

返回一个**RectangleF**,表示原始位图的预选区域,该区域转换为容器内的缩放选择图像。

PointF GetImageScaledOrigin(SizeF ContainerSize, SizeF ImageSize)

返回容器内缩放图像原点坐标的PointF引用。

SizeF GetImageScaledSize(SizeF ContainerSize, SizeF ImageSize)

返回在Container中缩放时Image的SizeF引用。
示例用法,演示如何使用在Container控件内创建的Rectangle选择裁剪Bitmap。TranslateZoomSelection方法返回与选择区域对应的Bitmap部分:

ZoomFactor zoomHelper = new ZoomFactor()
Bitmap originalBitmap;

RectangleF currentSelection = [Current Selection Rectangle];
RectangleF bitmapRect = zoomHelper.TranslateZoomSelection(currentSelection, [Container].Size, originalBitmap.Size);

var croppedBitmap = new Bitmap((int)bitmapRect.Width, (int)bitmapRect.Height, originalBitmap.PixelFormat))
using (var g = Graphics.FromImage(croppedBitmap))
{
    g.DrawImage(originalBitmap, new Rectangle(Point.Empty, Size.Round(bitmapRect.Size)), 
                bitmapRect, GraphicsUnit.Pixel);
    [Container].Image = croppedBitmap;
}

上述行为的示例

注意:* 示例中,Portrait中图像的预选将WidthHeight反转 *
ZoomFactor

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);
    }
}

相关问题