Web 專案頻繁需求:**上傳原圖 → 伺服器生成多種尺寸縮略圖 (列表圖、詳情圖、輪播圖) → 前端按需載入**。關鍵指標:**不變形、清晰度高、記憶體可控、支援多種裁剪模式**。
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public static class ThumbnailHelper
{
///
/// 生成高質量縮略圖
///
/// 原圖物理路徑
/// 輸出縮略圖物理路徑
/// 目標寬度
目標高度
模式: HW(強制縮放), W(寬固定高自適應), H(高固定寬自適應), Cut(裁剪填滿不變形)
/// JPEG 品質 1-100 (預設 90)
/// 輸出格式 (預設 Jpeg)
public static void MakeThumbnail(
string originalPath,
string thumbnailPath,
int width,
int height,
string mode = "Cut",
long quality = 90,
ImageFormat format = null)
{
if (!File.Exists(originalPath)) throw new FileNotFoundException("原圖不存在", originalPath);
if (width <= 0 || height <= 0) throw new ArgumentOutOfRangeException("寬高必須 > 0");
format ??= ImageFormat.Jpeg;
using (Image original = Image.FromFile(originalPath))
{
int ow = original.Width;
int oh = original.Height;
int targetW = width;
int targetH = height;
int srcX = 0, srcY = 0, srcW = ow, srcH = oh;
// 計算來源裁剪區域與目標尺寸
switch (mode.ToUpperInvariant())
{
case "HW": // 強制縮放 (可能變形)
break; // 全圖來源、全尺寸目標
case "W": // 寬固定,高等比
targetH = (int)Math.Round(oh * width / (double)ow);
break;
case "H": // 高固定,寬等比
targetW = (int)Math.Round(ow * height / (double)oh);
break;
case "CUT": // 裁剪填滿 (不變形,居中裁剪)
double targetRatio = (double)width / height;
double sourceRatio = (double)ow / oh;
if (sourceRatio > targetRatio) // 原圖較寬 → 裁剪左右
{
srcH = oh;
srcW = (int)Math.Round(oh * targetRatio);
srcX = (ow - srcW) / 2;
}
else // 原圖較高 → 裁剪上下
{
srcW = ow;
srcH = (int)Math.Round(ow / targetRatio);
srcY = (oh - srcH) / 2;
}
break;
default:
throw new ArgumentException($"不支援的模式: {mode}");
}
// 建立目標位圖
using (var bitmap = new Bitmap(targetW, targetH, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(bitmap))
{
// 高質量繪圖設定
g.InterpolationMode = InterpolationMode.HighQualityBicubic; // 雙三次插值 (縮放最佳)
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
// 背景透明 (PNG/WebP 需要);JPEG 會填黑,可先填白
if (format == ImageFormat.Png || format.Guid == ImageFormat.Webp.Guid)
g.Clear(Color.Transparent);
else
g.Clear(Color.White);
// 繪製:來源矩形 → 目標矩形
g.DrawImage(original,
new Rectangle(0, 0, targetW, targetH),
new Rectangle(srcX, srcY, srcW, srcH),
GraphicsUnit.Pixel);
// 保存:JPEG 品質控制
if (format == ImageFormat.Jpeg)
{
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
var jpegCodec = GetEncoderInfo("image/jpeg");
bitmap.Save(thumbnailPath, jpegCodec, encoderParams);
}
else
{
bitmap.Save(thumbnailPath, format);
}
}
}
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
return ImageCodecInfo.GetImageEncoders().FirstOrDefault(c => c.MimeType == mimeType);
}
}
| 模式 | 參數意義 | 輸出尺寸 | 變形 | 適用場景 |
|---|---|---|---|---|
| HW | 寬、高皆強制 | 完全符合指定 W×H | ✅ 可能變形 | 固定版面佔位、不介意比例 |
| W | 指定寬,高自動等比 | 寬=指定,高=計算 | ❌ 保持比例 | 列表圖、卡片寬度固定 |
| H | 指定高,寬自動等比 | 高=指定,寬=計算 | ❌ 保持比例 | 時間軸、固定高度區塊 |
| Cut | 指定寬高,**裁剪填滿** | 完全符合指定 W×H | ❌ **不變形** (居中裁剪) | **頭像、輪播圖、封面圖** 首選 |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| System.Drawing (GDI+) | 內建、API 熟悉、Windows 相容 | **非執行緒安全**、大量併發易崩潰、Linux/macOS 需 libgdiplus、效能一般 | 低併發、傳統 .NET Framework、Windows 專用 |
| ImageSharp (SixLabors) | **全託管、執行緒安全、跨平台、效能優、API 現代**、支援 WebP/AVIF | 需 NuGet 套件、API 與 GDI+ 不同 | **現代 .NET Core/5+ 專案首選** |
| SkiaSharp | Google Skia 引擎、極高效能、跨平台、功能豐富 (濾鏡、向量、文字) | 較大原生庫、學習曲線陡 | 高效能、複雜圖形處理、跨平台 |
| Magick.NET (ImageMagick) | 格式支援最全 (HEIC/RAW/PSD...)、命令列級功能 | 原生依賴重、部署複雜 | 專業圖像處理管線 |
// NuGet: SixLabors.ImageSharp, SixLabors.ImageSharp.Processing
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;
public static void MakeThumbnailSharp(string input, string output, int w, int h, string mode = "cut", int quality = 90)
{
using var img = Image.Load(input);
var options = new ResizeOptions
{
Mode = mode.ToLower() switch
{
"hw" => ResizeMode.Stretch,
"w" => ResizeMode.Max, // 寬固定
"h" => ResizeMode.Max, // 高固定 (需調整邏輯)
"cut" => ResizeMode.Crop,
_ => ResizeMode.Crop
},
Sampler = KnownResamplers.Lanczos3 // 高質量重採樣
};
if (mode.ToLower() == "w") options.Size = new Size(w, 0);
else if (mode.ToLower() == "h") options.Size = new Size(0, h);
else options.Size = new Size(w, h);
img.Mutate(x => x.Resize(options));
img.Save(output, new JpegEncoder { Quality = quality });
}
高質量縮略圖生成核心在於:**模式選擇 (Cut 為王)、插值算法 (Bicubic/Lanczos)、JPEG 品質 (85-90)、嚴格資源釋放**。**舊專案維護用 GDI+ 封裝函數即可;新專務必遷移至 ImageSharp**,獲得執行緒安全、跨平台、現代 API、更好效能與格式支援。配合**非同步背景生成 + CDN 快取**,構建高效能、可擴展的圖片處理管線。