如何放大一个面板内的图片框的绘制矩形?

时间:2016-08-23 07:13:30

标签: c# winforms zoom panel picturebox

我在面板中有一个 PictureBox,以便缩放和平移。我创建了用鼠标单击选择4个点并在PictureBox上绘制一个矩形的可能性。一旦矩形在我的图片上,我将矩形的坐标传递给方法“cropRectangle”。此方法裁剪矩形并将旧图像替换为裁剪后的图像。 效果很好

OriginalImage是pictureBox中实际图像的位图

private void cropRectangle(Rectangle rect){
    double left = (rect.X) * originalImage.Width / pictureBox.Width,
    top = (rect.Y) * originalImage.Width / pictureBox.Height,
    right = (rect.Width) * originalImage.Width / pictureBox.Width,
    bottom = (rect.Height) * originalImage.Height / pictureBox.Height;
    rect = new Rectangle (Convert.ToInt32(left), Convert.ToInt32(top), Convert.ToInt32(right), Convert.ToInt32(bottom));

    Bitmap bitmap = orignalImage.Clone(rect, originalImage.PixelFormat);
    pictureBox.Image = (Image)bitmap; 

    centerPictureBox();

    // fit image into pictureBox with respect to the ratio
    float ratio = orignalImage.Width / orignalImage.Height;
    pictureBox.Width = panel.Width;
    pictureBox.Height = Convert.ToInt32(pictureBox.Width * ratio);
    centerPictureBox();
}

我现在要做的是缩放所选区域而不是裁剪它。图片框的矩形必须与面板匹配。

如何通过面板仅显示图片框的选定区域(矩形)而不裁剪图像?

3 个答案:

答案 0 :(得分:1)

您应该坚持使用Bitmap对象修改现有的Graphics,而不是更改PictureBox的大小。当所需功能已在其他地方可用时,您不希望与UI控件绑定。

以下是实现这一目标的粗略步骤:

  1. 创建一个临时Bitmap对象,用于存储缩放的图像。 Bitmap tBitmap = new Bitmap(zoomX, zoomY, PixelFormat.Format24bppRgb);
  2. 当您想要缩放时,计算缩放因子和你已经做的事情(我没有检查代码是否正确,但我认为是这样)。
  3. 从临时位图创建一个新的Graphics对象。 Graphics graphics = Graphics.FromImage(tBitmap);
  4. 设置InterpolationMode,以便以高质量缩放图像。 graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
  5. 使用DrawImage方法(使用PictureBox中的原始图像)绘制缩放图像。 graphics.DrawImage(pictureBox.Image, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height), new Rectangle(/*The crop rectangle you draw already*/), GraphicsUnit.Pixel);
  6. 将新绘制的位图设置为PictureBox中的图像。 pictureBox.Image = tBitmap;
  7. 请记住处理我们用于绘图的图形对象。 graphics.Dispose();
  8. 您可能需要刷新PictureBox以强制它重绘自己。 pictureBox.Refresh();
  9. 这些是要遵循的基本步骤。我没有时间深入了解您现有的代码,因此您可能需要更改一些其他内容才能使其正常工作。

    这里还有一篇MSDN文章,其中涵盖了相同的内容:Cropping and Scaling Images in GDI+

答案 1 :(得分:1)

您可能对此控件(ZoomPicBox)感兴趣,它允许缩放和平移图片框。

此代码的所有功劳都归功于鲍勃鲍威尔,它来自他的网站(现在似乎已经停止了很长一段时间。)

我通过以下链接复制了archive.org中的代码:

  

https://web.archive.org/web/20080313161349/http://www.bobpowell.net/zoompicbox.htm

该链接有其他信息,值得一读。该代码也可以在VB.Net中找到。

我不知道为什么鲍勃鲍威尔的网站已关闭,但它是Windows图形信息的绝佳网站。

我觉得这段代码值得重复。可以将此控件拖到表单上。

