C# 在PictureBox处于';缩放';模式

C# 在PictureBox处于';缩放';模式,c#,C#,我有一个PictureBox1,它的sizemode设置为Stretch,PictureBox1。PictureBox1包含一个图像,让我选择其中的一部分,然后对其进行裁剪,并将裁剪后的部分存储在PictureBox2中。当sizemode设置为“拉伸”且图片未缩放时,效果非常好,但当我将其缩放或将sizemode设置为“缩放”时效果不佳 我用来裁剪部分图片的代码() 如何正确计算?如何使裁剪功能能够使用户放大/缩小并仍然裁剪图片的正确部分?您需要使用拉伸因子和偏移计算点 对于缩放而言,只有一

我有一个PictureBox1,它的sizemode设置为Stretch,PictureBox1。PictureBox1包含一个图像,让我选择其中的一部分,然后对其进行裁剪,并将裁剪后的部分存储在PictureBox2中。当sizemode设置为“拉伸”且图片未缩放时,效果非常好,但当我将其缩放或将sizemode设置为“缩放”时效果不佳

我用来裁剪部分图片的代码()


如何正确计算?如何使裁剪功能能够使用户放大/缩小并仍然裁剪图片的正确部分?

您需要使用拉伸因子和偏移计算点

对于
缩放
而言,只有一个因素,因为
图像
图片框
的纵横比始终相同,但通常存在一个偏移量;对于
Stretch
您不需要偏移,但需要两个因子

下面是一个例子,它一直使用两个
图片框
两个显示缩放版本和剪切位图。它使用了一个通用函数
ImageArea
,用于确定大小和偏移量

两个类级别变量:

Point pDown = Point.Empty;
Rectangle rect = Rectangle.Empty;
三个鼠标事件:

private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    pDown = e.Location;
    pictureBox1.Refresh();
}

private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (!e.Button.HasFlag(MouseButtons.Left)) return;

    rect = new Rectangle(pDown, new Size(e.X - pDown.X, e.Y - pDown.Y));
    using (Graphics g = pictureBox1.CreateGraphics())
    {
        pictureBox1.Refresh();
        g.DrawRectangle(Pens.Orange, rect);
    }
}

private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    Rectangle iR = ImageArea(pictureBox2);
    rect = new Rectangle(pDown.X - iR.X, pDown.Y - iR.Y, 
                         e.X - pDown.X, e.Y - pDown.Y);
    Rectangle rectSrc = Scaled(rect, pictureBox2, true);
    Rectangle rectDest = new Rectangle(Point.Empty, rectSrc.Size);

    Bitmap bmp = new Bitmap(rectDest.Width, rectDest.Height);
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.DrawImage(pictureBox2.Image, rectDest, rectSrc, GraphicsUnit.Pixel);
    }
    pictureBox2.Image = bmp;
}
下面是一个有用的函数,用于返回任何sizemode的picturebox内的实际图像区域..:

Rectangle ImageArea(PictureBox pbox)
{
    Size si = pbox.Image.Size;
    Size sp = pbox.ClientSize;

    if (pbox.SizeMode == PictureBoxSizeMode.StretchImage) 
       return pbox.ClientRectangle;
    if (pbox.SizeMode == PictureBoxSizeMode.Normal ||
        pbox.SizeMode == PictureBoxSizeMode.AutoSize) 
       return new Rectangle(Point.Empty, si);
    if (pbox.SizeMode == PictureBoxSizeMode.CenterImage)
        return new Rectangle(new Point((sp.Width - si.Width) / 2,
                            (sp.Height - si.Height) / 2), si);

    //  PictureBoxSizeMode.Zoom
    float ri = 1f * si.Width / si.Height;
    float rp = 1f * sp.Width / sp.Height;
    if (rp > ri)
    {
        int width = si.Width * sp.Height / si.Height;
        int left = (sp.Width - width) / 2;
        return new Rectangle(left, 0, width, sp.Height);
    }
    else
    {
        int height = si.Height * sp.Width / si.Width;
        int top = (sp.Height - height) / 2;
        return new Rectangle(0, top, sp.Width, height);
    }
}
我们只需要偏移量来确定未缩放的矩形。我们还需要扩大规模:

Rectangle Scaled(Rectangle rect, PictureBox pbox, bool scale)
{
    float factor = GetFactor(pbox);
    if (!scale) factor = 1f / factor;
    return Rectangle.Round(new RectangleF(rect.X * factor, rect.Y * factor,  
                               rect.Width * factor, rect.Height * factor));
}
为此,需要知道比例因子,它取决于纵横比:

float GetFactor(PictureBox pBox)
{
    if (pBox.Image == null) return 0;
    Size si = pBox.Image.Size;
    Size sp = pBox.ClientSize;
    float ri = 1f * si.Width / si.Height;
    float rp = 1f * sp.Width / sp.Height;
    float factor = 1f * pBox.Image.Width / pBox.ClientSize.Width;
    if (rp > ri) factor = 1f * pBox.Image.Height / pBox.ClientSize.Height;
    return factor;
}

如果
PictureBox
被放大或缩小
,此解决方案也会起作用,方法是将其放置在
自动滚动面板中
,并在缩放时更改
Pbox.Size

,然后拉伸1X==拉伸1Y。我如何将此应用于我的场景?你能再解释一下吗?你的解释对我来说不太清楚@hanspassanty你需要知道显示图像的大小,该方法计算它。只需复制缩放案例的代码。一旦你知道了这个尺寸,你就可以把它除以图像。宽度知道stretch1X。这样就有了弹性。显示的图像将被水平或垂直的字母框,由显示的图像大小和PictureBox.ClientSize之间的差值除以2进行偏移。这有点混乱,你能根据我上面发布的代码发布一些提示代码吗?提前谢谢@HansPassant@Hans你说得很对!有趣的是,我怎么找不到那个帖子。。!?我留下答案是因为它还创建了裁剪图像,并演示了它也可以在缩放模式下工作。工作正常,谢谢
float GetFactor(PictureBox pBox)
{
    if (pBox.Image == null) return 0;
    Size si = pBox.Image.Size;
    Size sp = pBox.ClientSize;
    float ri = 1f * si.Width / si.Height;
    float rp = 1f * sp.Width / sp.Height;
    float factor = 1f * pBox.Image.Width / pBox.ClientSize.Width;
    if (rp > ri) factor = 1f * pBox.Image.Height / pBox.ClientSize.Height;
    return factor;
}