using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Web;
public class ThumbnailHelper
{
///
/// 產生縮圖並儲存為 JPEG
///
/// 原圖路徑(虛擬或實體)
/// 輸出路徑(虛擬或實體)
/// 最大寬度
/// 最大高度
/// JPEG 品質 1-100,預設 90
/// 是否成功
public static bool Generate(string sourcePath, string destPath, int maxWidth, int maxHeight, int quality = 90)
{
try
{
// 1. 解析實體路徑
string srcPhysical = ResolvePhysicalPath(sourcePath);
string destPhysical = ResolvePhysicalPath(destPath);
if (!File.Exists(srcPhysical)) return false;
using (Image src = Image.FromFile(srcPhysical))
{
// 2. 計算等比尺寸
Size newSize = CalcProportionalSize(src.Width, src.Height, maxWidth, maxHeight);
if (newSize.Width >= src.Width && newSize.Height >= src.Height)
{
// 原圖已小於限制,直接複製
File.Copy(srcPhysical, destPhysical, true);
return true;
}
// 3. 繪製高品質縮圖
using (Bitmap bmp = new Bitmap(newSize.Width, newSize.Height))
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(src, 0, 0, newSize.Width, newSize.Height);
// 4. 以指定品質儲存 JPEG
var encoder = GetEncoder(ImageFormat.Jpeg);
var eps = new EncoderParameters(1);
eps.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);
bmp.Save(destPhysical, encoder, eps);
}
}
return true;
}
catch
{
// 實務請記錄 Log
return false;
}
}
private static Size CalcProportionalSize(int srcW, int srcH, int maxW, int maxH)
{
double ratio = Math.Min((double)maxW / srcW, (double)maxH / srcH);
return new Size((int)(srcW * ratio), (int)(srcH * ratio));
}
private static string ResolvePhysicalPath(string path)
{
if (HttpContext.Current != null && !Path.IsPathRooted(path))
return HttpContext.Current.Server.MapPath(path);
return path;
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
return ImageCodecInfo.GetImageDecoders()
.FirstOrDefault(c => c.FormatID == format.Guid);
}
}
// 在 .aspx.cs 或 .ashx 中
bool ok = ThumbnailHelper.Generate(
"~/Uploads/photo.jpg", // 來源虛擬路徑
"~/Thumbs/photo_300.jpg", // 目標虛擬路徑
300, 300, // 最大 300x300
90 // 品質 90
);
| 問題 | 原因 | 解決 |
|---|---|---|
| GIF 透明背景變黑 | 直接 DrawImage 不處理透明通道 | 建立 Bitmap 時指定 `PixelFormat.Format32bppArgb`,並 `g.Clear(Color.Transparent)` |
| 大圖 OutOfMemoryException | 一次載入完整像素陣列 | 改用 `Image.GetThumbnailImageAbort` 回呼或分塊處理;或限制最大像素數(如 4000x4000) |
| 儲存後檔案被鎖定 | `Image.FromFile` 鎖定檔案 | 改用 `using (var fs = new FileStream(...)) { Image.FromStream(fs); }` 或 `File.Copy` 到暫存檔再載入 |
`System.Drawing.Common` 在非 Windows 平台僅支援基本功能,建議改用 ImageSharp 或 Magick.NET 取得跨平台高效能影像處理。