将图像适配到PictureBox中

83
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
    myDatabaseConnection.Open();
    using (SqlCommand SqlCommand = new SqlCommand("Select Photo from Employee where EmpID LIKE '%' + @EmpID + '%' ", myDatabaseConnection))
    {
        SqlCommand.Parameters.AddWithValue("@EmpID", textBox1.Text);
        var DS = new DataSet();
        var adapter = new SqlDataAdapter(SqlCommand);
        adapter.Fill(DS, "Images");

        var imagesTable = DS.Tables["Images"];
        var imagesRows = imagesTable.Rows;
        var count = imagesRows.Count;

        if (count <= 0) return;

        var imageColumnValue =
            imagesRows[count - 1]["Image"];
        if (imageColumnValue == DBNull.Value)
            return;

        var data = (Byte[])imageColumnValue;
        using (var stream = new MemoryStream(data))
        {
            pictureBox1.Image = Image.FromStream(stream);
        }

    }
}
如果图片太大无法适应picturebox,需要什么代码才能让图片适应picturebox
我的picturebox是正方形的,如果图片是矩形的,如何裁剪并在picturebox中显示它,就像这张图片一样,图片的下部分将被裁剪。
11个回答

128

首先,要让任何图像“调整大小”以适应picturebox,您可以设置 PictureBox.SizeMode = PictureBoxSizeMode.StretchImage

如果您想预先裁剪图像(即剪掉侧面或顶部和底部),那么您需要清楚地定义所需的行为(从顶部开始,填充图片框的高度并裁剪剩余部分,还是从底部开始,将图片框的高度填满到顶部等),使用picturebox和图像的Height / Width属性裁剪图像并获得所需效果应该相对简单。


30

使用以下代码行,您将找到解决方案...

pictureBox1.ImageLocation = @"C:\Users\Desktop\mypicture.jpg";
pictureBox1.SizeMode =PictureBoxSizeMode.StretchImage;

26

请查看picturebox的sizemode属性。

pictureBox1.SizeMode =PictureBoxSizeMode.StretchImage;

13

您可以将 PictureBox 的 SizeMode 属性设置为 PictureSizeMode.Zoom,这将增大较小图像的大小或减小较大图像的大小以填充 PictureBox。


顺便说一下,我在Zoom中遇到了一个奇怪的错误。尽管在Visual Studio中设置为Zoom,但在代码中设置Image字段后,我必须再次在代码中将SizeMode设置为Zoom。否则,它不会缩小大图像。(我使用断点验证了它在设置图像时确实是Zoom,但直到我再次运行并设置Zoom的代码行才会缩小。经过两天的多次测试,以确保这确实发生了。) - ToolmakerSteve

13

伊玛目马赫迪aj

属性部分中的SizeMode更改

您可以使用属性部分


8

PictureBox.SizeMode选项缺少“fill”或“cover”模式,它类似于缩放,但会裁剪图片以确保填充图片框。在CSS中,这是“cover”选项。

下面的代码可以启用此功能:

static public void fillPictureBox(PictureBox pbox, Bitmap bmp)
{
    pbox.SizeMode = PictureBoxSizeMode.Normal;
    bool source_is_wider = (float)bmp.Width / bmp.Height > (float)pbox.Width / pbox.Height;

    var resized = new Bitmap(pbox.Width, pbox.Height);
    var g = Graphics.FromImage(resized);        
    var dest_rect = new Rectangle(0, 0, pbox.Width, pbox.Height);
    Rectangle src_rect;

    if (source_is_wider)
    {
        float size_ratio = (float)pbox.Height / bmp.Height;
        int sample_width = (int)(pbox.Width / size_ratio);
        src_rect = new Rectangle((bmp.Width - sample_width) / 2, 0, sample_width, bmp.Height);
    }
    else
    {
        float size_ratio = (float)pbox.Width / bmp.Width;
        int sample_height = (int)(pbox.Height / size_ratio);
        src_rect = new Rectangle(0, (bmp.Height - sample_height) / 2, bmp.Width, sample_height);
    }

    g.DrawImage(bmp, dest_rect, src_rect, GraphicsUnit.Pixel);
    g.Dispose();

    pbox.Image = resized;
}

2
您可以使用PictureBox控件的SizeMode属性,并将其设置为Center。这将使您的图像中心与图片框的中心匹配。
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;

