【问题标题】:Resize an image to fill a picture box without stretching调整图像大小以填充图片框而不拉伸
【发布时间】:2015-09-06 10:58:56
【问题描述】:

我想要一张图片来填充图片框,但不留下任何空白。因此,当图像的大小未调整为图片框的纵横比时,会切断图像的某些部分以适应它。并在用户调整窗口/图片框大小时进行调整。现有选项Sizemode = Zoom 会留下空白,因为它害怕切断任何图像,Sizemode = StretchImage 会拉伸图像,使其变形。

我能想到的唯一方法是创建一个算法来调整图像大小,保持对比度,并将图像的宽度或长度设置为图片框的宽度或长度,并创建一些运行该算法的运行时循环一帧一次。对于它所做的事情来说,这似乎是一种沉重的表现,而且有点骇人听闻。有更好的选择吗?

编辑: 对于任何路过的人,我实施 Ivan Stoev 的解决方案略有不同:

class ImageHandling
{
    public static Rectangle GetScaledRectangle(Image img, Rectangle thumbRect)
    {
        Size sourceSize = img.Size;
        Size targetSize = thumbRect.Size;
        float scale = Math.Max((float) targetSize.Width / sourceSize.Width, (float) targetSize.Height / sourceSize.Height);
        var rect = new RectangleF();
        rect.Width = scale * sourceSize.Width;
        rect.Height = scale * sourceSize.Height;
        rect.X = (targetSize.Width - rect.Width) / 2;
        rect.Y = (targetSize.Height - rect.Height) / 2;
        return Rectangle.Round(rect);
    }

    public static Image GetResizedImage(Image img, Rectangle rect)
    {
        Bitmap b = new Bitmap(rect.Width, rect.Height);
        Graphics g = Graphics.FromImage((Image) b);
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.DrawImage(img, 0, 0, rect.Width, rect.Height);
        g.Dispose();
        try
        {
            return (Image)b.Clone();
        }
        finally
        {
            b.Dispose();
            b = null;
            g = null;
        }
    }

    public Form1()
    {
        InitializeComponent();
        updateMainBackground();
    }

    void updateMainBackground()
    {
        Image img = Properties.Resources.BackgroundMain;
        Rectangle newRect = ImageHandling.GetScaledRectangle(img, mainBackground.ClientRectangle);
        mainBackground.Image = ImageHandling.GetResizedImage(img, newRect);
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
        updateMainBackground();
    }
}

【问题讨论】:

    标签: c# picturebox


    【解决方案1】:

    如果我理解正确,您正在寻找“填充”模式(类似于 Windows 背景图片)。没有标准的方法,但借助小型计算和 GDI+ 制作自己的方法并不难:

    using System;
    using System.Drawing;
    using System.IO;
    using System.Net;
    using System.Windows.Forms;
    
    namespace Samples
    {
        public class ImageFillBox : Control
        {
            public ImageFillBox()
            {
                SetStyle(ControlStyles.Selectable | ControlStyles.SupportsTransparentBackColor, false);
                SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.Opaque | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true);
            }
            private Image image;
            public Image Image
            {
                get { return image; }
                set
                {
                    if (image == value) return;
                    image = value;
                    Invalidate();
                }
            }
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                if (image == null)
                    e.Graphics.Clear(BackColor);
                else
                {
                    Size sourceSize = image.Size, targetSize = ClientSize;
                    float scale = Math.Max((float)targetSize.Width / sourceSize.Width, (float)targetSize.Height / sourceSize.Height);
                    var rect = new RectangleF();
                    rect.Width = scale * sourceSize.Width;
                    rect.Height = scale * sourceSize.Height;
                    rect.X = (targetSize.Width - rect.Width) / 2;
                    rect.Y = (targetSize.Height - rect.Height) / 2;
                    e.Graphics.DrawImage(image, rect);
                }
            }
        }
        static class Test
        {
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                var testForm = new Form();
                testForm.Controls.Add(new ImageFillBox
                {
                    Dock = DockStyle.Fill,
                    Image = GetImage(@"http://www.celebrityrockstarguitars.com/rock/images/Metall_1.jpg")
                });
                Application.Run(testForm);
            }
            static Image GetImage(string path)
            {
                var uri = new Uri(path);
                if (uri.IsFile) return Image.FromFile(path);
                using (var client = new WebClient())
                    return Image.FromStream(new MemoryStream(client.DownloadData(uri)));
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      根据 PictureBoxSizeMode 文档,您可以指定 PictureBoxSizeMode.Zoom 以使图像保持其纵横比。它会尽可能放大,而图像的任何部分都不会溢出图片框。

      您可以使用 Dock 属性(设置 DockStyle.Full)来让图片框调整到其容器的大小。

      【讨论】:

        【解决方案3】:

        对此有一个相当简单的解决方案。 PictureBox.SizeMode 有一些设置可以帮助我们。 Zoom 将调整图像以适合框,Normal 将放置图片而不调整大小。我们要做的是检查图像的高度和宽度,如果它大于PictureBox 大小,我们将进行缩放,如果不是,我们将其放入 Normal。见下文:

        if (image.Height > pctbx_ImageRecognition.Height || image.Width > pctbx_ImageRecognition.Width)
            pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Zoom;
        else
            pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Normal;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-16
          • 2010-09-19
          • 1970-01-01
          • 1970-01-01
          • 2012-07-30
          • 2016-09-11
          • 2013-05-20
          • 1970-01-01
          相关资源
          最近更新 更多