按比例缩放System.Drawing.Bitmap至指定大小

78

我希望能够将一个 System.Drawing.Bitmap 缩放至宽高至少小于某个固定值。这是为了在网站上生成图像库的缩略图,因此我想保持纵横比不变。

我已经找到了许多解决方案,但似乎都不能完全满足我的需求;它们都是以保持宽度或高度相同来进行缩放,而不是同时改变两者。

举个例子:

如果我有一张 4272 x 2848 的图像,并想将其缩放至 1024 x 768 的大小,则结果应该是 1024 x 683 并补边(用黑色边框填充)至 1024 x 768。

对于大于所需尺寸和小于所需尺寸的图像,我该如何做到这一点,并为缩放后不符合我需要的确切尺寸的图像添加填充呢?


为什么你不能通过计算来计算另一个维度呢? - Cody Gray
@CodyGray 其他的维度是什么?这是一个需要缩小但保持其宽高比的二维图像。我尝试过只取宽高比并找出接近目标尺寸的宽度和高度的公共分母,但从未成功过。 - Michael J. Gray
3个回答

199
位图构造函数内置了调整大小的功能。
Bitmap original = (Bitmap)Image.FromFile("DSC_0002.jpg");
Bitmap resized = new Bitmap(original,new Size(original.Width/4,original.Height/4));
resized.Save("DSC_0002_thumb.jpg");

http://msdn.microsoft.com/en-us/library/0wh0045z.aspx

如果您想要控制插值模式,请查看此帖子


2
谢谢。这对我很有帮助。我知道这是一个有点老的答案,但我的新图像为什么看起来模糊?我需要设置任何插值模式吗? - theGreenCabbage
2
这不就是在新的较小位图中绘制原始位图吗?图像的一部分应该被裁剪掉。 - DerpyNerd
5
这个操作不就是把原始位图绘制在一个新的更小的位图中吗?TFM链接就在那里:从指定的现有图像初始化一个新的Bitmap类实例,按指定的大小缩放 - ta.speot.is

69

目标参数:

float width = 1024;
float height = 768;
var brush = new SolidBrush(Color.Black);

你的原始文件:

var image = new Bitmap(file);

目标尺寸(缩放因子):

float scale = Math.Min(width / image.Width, height / image.Height);

首先需要刷一下画布,然后进行调整大小:

var bmp = new Bitmap((int)width, (int)height);
var graph = Graphics.FromImage(bmp);

// uncomment for higher quality output
//graph.InterpolationMode = InterpolationMode.High;
//graph.CompositingQuality = CompositingQuality.HighQuality;
//graph.SmoothingMode = SmoothingMode.AntiAlias;

var scaleWidth = (int)(image.Width * scale);
var scaleHeight = (int)(image.Height * scale);

graph.FillRectangle(brush, new RectangleF(0, 0, width, height));
graph.DrawImage(image, ((int)width - scaleWidth)/2, ((int)height - scaleHeight)/2, scaleWidth, scaleHeight);

别忘了执行 bmp.Save(filename) 来保存生成的文件。


3
这将创建一个纯黑色的图像。 - Michael J. Gray
4
var scale更改为float scale。我猜你的代码中widthheight可能被声明为int,这会导致问题。如果按照我给出的步骤进行,它可以正常工作。 scale 的整个目的是保持宽高比。完成后,请删除-1 - yamen
11
我知道这已经过时了,但这对我很有帮助,所以谢谢你。不过,我将 graph 放在 using 块中,因为它实现了 IDisposable 接口。 - JMK
3
我看到这篇文章已经有点老了,但是我想提醒一下,Graphics 是 Disposable() 类型,所以别忘了把它放进 using 语句中。 - iedoc
3
使用 FillRectangle 方法而不是 Clear 方法,是否有特定的原因?这样做可以避免创建画刷和释放它的步骤。 - RobIII
显示剩余5条评论

4

补充一下yamen的答案,该答案适用于图片但不适用于文本。

如果您正在尝试使用此功能来缩放文本,比如说Word文档(在这种情况下是通过Word Interop以字节形式存在),您需要进行一些修改,否则您将会得到巨大的侧边栏。

可能不是完美的解决方案,但对我有效!

using (MemoryStream ms = new MemoryStream(wordBytes))
{
    float width = 3840;
    float height = 2160;
    var brush = new SolidBrush(Color.White);

    var rawImage = Image.FromStream(ms);
    float scale = Math.Min(width / rawImage.Width, height / rawImage.Height);
    var scaleWidth  = (int)(rawImage.Width  * scale);
    var scaleHeight = (int)(rawImage.Height * scale);
    var scaledBitmap = new Bitmap(scaleWidth, scaleHeight);

    Graphics graph = Graphics.FromImage(scaledBitmap);
    graph.InterpolationMode = InterpolationMode.High;
    graph.CompositingQuality = CompositingQuality.HighQuality;
    graph.SmoothingMode = SmoothingMode.AntiAlias;
    graph.FillRectangle(brush, new RectangleF(0, 0, width, height));
    graph.DrawImage(rawImage, new Rectangle(0, 0 , scaleWidth, scaleHeight));

    scaledBitmap.Save(fileName, ImageFormat.Png);
    return scaledBitmap;
}

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