Web 開發中圖片處理無處不在:登入驗證碼防機器人、用戶上傳頭像自動加浮水印、商品圖生成縮圖提升載入速度。本文將這三大高頻需求整理為完整可執行的 ASP.NET 實作方案,涵蓋 System.Drawing 核心 API 應用。
<asp:Image> 控件,ImageUrl 指向驗證碼產生頁面ValidateCode.aspx,Page_Load 直接輸出 JPEG 圖片流Session,登入時比對用戶輸入<div class="login-form">
<table>
<tr><td>帳號:</td><td><asp:TextBox ID="txtAccount" runat="server" /></td></tr>
<tr><td>密碼:</td><td><asp:TextBox ID="txtPassword" runat="server" TextMode="Password" /></td></tr>
<tr><td>驗證碼:</td><td>
<asp:Image ID="imgCaptcha" runat="server" ImageUrl="ValidateCode.aspx" style="cursor:pointer;" onclick="this.src='ValidateCode.aspx?'+Math.random()" />
<span>點擊圖片更換</span>
</td></tr>
<tr><td>輸入:</td><td><asp:TextBox ID="txtCaptcha" runat="server" /></td></tr>
<tr><td><asp:Button ID="btnLogin" runat="server" Text="登入" OnClick="btnLogin_Click" /></td></tr>
</table>
</div>
protected void Page_Load(object sender, EventArgs e)
{
// 1. 產生 4 位隨機數字
string code = new Random().Next(1000, 9999).ToString();
Session["ValidateCode"] = code; // 存入 Session 供後續驗證
// 2. 建立畫布
Bitmap bitmap = new Bitmap(100, 40);
Graphics g = Graphics.FromImage(bitmap);
// 3. 繪製干擾線
g.DrawLine(new Pen(Brushes.Blue), 0, 10, 100, 10);
g.DrawLine(new Pen(Brushes.GreenYellow), 0, 25, 100, 25);
// 4. 繪製驗證碼文字
g.DrawString(code, new Font("Consolas", 24, FontStyle.Bold), Brushes.DarkGreen, new PointF(5, 2));
// 5. 輸出圖片流
Response.ContentType = "image/jpeg";
bitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
Response.End();
}
protected void btnLogin_Click(object sender, EventArgs e)
{
string userInput = txtCaptcha.Text.Trim();
string sessionCode = Session["ValidateCode"]?.ToString();
if (string.IsNullOrEmpty(sessionCode))
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('驗證碼已失效,請重新整理');", true);
else if (userInput.Equals(sessionCode, StringComparison.OrdinalIgnoreCase))
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('驗證通過!');", true);
else
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('驗證碼錯誤');", true);
}

FileUpload 選擇圖片Graphics 物件在圖片上繪製文字_Watermarked),刪除原圖,回傳新圖路徑供預覽<table style="background:lightblue">
<tr>
<td>選擇圖片:</td>
<td><asp:FileUpload ID="fuImage" runat="server" /></td>
<td><asp:Button ID="btnUpload" runat="server" Text="上傳並加浮水印" OnClick="btnUpload_Click" /></td>
</tr>
<tr><td colspan="3"><asp:Image ID="imgPreview" runat="server" /></td></tr>
</table>
protected void btnUpload_Click(object sender, EventArgs e)
{
if (!fuImage.HasFile)
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('請先選擇檔案');", true);
return;
}
// 1. 取得副檔名、產生新檔名
string ext = Path.GetExtension(fuImage.FileName).ToLower();
string fileName = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string saveDir = Server.MapPath("~/Uploads/");
if (!Directory.Exists(saveDir)) Directory.CreateDirectory(saveDir);
string originalPath = Path.Combine(saveDir, fileName + ext);
string watermarkedPath = Path.Combine(saveDir, fileName + "_Watermarked" + ext);
// 2. 儲存原圖
fuImage.SaveAs(originalPath);
// 3. 繪製浮水印
using (Bitmap bmp = new Bitmap(originalPath))
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawString("© MyWebsite 2024", new Font("微軟正黑體", 20, FontStyle.Bold),
new SolidBrush(Color.FromArgb(128, 255, 255, 255)), // 半透明白色
new PointF(20, 20));
bmp.Save(watermarkedPath, ImageFormat.Jpeg);
}
// 4. 清理原圖、顯示結果
File.Delete(originalPath);
imgPreview.ImageUrl = "~/Uploads/" + fileName + "_Watermarked" + ext;
}

用戶上傳的圖片尺寸不一,需產生固定尺寸縮圖(如 160x120),並支援:
public static class ImageHelper
{
///
/// 產生縮圖
///
/// 原圖完整路徑
/// 縮圖儲存路徑
/// 目標寬度
/// 目標高度
/// 模式:HW(拉伸)、W(指定寬)、H(指定高)、CUT(裁切填滿)
public static void CreateThumbnail(string sourcePath, string destPath, int width, int height, string mode)
{
using (Image srcImg = Image.FromFile(sourcePath))
{
int srcW = srcImg.Width, srcH = srcImg.Height;
int destX = 0, destY = 0, cropW = srcW, cropH = srcH;
// 計算裁切區域
switch (mode.ToUpper())
{
case "W": // 指定寬,高等比
height = srcH * width / srcW;
break;
case "H": // 指定高,寬等比
width = srcW * height / srcH;
break;
case "CUT": // 裁切填滿
double srcRatio = (double)srcW / srcH;
double destRatio = (double)width / height;
if (srcRatio > destRatio) // 原圖較寬,裁切左右
{
cropH = srcH;
cropW = (int)(srcH * destRatio);
destX = (srcW - cropW) / 2;
}
else // 原圖較高,裁切上下
{
cropW = srcW;
cropH = (int)(srcW / destRatio);
destY = (srcH - cropH) / 2;
}
break;
}
// 建立目標 Bitmap 並繪製
using (Bitmap bmp = new Bitmap(width, height))
using (Graphics g = Graphics.FromImage(bmp))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.Clear(Color.Transparent);
g.DrawImage(srcImg, new Rectangle(0, 0, width, height),
new Rectangle(destX, destY, cropW, cropH), GraphicsUnit.Pixel);
bmp.Save(destPath, ImageFormat.Jpeg);
}
}
}
}
protected void btnUpload_Click(object sender, EventArgs e)
{
// ... 前面上傳邏輯同場景二 ...
// 產生縮圖
string thumbPath = Path.Combine(saveDir, fileName + "_Thumb" + ext);
ImageHelper.CreateThumbnail(originalPath, thumbPath, 160, 120, "CUT");
// 顯示縮圖
imgThumb.ImageUrl = "~/Uploads/" + fileName + "_Thumb" + ext;
}

| 場景 | 關鍵技術點 | 效能建議 |
|---|---|---|
| 驗證碼 | Session 儲存、Graphics 繪圖、Response.OutputStream 輸出 | 考慮改用 ASP.NET Core 的 Microsoft.AspNetCore.Antiforgery 或第三方庫 |
| 浮水印 | Font/Brush 設定、半透明色、座標計算 | 大量圖片處理建議佇列化(Hangfire/BackgroundService) |
| 縮圖 | InterpolationMode、裁切邏輯、記憶體釋放 | 使用 ImageSharp 或 SkiaSharp 取代 System.Drawing(跨平台、效能更好) |
掌握 System.Drawing 命名空間下的 Bitmap、Graphics、Image 核心類別,即可應對絕大多數 Web 圖片處理需求。實務上建議將上述功能封裝為獨立服務類,搭配依賴注入使用,並注意 IDisposable 正確釋放非受控資源,避免記憶體洩漏。