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

Я хотел, чтобы изображение заполняло поле изображения, но не оставляло пробелов. Таким образом, части изображения обрезаются, когда его размер не изменяется до соотношения сторон 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)


arrow_upward
1
arrow_downward

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

arrow_upward
1
arrow_downward

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

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

person iEoj    schedule 06.09.2015

arrow_upward
0
arrow_downward

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