通过


示例:图像水印模块

作者 :Fabio Yeon

此示例演示如何编写本机(C++)模块,该模块将动态地将用户配置的水印插入到正在处理的映像中,以及如何扩展配置和 inetmgr UI 工具,以便轻松管理新模块。

水印模块具有以下功能:

  • 可以在任何配置级别(例如站点、应用程序、虚拟目录等)启用/禁用它。
  • 它可以水印 JPG、GIF 和 PNG 图像格式。
  • 水印图像可以是 JPG、GIF 或 PNG 格式。 水印图像不必与要水印的图像类型相同(即 GIF 水印图像可用于对 PNG 图像请求进行水印)。
  • 可以配置水印图像的位置(“左上”、“右上”、“左下”、“右下”、“居中”,以及“磁贴”和“拉伸”的选项)。 如果需要,只有“stretch”选项才会更改/修改水印图像。
  • 还可以选择水印图像的透明度级别,从 0 到 100%。

若要编译示例,必须安装适用于 Windows Vista 或 Windows Server 2008 的平台 SDK。 示例中包含的项目文件可以在 Visual Studio 2005 或 2008 中加载。

此处提供了这些示例的源代码。

水印模块

此示例的第一个组件是水印模块本身。 它是一个本机 C++ 模块,在请求被处理时进行监视,如果请求的 MIME 类型指示它是图像,它将动态地将用户配置的水印应用于图像,并替换传出的图像。 这一切都在请求处理程序之后运行的模块中以透明方式完成。 为了说明这一点:

展示从请求处理程序到图像水印器的决策树关系的图表。如果请求处理程序中有图像,则会发送新图像,否则将发送原始图像。

  1. 代码的逻辑非常简单:
  2. 首次加载模块时,它会为 RQ_EXECUTE_REQUEST_HANDLER 事件之后的通知注册,这意味着该模块在请求处理程序运行后希望立即收到系统的通知。
  3. 现在,当触发后RQ_EXECUTE_REQUEST_HANDLER事件时,它将检索其路径的配置。 如果未启用,它将不对请求和保释执行任何进一步操作。
  4. 如果已启用,它将检查“Content-Type”响应标头,并查看它是否为图像类型。 如果不是,它将退出。
  5. 如果是图像,则会看到响应是缓冲区还是文件句柄。 如果是以后,它将将图像加载到内存中,根据用户配置的设置应用水印(即图像文件、位置、透明度),将生成的图像保存到内存中缓冲区,将响应数据替换为内存中缓冲区并返回。
  6. 内存中缓冲区将在模块的“Dispose”方法中释放。

使用 ATL 的 CImage 类使加载和处理图像变得非常简单,特别是因为它可以轻松操作各种图像格式。

现在,此示例中存在一些注意事项,应该考虑这一点,尤其是在希望将其用于“真实”生产环境中时:

  • 该代码仅适用于响应位于文件句柄中的图像类型。 HTTP_RESPONSE对象可以改为包含一系列缓冲区中的图像。 一个有趣的练习是创建一个基于内存的 IStream 实现,用于封装响应对象中的缓冲区(注意多个缓冲区响应!)。
  • 该模块不会尝试修改或更新“ETag”响应标头。 这意味着,生成的水印图像将被视为“真实”图像,就客户端而言(应如此),但也可能会混淆客户端缓存逻辑。 正确实现此操作必须修改“ETag”,以考虑水印映像的配置。 例如,在目前的实现过程中,如果您在图像上使用“WatermarkFileA”进行“UpperLeft”位置的水印添加,并设置透明度为“50%”,然后通过浏览器(如 Internet Explorer)发出请求,IE 会根据各种响应标头缓存该图像。 如果要更改水印模块的配置(即更改了图像、位置或透明度),并再次请求文件(通过“F5”),因为图像已由 IE 缓存,而不是请求图像,而是只需执行“HEAD”请求,发送有关图像的信息。 请求处理程序(不知道图像已更改)将响应之前发送的响应仍然有效,并结束请求处理。 遗憾的是,在这种情况下,水印模块将没有机会使用新配置运行并重新为映像加水印,因此客户端会愉快地继续显示旧的水印图像。 正确修复后,水印模块会以某种方式将其配置合并到响应的“ETag”中,以便对图像或水印模块所做的任何更改都会导致任何客户端缓存映像失效并对其重新处理。

配置

水印模块的配置是通过“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,将 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" />

重启该工具,网站中应提供一个新图标。