希望这能有所帮助。


1

我在VB中有例行程序...

但是你需要有两个pictureboxes...一个用于框架...一个用于图片...它可以保持图片的大小比例

假设picFrame是图像框架,picImg是图像

Sub InsertPicture(ByVal oImg As Image)
    Dim oFoto As Image
    Dim x, y As Integer

    oFoto = oImg
    picImg.Visible = False
    picImg.Width = picFrame.Width - 2
    picImg.Height = picFrame.Height - 2
    picImg.Location = New Point(1, 1)
    SetPicture(picPreview, oFoto)
    x = (picImg.Width - picFrame.Width) / 2
    y = (picImg.Height - picFrame.Height) / 2
    picImg.Location = New Point(x, y)
    picImg.Visible = True

End Sub

我相信你可以将它做成C#代码....


0

要实现类似 CSS 中 background-size: cover 的行为,您可以编写自己的派生 PictureBox 类,并覆盖 OnPaint 方法以实现自定义大小调整行为。

下面提供了我编写的自定义 PictureBox 实现,它具有“覆盖”和“适应”模式。该类具有设计器支持,因此属性可以在设计器中轻松更改,其结果将在视图中可见。请阅读下面的注释获取额外信息。

using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

// Source: https://dev59.com/0mQn5IYBdhLWcg3wcm17#67452837

namespace System.Windows.Forms.Derived
{
    public enum ExtendedPictureBoxSizeMode
    {
        Off = 0,
        Cover = 1,
        Fit = 2
    }

    public class ResponsivePictureBox : PictureBox
    {
        private ExtendedPictureBoxSizeMode extendedSizeMode = ExtendedPictureBoxSizeMode.Off;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue(ExtendedPictureBoxSizeMode.Off)]
        [Category("Behavior")]
        public ExtendedPictureBoxSizeMode ExtendedSizeMode
        {
            get => extendedSizeMode;
            set
            {
                extendedSizeMode = value;
                Invalidate();
            }
        }