namespace bobpowell.net
{
  /// <summary>
  /// ZoomPicBox does what it says on the wrapper.
  /// </summary>
  /// <remarks>
  /// PictureBox doesn't lend itself well to overriding. Why not start with something basic and do the job properly?
  /// </remarks>
  public class ZoomPicBox : ScrollableControl
  {

    Image _image;
    [
    Category("Appearance"),
    Description("The image to be displayed")
    ]
    public Image Image
    {
      get{return _image;}
      set
      {
        _image=value;
        UpdateScaleFactor();
        Invalidate();
      }
    }

    float _zoom=1.0f;
    [
    Category("Appearance"),
    Description("The zoom factor. Less than 1 to reduce. More than 1 to magnify.")
    ]
    public float Zoom
    {
      get{return _zoom;}
      set
      {
        if(value<0 || value<0.00001)
          value=0.00001f;
        _zoom=value;
        UpdateScaleFactor();
        Invalidate();
      }
    }

    /// <summary>
    /// Calculates the effective size of the image
    ///after zooming and updates the AutoScrollSize accordingly
    /// </summary>
    private void UpdateScaleFactor()
    {
      if(_image==null)
        this.AutoScrollMinSize=this.Size;
      else
      {
        this.AutoScrollMinSize=new Size(
          (int)(this._image.Width*_zoom+0.5f),
          (int)(this._image.Height*_zoom+0.5f)
          );
      }
    }

    InterpolationMode _interpolationMode=InterpolationMode.High;
    [
    Category("Appearance"),
    Description("The interpolation mode used to smooth the drawing")
    ]
    public InterpolationMode InterpolationMode
    {
      get{return _interpolationMode;}
      set{_interpolationMode=value;}
    }


    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
      // do nothing.
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      //if no image, don't bother
      if(_image==null)
      {
        base.OnPaintBackground(e);
        return;
      }
      //Set up a zoom matrix
      Matrix mx=new Matrix(_zoom,0,0,_zoom,0,0);
      //now translate the matrix into position for the scrollbars
      mx.Translate(this.AutoScrollPosition.X / _zoom, this.AutoScrollPosition.Y / _zoom);
      //use the transform
      e.Graphics.Transform=mx;
      //and the desired interpolation mode
      e.Graphics.InterpolationMode=_interpolationMode;
      //Draw the image ignoring the images resolution settings.
      e.Graphics.DrawImage(_image,new Rectangle(0,0,this._image.Width,this._image.Height),0,0,_image.Width, _image.Height,GraphicsUnit.Pixel);
      base.OnPaint (e);
    }


    public ZoomPicBox()
    {
      //Double buffer the control
      this.SetStyle(ControlStyles.AllPaintingInWmPaint |
        ControlStyles.UserPaint |
        ControlStyles.ResizeRedraw |
        ControlStyles.UserPaint |
        ControlStyles.DoubleBuffer, true);

      this.AutoScroll=true;
    }
  }
}

答案 2 :(得分:0)

我找到了解决问题的优雅方法:

private void zoomInsideRectangle(Rectangle rect){
    float zoomFactor = ((float)panel.Width / rect.Width) - 1;

    pictureBox.Width = pictureBox.Width + convertToIntPerfect(pictureBox.Width * zoomFactor);
    pictureBox.Height = pictureBox.Height + convertToIntPerfect(pictureBox.Height * zoomFactor);

    rect.X = rect.X + convertToIntPerfect(rect.X * zoomFactor);
    rect.Y = rect.Y + convertToIntPerfect(rect.Y * zoomFactor);

    pictureBox.Left = convertToIntPerfect(-rect.X);
    pictureBox.Top = convertToIntPerfect(-rect.Y);
}

因为我知道面板的长度,我可以看到图片框。我采用面板的比例和我要放大的矩形的宽度。这个比例是我的缩放。

我将图片框的大小乘以我计算的比率。

我将图片框左侧和顶部用我的矩形坐标锚定。但在此之前我必须将我的矩形坐标与zoomratio相乘,因为我改变了图片框的大小。

我没有实现Y转换,因为图像的原始比例将被损坏。