Beispiel: Image Watermark Module

von Fabio Yeon

Dies ist ein Beispiel für das Schreiben eines systemeigenen (C++)-Moduls, das dynamisch ein vom Benutzer konfiguriertes Wasserzeichen in ein bereitgestelltes Bild einfügt und wie die Konfiguration und das Inetmgr-UI-Tool erweitert werden, um eine einfache Verwaltung des neuen Moduls zu ermöglichen.

Das Wasserzeichenmodul verfügt über die folgenden Funktionen:

  • Sie kann auf jeder Konfigurationsebene aktiviert/deaktiviert werden (z. B. Standort, Anwendung, virtuelles Verzeichnis usw.).
  • Es kann die Bildformate JPG, GIF und PNG mit einem Wasserzeichen versehen.
  • Das Wasserzeichenbild kann im JPG-, GIF- oder PNG-Format vorliegen. Das Wasserzeichenbild muss nicht den gleichen Typ aufweisen wie das zu wasserzeichende Bild (d. h. ein GIF-Wasserzeichenbild kann zum Wasserzeichen einer PNG-Bildanforderung verwendet werden).
  • Man kann die Position des Wasserzeichenbilds ("oben links", "oben rechts", "unten links", "unten rechts", "Mitte" sowie die Optionen von "Kachel" und "Strecken") konfigurieren. Nur die Option "Strecken" ändert bei Bedarf das Wasserzeichenbild.
  • Man kann auch den Transparenzgrad des Wasserzeichenbilds von 0 bis 100%auswählen.

Um das Beispiel zu kompilieren, müssen Sie das Platform SDK für Windows Vista oder Windows Server 2008 installieren. Die im Beispiel enthaltene Projektdatei kann in Visual Studio 2005 oder 2008 geladen werden.

Der Quellcode für diese Beispiele ist hier verfügbar.

Wasserzeichenmodul

Die erste Komponente dieses Beispiels ist das Wasserzeichenmodul selbst. Es handelt sich um ein natives C++-Modul, das überwacht, wie Anforderungen bearbeitet werden. Wenn der MIME-Typ der Anforderung angibt, dass es sich um ein Bild handelt, wird ein vom Benutzer konfigurierbares Wasserzeichen dynamisch auf das Bild angewandt und das ausgehende Bild ersetzt. Dies erfolgt alle transparent in einem Modul, das nach dem Anforderungshandler ausgeführt wird. Um es zu veranschaulichen:

Diagramm, das eine Entscheidungsstruktur von Request Handler zu Image Water marker zeigt. Wenn ein Bild aus dem Anforderungshandler vorhanden ist, wird ein neues Bild gesendet, andernfalls wird das ursprüngliche Bild gesendet.

  1. Die Logik des Codes ist ziemlich einfach:
  2. Wenn das Modul zum ersten Mal geladen wird, registriert es sich für das Ereignis post-RQ_EXECUTE_REQUEST_HANDLER, das dem System angibt, dass es unmittelbar nach dem Ausführen des Anforderungshandlers benachrichtigt werden soll.
  3. Wenn das Ereignis nach RQ_EXECUTE_REQUEST_HANDLER ausgelöst wird, ruft es nun die Konfiguration für den Pfad ab. Wenn sie nicht aktiviert ist, führt sie keine weiteren Schritte für die Anfrage und die Rettung durch.
  4. Wenn die Funktion aktiviert ist, wird der Antwortheader "Content-Type" überprüft, um festzustellen, ob es sich um einen Bildtyp handelt oder nicht. Wenn dem nicht so ist, wird es abbrechen.
  5. Wenn es sich um ein Bild handelt, wird angezeigt, ob es sich bei der Antwort um einen Puffer oder ein Dateihandle handelt. Wenn es später ist, wird das Bild in den Arbeitsspeicher geladen, das Wasserzeichen basierend auf den vom Benutzer konfigurierten Einstellungen (d. h. Bilddatei, Position, Transparenz) angewendet, das resultierende Bild in einem Speicherpuffer gespeichert, die Antwortdaten durch den Speicherpuffer ersetzt und zurückgegeben.
  6. Der Speicherpuffer wird in der "Dispose"-Methode des Moduls freigegeben.

Die Verwendung der CImage-Klassen von ATL macht das Laden und Verarbeiten des Bilds sehr einfach, insbesondere da es verschiedene Bildformate problemlos bearbeiten kann.