        private ContentAlignment extendedImageAlign = ContentAlignment.MiddleCenter;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue(ContentAlignment.MiddleCenter)]
        [Category("Behavior")]
        public ContentAlignment ExtendedImageAlign
        {
            get => extendedImageAlign;
            set
            {
                extendedImageAlign = value;
                Invalidate();
            }
        }

        private InterpolationMode interpolationMode = InterpolationMode.Default;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue(InterpolationMode.Default)]
        [Category("Behavior")]
        public InterpolationMode InterpolationMode
        {
            get => interpolationMode;
            set
            {
                if (value == InterpolationMode.Invalid)
                    return;

                interpolationMode = value;
                Invalidate();
            }
        }

        private PixelOffsetMode pixelOffsetMode = PixelOffsetMode.Default;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [DefaultValue(PixelOffsetMode.Default)]
        [Category("Behavior")]
        public PixelOffsetMode PixelOffsetMode
        {
            get => pixelOffsetMode;
            set
            {
                if (value == PixelOffsetMode.Invalid)
                    return;

                pixelOffsetMode = value;
                Invalidate();
            }
        }

        // When changing the Padding property in the designer nothing seems to happen by default. Since our custom
        // control depends on the Padding property, we want the designer to repaint the control whenever its
        // value is changed, so we override the property and call Invalidate() in the setter to account for this.
        public new Padding Padding
        {
            get => base.Padding;
            set
            {
                base.Padding = value;
                Invalidate();
            }
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            pe.Graphics.InterpolationMode = InterpolationMode;
            pe.Graphics.PixelOffsetMode = PixelOffsetMode;

            if (ExtendedSizeMode == ExtendedPictureBoxSizeMode.Off || Image == null)
            {
                base.OnPaint(pe);
                return;
            }

            switch (ExtendedSizeMode)
            {
                case ExtendedPictureBoxSizeMode.Cover:
                    PaintCovered(pe);
                    return;

                case ExtendedPictureBoxSizeMode.Fit:
                    PaintFitted(pe);
                    return;
            }
        }

        private void PaintFitted(PaintEventArgs pe)
        {
            Rectangle rect = DeflateRect(ClientRectangle, Padding);

            if (rect.Height <= 0 || rect.Width <= 0) return;

            Image img = Image;
            int w, h;

            if (img.Width > rect.Width || img.Height > rect.Height)
            {
                if ((double)img.Width / img.Height > (double)rect.Width / rect.Height)
                {
                    w = rect.Width;
                    h = (int)((double)img.Height / img.Width * rect.Width);
                }
                else
                {
                    w = (int)((double)img.Width / img.Height * rect.Height);
                    h = rect.Height;
                }
            }
            else
            {
                w = img.Width;
                h = img.Height;
            }

            rect = GetAlignedContentRect(rect, w, h, ExtendedImageAlign);

            pe.Graphics.DrawImage(img, rect);
        }

        private void PaintCovered(PaintEventArgs pe)
        {
            Rectangle rect = DeflateRect(ClientRectangle, Padding);

            if (rect.Height <= 0 || rect.Width <= 0) return;

            Image img = Image;
            int w, h;

            if ((double)img.Width / img.Height > (double)rect.Width / rect.Height)
            {
                w = (int)((double)rect.Width / rect.Height * img.Height);
                h = img.Height;
            }
            else
            {
                w = img.Width;
                h = (int)((double)rect.Height / rect.Width * img.Width);
            }

            Rectangle imageRect = new Rectangle(0, 0, img.Width, img.Height);
            Rectangle portion = GetAlignedContentRect(imageRect, w, h, ExtendedImageAlign);

            pe.Graphics.DrawImage(img, rect, portion, GraphicsUnit.Pixel);
        }

        private static Rectangle GetAlignedContentRect(Rectangle containerRect, int contentW, int contentH, ContentAlignment imageAlign)
        {
            int containerW = containerRect.Width;
            int containerH = containerRect.Height;

            int x = (containerW - contentW) / 2;
            int y = (containerH - contentH) / 2;

            switch (imageAlign)
            {
                case ContentAlignment.TopLeft:
                    x = y = 0;
                    break;

                case ContentAlignment.TopCenter:
                    y = 0;
                    break;

                case ContentAlignment.TopRight:
                    x = containerW - contentW;
                    y = 0;
                    break;

                case ContentAlignment.MiddleRight:
                    x = containerW - contentW;
                    break;

                case ContentAlignment.BottomRight:
                    x = containerW - contentW;
                    y = containerH - contentH;
                    break;

                case ContentAlignment.BottomCenter:
                    y = containerH - contentH;
                    break;

                case ContentAlignment.BottomLeft:
                    x = 0;
                    y = containerH - contentH;
                    break;

                case ContentAlignment.MiddleLeft:
                    x = 0;
                    break;
            }

            return new Rectangle(containerRect.X + x, containerRect.Y + y, contentW, contentH);
        }

        public static Rectangle DeflateRect(Rectangle rect, Padding padding)
        {
            rect.X += padding.Left;
            rect.Y += padding.Top;
            rect.Width -= padding.Horizontal;
            rect.Height -= padding.Vertical;
            return rect;
        }
    }
}

注意事项

在开发Windows Forms应用程序时,我需要类似CSS的“覆盖”行为,因此我决定编写自己的PictureBox实现。这个ResponsivePictureBox类有一个新属性叫做ExtendedSizeMode,它可以是CoverFitOff。覆盖模式模仿了CSS覆盖模式,适合于默认PictureBox“缩放”模式,但无论何时都会尽可能显示图像的原始大小。

此外,当使用ExtendedSizeMode时,新的ExtendedImageAlign属性将把图像对齐到适当的角落。

这个类还有一个InterpolationModePixelOffsetMode属性,允许您进一步优化/自定义渲染。这基于这里展示的帖子

ExtendedSizeMode设置为Off时,PictureBox会正常工作,除了InterpolationModePixelOffsetMode也会按照默认模式工作。

默认的Padding属性对于适应和覆盖模式都有影响,允许您在PictureBox内部偏移图像。

Designer view

作为一则附注:这段代码远非完美,欢迎报告任何错误或进一步改进!

很棒的解决方案,谢谢!但是,重新设置ImageLocation属性以更改当前图像似乎不起作用。不确定原因。 - Shleemypants

0
你可以尝试更改PictureBox的SizeMode属性。
你也可以将图像设置为PictureBox的BackGroundImage,并尝试将BackGroundImageLayout更改为正确的模式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接