调整图像大小以在不拉伸的情况下填充图片框
Resize an image to fill a picture box without stretching
我想要一张图片来填充图片框,但不留任何空白。因此,当图像未调整为 pictureBox 的纵横比时,会裁掉部分图像以适合。并随着用户调整 window/pictureBox 的大小进行调整。现有的选项,Sizemode = Zoom
留下空白,因为它害怕切断任何图像并且 Sizemode = StretchImage
拉伸图像,扭曲它。
我能想到的唯一方法是创建一个算法来调整图像大小,保持对比度,将图像的宽度或长度设置为 pictureBox 的宽度或长度,并创建一些运行时循环该算法每帧一次。对于它所做的事情来说,它的性能似乎有点重,而且有点骇人听闻。还有更好的选择吗?
编辑:
对于任何路过的人,我实施 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();
}
}
根据 PictureBoxSizeMode 文档,您可以指定 PictureBoxSizeMode.Zoom 以使图像保持其纵横比。它会尽可能放大而不让图片的任何部分溢出图片框。
您可以使用 Dock 属性(设置 DockStyle.Full)让图片框调整到其容器的大小。
如果我没理解错的话,你在找"Fill"模式(类似于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)));
}
}
}
对此有一个相当简单的解决方案。 PictureBox.SizeMode
有一些设置可以帮助我们解决问题。缩放将调整图像以适合方框,普通将放置图片而不调整大小。我们要做的是检查图像的高度和宽度,如果它大于 PictureBox
大小,我们将缩放,如果不是,我们将把它放在普通。见下文:
if (image.Height > pctbx_ImageRecognition.Height || image.Width > pctbx_ImageRecognition.Width)
pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Zoom;
else
pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Normal;
我想要一张图片来填充图片框,但不留任何空白。因此,当图像未调整为 pictureBox 的纵横比时,会裁掉部分图像以适合。并随着用户调整 window/pictureBox 的大小进行调整。现有的选项,Sizemode = Zoom
留下空白,因为它害怕切断任何图像并且 Sizemode = StretchImage
拉伸图像,扭曲它。
我能想到的唯一方法是创建一个算法来调整图像大小,保持对比度,将图像的宽度或长度设置为 pictureBox 的宽度或长度,并创建一些运行时循环该算法每帧一次。对于它所做的事情来说,它的性能似乎有点重,而且有点骇人听闻。还有更好的选择吗?
编辑: 对于任何路过的人,我实施 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();
}
}
根据 PictureBoxSizeMode 文档,您可以指定 PictureBoxSizeMode.Zoom 以使图像保持其纵横比。它会尽可能放大而不让图片的任何部分溢出图片框。
您可以使用 Dock 属性(设置 DockStyle.Full)让图片框调整到其容器的大小。
如果我没理解错的话,你在找"Fill"模式(类似于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)));
}
}
}
对此有一个相当简单的解决方案。 PictureBox.SizeMode
有一些设置可以帮助我们解决问题。缩放将调整图像以适合方框,普通将放置图片而不调整大小。我们要做的是检查图像的高度和宽度,如果它大于 PictureBox
大小,我们将缩放,如果不是,我们将把它放在普通。见下文:
if (image.Height > pctbx_ImageRecognition.Height || image.Width > pctbx_ImageRecognition.Width)
pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Zoom;
else
pctbx_ImageRecognition.SizeMode = PictureBoxSizeMode.Normal;