共用方式為


範例:影像浮水印模組

作者 :法比奧·延

這是如何撰寫原生(C++)模組的範例,該模組能動態地將使用者自訂的浮水印插入所提供的圖片中,以及如何擴展設定與 inetmgr UI 工具,以便輕鬆管理新模組。

浮水印模組具備以下功能:

  • 它可以在任何設定層級(例如網站、應用程式、虛擬目錄等)啟用或停用。
  • 它可以為 JPG、GIF 和 PNG 格式加上浮水印。
  • 浮水印圖片可以是 JPG、GIF 或 PNG 格式。 浮水印圖片不必與浮水印圖片類型相同(例如,GIF 浮水印圖片可以用來加水印PNG圖片的請求)。
  • 你可以設定浮水印圖片的位置(「左上」、「右上」、「左下」、「右下」、「中間」,以及「平貼」和「拉伸」選項)。 只有「拉伸」選項能在需要時更改或修改浮水印圖片。
  • 也可以選擇浮水印影像的透明度等級,從 0 到 100%。

若要編譯範例,您必須安裝 Windows Vista 平台 SDK 或 Windows Server 2008。 範例中包含的專案檔案可在 Visual Studio 2005 或 2008 中載入。

這些樣本的原始碼 可在此取得

浮水印模組

此樣本的第一個組件是浮水印模組本身。 它是一個原生的 C++ 模組,會監控請求的送達,如果請求的 MIME 類型顯示是映像檔,它會動態地為映像加上使用者設定的浮水印,並替換出檔映像檔。 這一切都透明地在一個模組中執行,該模組在請求處理器之後執行。 舉例來說:

這張圖顯示了從請求處理程式到影像水標記的決策樹。如果有來自請求處理程序的影像,會傳送新的影像,否則會傳送原始影像。

  1. 程式碼的邏輯相當直接明瞭:
  2. 模組首次載入時會註冊後RQ_EXECUTE_REQUEST_HANDLER事件,該事件指示系統希望在請求處理程序執行後立即收到通知。
  3. 現在,當 post-RQ_EXECUTE_REQUEST_HANDLER 事件觸發時,它將獲取其路徑的設定。 如果沒有啟用,它不會對請求做任何進一步的處理,然後就會放棄。
  4. 如果啟用了,它會檢查「Content-Type」回應標頭,看看是否是圖片類型。 如果不是,它就會放棄。
  5. 如果是圖片,它會判斷回應是缓存還是檔案柄。 如果是後者,它會將影像載入記憶體,根據使用者設定的設定(例如影像檔案、位置、透明度)套用浮水印,將產生的影像儲存到記憶體內緩衝區,然後將回應資料替換成記憶體緩衝區,然後返回。
  6. 記憶體內緩衝區將在模組的「Dispose」方法中釋放。

使用 ATL 的 CImage 類別使得載入與處理影像變得非常簡單,尤其因為它能輕鬆操作各種影像格式。

不過,這個範例中有幾個注意事項,特別是如果想在「真實」生產環境中使用,應該加以注意:

  • 這段程式碼僅適用於使用檔案控制代碼接收回應的圖片類型。 HTTP_RESPONSE物件可能會將影像包含在一系列緩衝區中。 一個有趣的練習是建立一個記憶體內的 IStream 實作,將緩衝區包裹在回應物件中(注意多個緩衝區回應!)。
  • 模組不會嘗試修改或更新「ETag」回應標頭。 這表示產生的浮水印影像在用戶端眼中會被視為「真實」影像(理應如此),但也可能混淆用戶端快取邏輯。 正確的實作必須修改「ETag」以考量浮水印影像的配置。 例如,在目前的實作中,如果你在「左上方」位置用「WatermarkFileA」浮水印,透明度為「50%」,然後用瀏覽器(例如 Internet Explorer)提出請求,IE 會根據各種回應標頭快取該圖片。 如果你更改浮水印模組的設定(例如更改圖片、位置或透明度),並再次請求(透過「F5」),因為圖片已被 IE 快取,它不會直接請求圖片,而是直接發送「HEAD」請求,傳送它擁有的圖片資訊。 請求處理器不知道映像已變更,會回應先前的回應仍然有效,並結束請求處理。 不幸的是,在這種情況下,浮水印模組無法在新設定下執行並重新加浮水印,所以客戶端會樂意繼續顯示舊的浮水印圖片。 正確的解決方法是讓浮水印模組在回應的「ETag」中整合其設定,這樣任何對圖片或浮水印模組的變更都會使任何客戶快取影像失效並重新處理。

Configuration

浮水印模組的設定是透過「system.webServer」命名空間中的一個新區塊完成。 結構檔案如下:

<configSchema> 
 <sectionSchema name="system.webServer/watermark"> 
  <attribute name="enabled" type="bool" defaultValue="false" /> 
  <attribute name="watermarkImage" type="string" /> 
  <attribute name="transparency" type="uint" defaultValue="50" validationType="integerRange" validationParameter="0,100" /> 
  <attribute name="position" type="enum" defaultValue="LowerRight" > 
    <enum name="UpperLeft" value="0" /> 
    <enum name="UpperRight" value="1" /> 
    <enum name="LowerLeft" value="2" /> 
    <enum name="LowerRight" value="3" /> 
    <enum name="Center" value="4" /> 
    <enum name="Stretch" value="5" /> 
    <enum name="Tile" value="6" /> 
  </attribute> 
 </sectionSchema> 
</configSchema>

「watermark.xml」檔案應放置在 %windir%\system32\inetsrv\config\schema 目錄中以使其生效,並在「system.webServer」命名空間的「applicationhost.config」檔案中新增區段定義。

<section name="Watermark" overrideModeDefault="Allow" />

要使用該模組,必須將該模組安裝在全域模組清單中,「system.webServer\globalModules」中:

<add name="WatermarkModule" image="c:\Watermark\Watermark.dll" />

並且為應用程式中的模組清單「system.webServer\modules」添加:

<add name="WatermarkModule" />

Inetmgr

除了模組範例外,還有一組管理型類別,這些類別是新推出的「Inetmgr」UI 管理工具的管理外掛。 關於如何撰寫及擴展新「Inetmgr」的其他文件,可在此取得。 簡言之,使用它們需要建立、將 dll 加入 GAC(全域組裝快取),並在檔案中加入以下設定 %windir%\system32\inetsrv\config\administration.config

在 <moduleProviders> 集合中,新增以下條目:

<add name="Watermark" type="WatermarkServer.WatermarkModuleProvider, Watermarkserver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5f6f8f3f74d67fe4" />

並且在 <modules> 集合中加入以下這行:

<add name="Watermark" />

重新啟動工具後,你的網站應該會出現新的圖示。