【问题标题】:Crop image using a fixed-size draggable picturebox使用固定大小的可拖动图片框裁剪图像
【发布时间】:2013-09-21 05:29:05
【问题描述】:

我正在处理一个涉及裁剪图像的 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 的坐标来定义裁剪区域的起点,但没有按预期工作......有时,我什至会得到一个“Out内存”异常。

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

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

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

【问题讨论】:

    标签: c# .net winforms image crop


    【解决方案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);
    

    注意:您也可以像这样使用RectangleToClientRectangleToScreen

    private void tsbRecortar_Click(object sender, EventArgs e){
       Rectangle recorte = yourPictureBox.RectangleToClient(pbxSeleccion.RectangleToScreen(pbxSeleccion.ClientRectangle));
       foto = recortarImagen(foto, recorte);
       pbxImagen.Image = foto;
    }
    

    【讨论】:

    • 太棒了,就像一个魅力!感谢您抽出时间回复。我注意到部分错误来自我将 pbxImagen 中加载的图像的 SizeMode 设置为 CenterImage。可以做到,但是一旦图像居中,我需要考虑左边距 - 我会处理并更新它。
    【解决方案2】:

    试试这个代码来裁剪图片框中的图像

        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. 裁剪后

    【讨论】:

      猜你喜欢
      • 2015-02-15
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-18
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多