Изменение размера изображения, чтобы заполнить поле изображения без растяжения

Я хотел, чтобы изображение заполняло поле изображения, но не оставляло пробелов. Таким образом, части изображения обрезаются, когда его размер не изменяется до соотношения сторон pictureBox. И настроить, как пользователь изменяет размер окна/pictureBox. Существующие варианты, Sizemode = Zoom оставляет пробелы, так как боится обрезать любую часть изображения, а Sizemode = StretchImage растягивает изображение, искажая его.

Единственный способ, которым я могу это сделать, - это создать алгоритм для изменения размера изображения, сохраняя коэффициент контрастности и устанавливая ширину или длину изображения в ширину или длину pictureBox и создавая некоторый цикл времени выполнения, который запускает алгоритм один раз кадр . Кажется, что производительность тяжелая для того, что она делает, и какая-то хакерская. Есть ли лучший вариант?

Редактировать: для всех, кто придет, я немного по-другому реализовал решение Ивана Стоева:

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();
    }
}

person Community    schedule 06.09.2015    source источник


Ответы (3)


Если я правильно понимаю, вы ищете режим «Заливка» (аналогичный фоновому изображению 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)));
        }
    }
}
person Ivan Stoev    schedule 06.09.2015

В соответствии с документацией PictureBoxSizeMode вы можете указать PictureBoxSizeMode.Zoom, чтобы изображение сохраняло соотношение сторон. Он будет увеличиваться настолько, насколько это возможно, без какой-либо части изображения, переполняющей окно изображения.

И вы можете поиграть со свойством Dock (установив DockStyle.Full), чтобы изменить размер окна изображения до размера его контейнера.

person iEoj    schedule 06.09.2015

Для этого есть довольно простое решение. 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;
person Jon Huthsing    schedule 01.08.2020