1

我正在开发一个涉及裁剪图像的 winforms 项目。我的目标是通过使用固定大小的可拖动图片框控件来做到这一点,允许用户选择他们想要保留的区域。

我的问题是当我裁剪图像时;它“有效”,但作物面积略有偏移。这是我得到的结果:

原始图像 裁剪图像

为了澄清,我不是在谈论缩放,这是每个设计。请注意,橙色框主要集中在风暴眼上,但裁剪后的图像不是。

这是我的裁剪操作代码:

private void tsbRecortar_Click(object sender, EventArgs e)
{
    Rectangle recorte = new Rectangle(pbxSeleccion.Location.X, pbxSeleccion.Location.Y, pbxSeleccion.Width, pbxSeleccion.Height);

    foto = recortarImagen(foto, recorte);
    pbxImagen.Image = foto;
}

private Image recortarImagen(Image imagen, Rectangle recuadro)
{
    try
    {
        Bitmap bitmap = new Bitmap(imagen);
        Bitmap cropedBitmap = bitmap.Clone(recuadro, bitmap.PixelFormat);

        return (Image)(cropedBitmap);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error");

        return null;
    }
}

pbxSeleccion是可拖动的橙色矩形;它的父级是pbxImage(我在表单加载时重新设置它的父级)。

如您所见,我使用pbxSeleccion的坐标来定义裁剪区域的起点,但没有按预期工作......有时,我什至会遇到“内存不足”异常。

我认为这与图像在父图片框中的加载方式有关,与“幕后”如何处理边距有关,但我没有尝试修复它......只是改变了偏移的大小。

搜索网络和 SO 对我有很大帮助,但对于这个特定问题,我似乎找不到答案......请随时指出我的代码的改进,我没有长时间编码并且我是 C# 和 .NET 的新手

非常感谢任何帮助。干杯!

4

2 回答 2

1

假设您的原始图像显示在PictureBox. 您传入了橙色裁剪窗口的错误位置。这是为您更正的代码:

private void tsbRecortar_Click(object sender, EventArgs e){
  Point p = yourPictureBox.PointToClient(pbxSelection.PointToScreen(Point.Empty));
  Rectangle recorte = new Rectangle(p.X, p.Y, pbxSeleccion.Width, pbxSeleccion.Height);

  foto = recortarImagen(foto, recorte);
  pbxImagen.Image = foto;
}

我在这里使用PointToClientPointToScreen,因为我认为这是最好的方法。然后,您可以pictureBox安全地更改您的容器,而无需修改代码。如果您使用如下代码,当您想将您pictureBox的容器放入另一个容器中时,它是不够动态的:

Rectangle recorte = new Rectangle(pbxSeleccion.X + yourPictureBox.Left,
                                  pbxSeleccion.Y + yourPictureBox.Top, 
                                  pbxSeleccion.Width, pbxSeleccion.Height);

注意:您也可以像这样使用RectangleToClient和:RectangleToScreen

private void tsbRecortar_Click(object sender, EventArgs e){
   Rectangle recorte = yourPictureBox.RectangleToClient(pbxSeleccion.RectangleToScreen(pbxSeleccion.ClientRectangle));
   foto = recortarImagen(foto, recorte);
   pbxImagen.Image = foto;
}
于 2013-09-21T16:11:02.457 回答
1

尝试使用此代码在图片框中裁剪图像

    public static Image Fit2PictureBox(this Image image, PictureBox picBox)
    {
        Bitmap bmp = null;
        Graphics g;

        // Scale:
        double scaleY = (double)image.Width / picBox.Width;
        double scaleX = (double)image.Height / picBox.Height;
        double scale = scaleY < scaleX ? scaleX : scaleY;

        // Create new bitmap:
        bmp = new Bitmap(
            (int)((double)image.Width / scale),
            (int)((double)image.Height / scale));

        // Set resolution of the new image:
        bmp.SetResolution(
            image.HorizontalResolution,
            image.VerticalResolution);

        // Create graphics:
        g = Graphics.FromImage(bmp);

        // Set interpolation mode:
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;

        // Draw the new image:
        g.DrawImage(
            image,
            new Rectangle(          // Ziel
                0, 0,
                bmp.Width, bmp.Height),
            new Rectangle(          // Quelle
                0, 0,
                image.Width, image.Height),
            GraphicsUnit.Pixel);

        // Release the resources of the graphics:
        g.Dispose();

        // Release the resources of the origin image:
        image.Dispose();

        return bmp;
    }       

    public static Image Crop(this Image image, Rectangle selection)
    {
        Bitmap bmp = image as Bitmap;

        // Check if it is a bitmap:
        if (bmp == null)
            throw new ArgumentException("Kein gültiges Bild (Bitmap)");

        // Crop the image:
        Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);

        // Release the resources:
        image.Dispose();

        return cropBmp;
    }

为 PictureBox 上的鼠标事件编写以下代码

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _selecting = true;
                _selection = new Rectangle(new Point(e.X, e.Y), new Size());
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && _selecting)
            {
                // Create cropped image:
                try
                {
                    Image img = pictureBox1.Image.Crop(_selection);


                    // Fit image to the picturebox:
                    pictureBox1.Image = img.Fit2PictureBox(pictureBox1);
                }
                catch { }
                _selecting = false;
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            // Update the actual size of the selection:
            if (_selecting)
            {
                _selection.Width = e.X - _selection.X;
                _selection.Height = e.Y - _selection.Y;

                // Redraw the picturebox:
                pictureBox1.Refresh();
            }
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (_selecting)
            {
                // Draw a rectangle displaying the current selection
                Pen pen = Pens.LightSkyBlue;
                e.Graphics.DrawRectangle(pen, _selection);
            }
        }

输出画面

  1. 种植前

在此处输入图像描述

  1. 裁剪后

在此处输入图像描述

于 2014-11-13T07:19:14.217 回答