架構
genimage.ashx:註冊 Class="Namespace.ImageGenerator"。
ImageGenerator.cs:實作 IHttpHandler,依查詢字串輸出原圖或縮圖。
- 前端
<asp:Image ImageUrl='genimage.ashx?id=123' /> 或 <img src='genimage.ashx?id=123&thumbnail=1' />。
處理常式完整實作
public class ImageGenerator : IHttpHandler
{
public bool IsReusable => true;
public void ProcessRequest(HttpContext context)
{
int picId = Convert.ToInt32(context.Request["id"]);
string imgPath = PhotoData.GetPath(picId, out int views); // 自訂資料存取
context.Response.ContentType = "image/jpeg";
if (context.Request["thumbnail"] != null) // 輸出縮圖
{
using (var bmp = new Bitmap(imgPath))
{
float scale = 150f / Math.Max(bmp.Width, bmp.Height);
using (var thumb = bmp.GetThumbnailImage(
(int)(bmp.Width * scale), (int)(bmp.Height * scale), null, IntPtr.Zero))
{
thumb.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
}
else // 輸出原圖串流
{
context.Response.TransmitFile(imgPath); // 高效傳送檔案,不載入記憶體
PhotoData.IncrementViews(picId); // 更新瀏覽次數
}
}
}
關鍵技術點
- TransmitFile:直接由核心模式傳送檔案,避免大圖載入記憶體導致 OOM,效能遠優於
FileStream + BinaryWrite 迴圈。
- GetThumbnailImage:快速產生縮圖,但品質一般;高品質需求請用
Graphics.DrawImage + InterpolationMode.HighQualityBicubic。
- 快取控制:
context.Response.Cache.SetCacheability(HttpCacheability.Public); context.Response.Cache.SetMaxAge(TimeSpan.FromDays(30)); 讓瀏覽器/CDN 快取靜態圖片。
- 安全性:驗證
picId 權限,防止遍歷枚舉;路徑不可直接暴露實體磁碟結構。
前端使用範例
<!-- 列表頁顯示縮圖 -->
<asp:Repeater ID="rptPhotos" runat="server">
<ItemTemplate>
<img src='genimage.ashx?id=<%# Eval("Id") %>&thumbnail=1' alt='<%# Eval("Title") %>' />
</ItemTemplate>
</asp:Repeater>
<!-- 詳細頁顯示原圖 -->
<asp:Image ID="imgDetail" runat="server" />
<script>
imgDetail.ImageUrl = "genimage.ashx?id=" + Request.QueryString["id"];
</script>
擴充:動態水印、壓縮品質、格式轉換
// 加浮水印
using (var g = Graphics.FromImage(bmp))
{
var font = new Font("微軟正黑體", 12);
g.DrawString("© MySite", font, Brushes.White, bmp.Width - 100, bmp.Height - 20);
}
// 指定 JPEG 品質
var encoder = ImageCodecInfo.GetImageEncoders().First(c => c.MimeType == "image/jpeg");
var ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(Encoder.Quality, 85L);
bmp.Save(stream, encoder, ep);