縮圖生成是影像處理常見需求。.NET System.Drawing 命名空間提供兩種主要路徑:手動繪圖控制(Graphics.DrawImage)與 內建 GetThumbnailImage。前者靈活支援裁切、比例縮放、高品質插值;後者程式碼極簡但品質與參數控制有限。本文深度解析兩種策略的完整實作、優缺點比較與選型指南。
核心步驟:
Image.FromFile。Bitmap 畫布與 Graphics 物件。InterpolationMode.HighQualityBicubic、平滑模式 SmoothingMode.HighQuality。DrawImage 繪製指定區域。public static void MakeThumbnail(
string sourcePath, string destPath,
int width, int height, string mode, string format = "jpg")
{
using (Image original = Image.FromFile(sourcePath))
{
int ow = original.Width, oh = original.Height;
int targetW = width, targetH = height;
int x = 0, y = 0, srcW = ow, srcH = oh;
switch (mode.ToUpper())
{
case "W":
targetH = oh * width / ow;
break;
case "H":
targetW = ow * height / oh;
break;
case "CUT":
double targetRatio = (double)width / height;
double sourceRatio = (double)ow / oh;
if (sourceRatio > targetRatio)
{
srcH = oh;
srcW = (int)(oh * targetRatio);
x = (ow - srcW) / 2;
}
else
{
srcW = ow;
srcH = (int)(ow / targetRatio);
y = (oh - srcH) / 2;
}
break;
}
using (Bitmap bmp = new Bitmap(targetW, targetH))
using (Graphics g = Graphics.FromImage(bmp))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.Clear(Color.Transparent);
g.DrawImage(original,
new Rectangle(0, 0, targetW, targetH),
new Rectangle(x, y, srcW, srcH),
GraphicsUnit.Pixel);
ImageFormat imgFormat = format.ToLower() switch
{
"png" => ImageFormat.Png,
"gif" => ImageFormat.Gif,
"bmp" => ImageFormat.Bmp,
_ => ImageFormat.Jpeg
};
bmp.Save(destPath, imgFormat);
}
}
}
.NET Framework 內建方法,一行程式碼即可產生縮圖,但有已知限制:
Image.GetThumbnailImageAbort 回呼(通常傳回 false 即可)。
public class ThumbnailHelper
{
private readonly Image _source;
public ThumbnailHelper(string filePath) => _source = Image.FromFile(filePath);
// 1. 回傳 Image 物件(指定寬高)
public Image GetThumbnail(int w, int h)
{
return _source.GetThumbnailImage(w, h, () => false, IntPtr.Zero);
}
// 2. 直接儲存檔案(指定寬高)
public bool SaveThumbnail(int w, int h, string destPath)
{
try
{
using (var thumb = GetThumbnail(w, h))
{
thumb.Save(destPath, ImageFormat.Jpeg);
}
return true;
}
catch { return false; }
}
// 3. 依比例縮放(0.0~1.0)
public Image GetThumbnail(double scale)
{
int w = (int)(_source.Width * scale);
int h = (int)(_source.Height * scale);
return GetThumbnail(w, h);
}
// 4. 依比例縮放並儲存
public bool SaveThumbnail(double scale, string destPath)
{
try
{
using (var thumb = GetThumbnail(scale))
{
thumb.Save(destPath, ImageFormat.Jpeg);
}
return true;
}
catch { return false; }
}
public void Dispose() => _source?.Dispose();
}
| 維度 | Graphics 手動繪圖 | GetThumbnailImage |
|---|---|---|
| 圖片品質 | ⭐⭐⭐⭐⭐ (可調插值演算法) | ⭐⭐ (固定低品質) |
| 功能彈性 | 支援裁切、旋轉、水印、多格式 | 僅等比縮放 |
| 程式碼複雜度 | 中等 (~50 行) | 極低 (~5 行) |
| 效能 | 稍慢(高品質插值計算量大) | 極快(原生最佳化) |
| 適用場景 | 正式產品、使用者頭像、商品縮圖牆 | 快速原型、後台預覽、臨時縮圖 |
System.Drawing.Common 在非 Windows 平台僅支援基本功能,生產環境建議改用 ImageSharp 或 SkiaSharp:
// ImageSharp 範例
using (var img = Image.Load(sourcePath))
{
img.Mutate(x => x.Resize(new ResizeOptions
{
Mode = ResizeMode.Crop, // 對應 Cut 模式
Size = new Size(width, height)
}));
img.Save(destPath);
}
兩者皆為純 managed 程式碼,支援 Linux Docker 容器部署,且 API 更現代化。