In diesem Beispiel gibt es nun einige Vorbehalte und sollte berücksichtigt werden, insbesondere, wenn man es in einer "echten" Produktionsumgebung verwenden möchte:

  • Der Code funktioniert nur für Bildtypen, bei denen sich die Antwort in einem Dateihandle befindet. Das HTTP_RESPONSE-Objekt kann stattdessen das Bild in einer Reihe von Puffern enthalten. Eine interessante Übung wäre das Erstellen einer IStream-Implementierung im Arbeitsspeicher, die die Puffer im Antwortobjekt umschließt (achten Sie auf die mehrfachen Pufferantworten!).
  • Das Modul versucht nicht, den Antwortheader "ETag" zu ändern oder zu aktualisieren. Dies bedeutet, dass das resultierende wasserzeichenbehaftete Bild als "reales" Bild betrachtet wird, soweit der Client betroffen ist (was er auch sollte), kann jedoch auch die Client-Cache-Logik verwirren. Eine korrekte Implementierung müsste das "ETag" ändern, um die Konfiguration des mit Wasserzeichen versehenen Bilds zu berücksichtigen. Wenn Sie beispielsweise in der aktuellen Implementierung ein Bild mit "WatermarkFileA" in der Position "UpperLeft" mit einer Transparenz von "50%" versehen und dann eine Anforderung mit einem Browser (d. h. Internet Explorer) erstellt haben, würde IE dieses Bild basierend auf den verschiedenen Antwortheadern zwischenspeichern. Wenn Sie die Konfiguration des Wasserzeichenmoduls (d. h. das Bild, die Position oder die Transparenz geändert) ändern und die Datei erneut angefordert haben (über "F5"), da das Bild von IE zwischengespeichert wurde, anstatt das Bild anzufordern, würde es einfach eine "HEAD"-Anforderung ausführen und die Informationen senden, die es über das Bild hat. Der Anforderungshandler, der nicht weiß, dass das Bild geändert wurde, antwortet, dass die zuvor gesendete Antwort noch gültig ist und die Anforderungsverarbeitung beendet wird. Leider hat das Wasserzeichenmodul in diesem Fall keine Gelegenheit, seine neue Konfiguration auszuführen und das Bild erneut zu kennzeichnen, sodass der Kunde weiterhin das alte, mit Wasserzeichen versehene Bild anzeigt. Ein ordnungsgemäßer Fix dafür wäre, dass das Wasserzeichenmodul seine Konfiguration irgendwie in das "ETag" der Antwort integriert, sodass Änderungen am Bild oder Wasserzeichenmodul eine Ungültigkeit eines zwischengespeicherten Clientbildes und eine erneute Verarbeitung des Bildes verursachen.

Konfiguration

Die Konfiguration des Wasserzeichenmoduls erfolgt über einen neuen Abschnitt im Namespace "system.webServer". Die Schemadatei lautet wie folgt:

<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>

Die Datei "watermark.xml" sollte im %windir%\system32\inetsrv\config\schema Verzeichnis abgelegt werden, damit sie wirksam wird, und fügen Sie die Abschnittsdefinition in der Datei "applicationhost.config" unter dem Namespace "system.webServer" hinzu:

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

Um das Modul zu verwenden, muss das Modul dann in der globalen Modulliste "system.webServer\globalModules" installiert werden:

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

Und zur Modulliste für die Anwendung "system.webServer\modules":

<add name="WatermarkModule" />

Inetmgr

Zusammen mit dem Modulbeispiel gibt es eine Reihe von verwalteten Klassen, die Management-Plug-Ins für das neue Verwaltungswerkzeug der Benutzeroberfläche "Inetmgr" sind. Es gibt verschiedene weitere Dokumentationen zum Schreiben und Erweitern des neuen "Inetmgr", die hier verfügbar sind. Kurz gesagt, um sie zu verwenden, muss man die DLL-Dateien dem GAC (Global Assembly Cache) hinzufügen und die folgende Konfiguration der %windir%\system32\inetsrv\config\administration.config Datei hinzufügen:

Fügen Sie in der <moduleProviders-Auflistung> den folgenden Eintrag hinzu:

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

Fügen Sie der Sammlung die folgende Zeile hinzu: <modules>

<add name="Watermark" />

Starten Sie das Tool neu, und ein neues Symbol sollte auf Ihrer Website verfügbar sein.