首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 動態圖片浮水印:HttpHandler 即時合成不異檔原圖

     編輯:ASP.NET 基礎

兩種浮水印策略比較

策略時機優點缺點
上傳時合成SaveAs 後立即 GDI+ 繪製請求時直接輸出靜態檔,CPU 壓力低原圖永久改變、無法移除/更換浮水印
請求時合成 (本文方案)HttpHandler ProcessRequest原圖完整保留、浮水印可隨時調整/關閉每次請求消耗 CPU/記憶體、需快取緩解

HttpHandler 完整實作

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;

namespace BookShop.Web
{
    public class WaterMark : IHttpHandler
    {
        private const string WatermarkPath = "~/Images/watermark.png"; // 建議 PNG 透明背景
        private const string DefaultImagePath = "~/Images/default.jpg";

        public bool IsReusable => false;

        public void ProcessRequest(HttpContext context)
        {
            string physicalPath = context.Request.PhysicalPath;
            Image sourceImage;

            // 1. 取得來源圖片
            if (File.Exists(physicalPath))
            {
                sourceImage = Image.FromFile(physicalPath);
            }
            else
            {
                // 找不到檔案 → 輸出預設圖
                sourceImage = Image.FromFile(context.Server.MapPath(DefaultImagePath));
            }

            try
            {
                // 2. 載入浮水印
                using (Image watermark = Image.FromFile(context.Server.MapPath(WatermarkPath)))
                using (Graphics g = Graphics.FromImage(sourceImage))
                {
                    // 高品質繪圖設定
                    g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                    // 3. 計算位置:右下角對齊,留 10px 邊距
                    int x = sourceImage.Width - watermark.Width - 10;
                    int y = sourceImage.Height - watermark.Height - 10;
                    if (x < 0) x = 0;
                    if (y < 0) y = 0;

                    // 4. 繪製浮水印
                    g.DrawImage(watermark, x, y, watermark.Width, watermark.Height);
                }

                // 5. 輸出 JPEG (可依原圖格式動態決定)
                context.Response.Clear();
                context.Response.ContentType = "image/jpeg";
                context.Response.Cache.SetCacheability(HttpCacheability.Public);
                context.Response.Cache.SetMaxAge(TimeSpan.FromDays(30)); // 瀏覽器快取 30 天
                context.Response.Cache.SetLastModified(File.GetLastWriteTimeUtc(physicalPath));

                sourceImage.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            }
            finally
            {
                sourceImage?.Dispose(); // 確保釋放非託管資源
            }
        }
    }
}

Web.config 註冊 (IIS 7+ 整合模式)

<system.webServer>
  <handlers>
    <add name="WaterMarkHandler" 
         path="*.jpg" verb="GET" 
         type="BookShop.Web.WaterMark, BookShop.Web" 
         preCondition="integratedMode" />
    <!-- 若需支援 png/gif,複製並修改 path -->
  </handlers>
</system.webServer>

效能優化關鍵 (生產環境必做)

  1. 輸出快取:在 `ProcessRequest` 開頭檢查 `context.Request.Headers["If-Modified-Since"]`,若未修改回傳 `304 Not Modified`。
  2. 記憶體快取合成圖:使用 `MemoryCache` 以 `physicalPath + watermark.LastWriteTime` 為 Key 快取合成後的 byte[],避免重複 GDI+ 運算。
  3. 非同步處理:改實作 `IHttpAsyncHandler`,將 GDI+ 工作排入 ThreadPool,釋放 IIS 執行緒處理其他請求。
  4. CDN/反向代理:前置 Nginx/Cloudflare 快取合成圖,應用層幾乎不受請求壓力。

安全性考量

  • 驗證 `PhysicalPath` 是否在允許目錄下,防止路徑遍歷 (`../../web.config`)。
  • 限制圖片最大尺寸 (如 5000x5000),避免惡意大圖導致 OOM。
  • 浮水印圖片建議預先處理為半透明 PNG,檔案體積小、品質佳。

現代替代方案

  • ImageSharp / SkiaSharp:跨平台、無 GDI+ 依賴、支援 Linux 容器、記憶體管理更安全。
  • URL 簽名 + 雲端圖片處理服務:如 Cloudinary、Imgix、Azure CDN Image Optimization,將處理卸載至邊緣節點。

小結

HttpHandler 動態浮水印保護原圖完整性,適合「浮水印策略頻繁變更」或「需保留原圖供下載」的場景。生產部署務必加上**快取層 (MemoryCache + HTTP 304 + CDN)**,否則高併發下 GDI+ 會成為效能瓶頸。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved