在上傳頭像、商品圖、內容插圖等場景,需將任意尺寸原圖縮放至指定最大寬高範圍內,且保持長寬比不變形。本文提供一個纯静态方法 NewSize,輸入原圖寬高與目標最大寬高,輸出計算後的最佳 Size,代碼極簡、無依賴、單元測試友好。
using System.Drawing;
public static class ImageHelper {
///
/// 計算等比縮放後的尺寸
///
/// 目標最大寬度
/// 目標最大高度
/// 原圖寬度
/// 原圖高度
/// 縮放後的 Size (寬, 高)
public static Size NewSize(int maxWidth, int maxHeight, int width, int height) {
double w = 0, h = 0;
double sw = width, sh = height, mw = maxWidth, mh = maxHeight;
if (sw < mw && sh < mh) {
// 原圖已在目標框內,不放大
w = sw; h = sh;
}
else if ((sw / sh) > (mw / mh)) {
// 原圖較寬,以寬度為基準縮放
w = mw;
h = (w * sh) / sw;
}
else {
// 原圖較高,以高度為基準縮放
h = mh;
w = (h * sw) / sh;
}
return new Size((int)Math.Round(w), (int)Math.Round(h));
}
}
目標框: 300x300
原圖 600x400 (寬高比 1.5) > 目標框比 1.0 → 以寬為基準 → 300x200
原圖 400x600 (寬高比 0.67) < 目標框比 1.0 → 以高為基準 → 200x300
原圖 200x150 (均小於目標) → 不縮放 → 200x150
public static void SaveThumbnail(string srcPath, string destPath, int maxW, int maxH, long quality = 85) {
using (var img = Image.FromFile(srcPath)) {
Size newSize = NewSize(maxW, maxH, img.Width, img.Height);
using (var bmp = new Bitmap(newSize.Width, newSize.Height))
using (var g = Graphics.FromImage(bmp)) {
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(img, new Rectangle(0, 0, newSize.Width, newSize.Height),
0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
// JPEG 編碼器質量設置
var encoder = ImageCodecInfo.GetImageEncoders()
.First(c => c.FormatDescription == "JPEG");
var ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(Encoder.Quality, quality);
bmp.Save(destPath, encoder, ep);
}
}
}
[Theory]
[InlineData(300, 300, 600, 400, 300, 200)]
[InlineData(300, 300, 400, 600, 200, 300)]
[InlineData(300, 300, 200, 150, 200, 150)]
[InlineData(100, 200, 400, 300, 100, 75)]
public void NewSize_ShouldKeepAspectRatio(int maxW, int maxH, int w, int h, int expW, int expH) {
var size = ImageHelper.NewSize(maxW, maxH, w, h);
Assert.Equal(expW, size.Width);
Assert.Equal(expH, size.Height);
}
可在 NewSize 基礎上擴展參數 mode (Enum: Fit / Fill / Pad) 實現上述變體,核心數學邏輯不變。
將此方法放入 ImageHelper,所有圖片處理入口統一調用,確保縮略圖生成邏輯一致、可測試、可維護。