从多页 TIFF 生成 Silverlight 2 DeepZoom 图像集合






4.86/5 (14投票s)
无需使用外部工具,即可在托管代码中快速生成 DeepZoom 图像瓦片集、集合缩略图和 XML 数据。
致谢
在此项目中,我使用了 Justin Dunlap 在 codeproject.com 上发布的 EditableBitmap 类 的一个版本。Justin 的类为我解决了一个巨大的性能问题,因为他的想法允许我以比使用通常的 Graphics.DrawImage 技术快 400% 的速度渲染图像瓦片。谢谢你,Justin!
引言
这个代码项目受到了 Jose Fajardo 的一次采访 的启发。在视频中,Jose 展示了他的观点:“网上所有的文档都可以被 DeepZoom 化”。在我们公司,我们有一个定期的研发“自由玩耍日”,在我安排的日子里,我决定为我们的文档管理软件尝试 Jose 的概念。我们的软件将扫描件存储为 TIFF 或 JPEG 图像,我决定尝试将它们“DeepZoom 化”。
Jose 使用了 Microsoft DeepZoom Composer 随附的一个命令行工具来转换他的文档,但根据我的经验,在服务器环境中依赖命令行工具并不是一个非常稳定的解决方案,特别是如果你想转换我们的 DMS 通常包含的大量扫描件。使用不同方法的第二个原因是,当前 DeepZoom Composer Beta 版(2008 年 6 月版本)的集合功能有点不稳定。如果你在一个 DeepZoom 集合中混合具有不同 DPI 值的图像,Composer 将不一致地渲染图像位置。通常,我们的客户会在一个扫描件批次中混合 200 dpi 和 300 dpi、纵向和横向的页面,我无法通过 DeepZoom Composer 正确渲染这样的 DeepZoom 集合。
因此,产生了这样一个想法:我希望仅通过我自己的托管 C# 代码生成 DeepZoom 集合,而不依赖任何外部工具或非标准程序集,以确保代码的最大可移植性。我的研发项目是一个简单的 Windows Forms 应用程序,但我严格地将用户界面代码和业务逻辑代码分离,以便将来能在服务器应用程序中重用代码。
背景
DeepZoom 是 Microsoft 新的 Silverlight 环境中的一个流行部分。它是一个非常酷的渐进式渲染系统,允许使用 Google Maps 中使用的类似技术,以非常快的速度进行大幅度的缩放。
与 Google Maps 一样,DeepZoom 使用了多种图像瓦片集,这些瓦片集以各种缩放比例存储。DeepZoom 的瓦片始终为 256x256 像素,并且每个较低的缩放级别都比上一级别缩小一倍,直到达到总是 1x1 像素图像的级别 0。更多信息可以在 Jaime Rodriguez 的 这篇文章 中找到。
有两种不同的 DeepZoom 图像类型:*DeepZoom composition*(组合)和 *DeepZoom collection*(集合)。组合是一个包含所有图像数据的巨大图像瓦片集;集合可以看作是在一页中组合的组合集。
虽然在查看器中集合看起来与组合非常相似,但它还有一个额外的好处,即可以在不重新创建属于组合中相邻图像的图像瓦片的情况下替换集合中的一个图像。此外,集合的概念更适合于面向页面的图像数据,例如文档扫描件批次。
DeepZoom 集合的组成部分
DeepZoom 集合由以下部分组成:
- 一个根文件夹,包含承载 DeepZoom 控件的 Silverlight 项目二进制文件。通常,根文件夹是你的 Web 应用程序的 Silverlight *ClientBin* 子目录。
- 一个存储生成图像(瓦片)的文件夹。默认情况下,它是根文件夹的子目录 *GeneratedImages*。
- 对于集合,DeepZoom Composer 会将三个 XML 数据文件放在 *GeneratedImages* 文件夹中:
- SparseImageDataSceneGraph.xml:此文件包含图像场景的描述,但该描述似乎未被当前版本的查看器使用(请记住:到 2008 年 10 月为止,DeepZoom 的一切都仍是 Beta 版)。
- Metadata.xml:此文件包含与场景图 XML 文件完全相同的数据,格式几乎(但不完全)相同。
- dzc_output.xml:这是查看器实际用于渲染 DeepZoom 集合的数据文件。
- GeneratedImages/dzc_output_images 文件夹包含你 DeepZoom 集合中每个图像的 DeepZoom 组合瓦片集。
- GeneratedImages/dzc_output_files 文件夹包含集合的缩略图瓦片集。这些缩略图瓦片的格式和布局在此 处 有详细说明。
不幸的是,其中一个重要部分 - Viewport 坐标系统 - 目前在官方的 DeepZoom XSD Schema 中并未记载。
使用代码
此代码项目是一个 Windows Forms 应用程序,旨在演示 Decos.DeepZoom.GenerateDeepZoom
类的使用。要查看它的功能,请下载并试用已编译的运行时(.NET 2.0 程序集)。使用文件打开按钮选择提供的“sample.tif”多页 TIFF 文件,或任何你喜欢的图像文件(对于 TIFF 图像保持选中“Scans”,对于 JPG、BMP、GIF 或 PNG 选择“Other image files”),然后单击 [Generate] 按钮。处理完成后,你的默认浏览器的窗口应该会打开,并在 Silverlight 2 beta 2 版本的 DeepZoom 查看器中显示结果。如果你还没有 Silverlight 2 beta 2,网页会提示你“Get Silverlight”。
生成图像的位置
DeepZoom 图像生成在你的 *%TEMP%* 路径下的一个子目录 *DecosDeepZoom* 中。在此目录中,你还会找到 DeepZoomProject.xap 和 DeepZoomProjectTestPage.html 的副本,它们作为嵌入资源链接到可执行程序集。这两个文件是 DeepZoom Composer 生成的测试网站的一个稍作修改的版本(修复了鼠标处理中的一个小 bug,并使控件可缩放)。Silverlight 项目本身也包含在源代码下载中。
启动代码和 GenerateDeepZoom 的主入口点
public frmMain()
{
InitializeComponent();
CreateTestPage();
m_gdz = new GenerateDeepZoom();
m_gdz.OnGenerateDeepZoomProgress +=
new GenerateDeepZoom.GenerateDeepZoomProgress(
m_gdz_OnGenerateDeepZoomProgress);
}
在启动代码中,CreateTestPage()
负责复制嵌入资源并设置输出路径。m_gdz
是稍后将执行实际工作的 GenerateDeepZoom
对象。
private void btnGenerate_Click(object sender, EventArgs e)
{
...
if (m_gdz.GenerateFromScanFile(txtFilePath.Text, m_sDeepZoomImagesPath))
ShowOutput();
else
MessageBox.Show("DeepZoom image generation failed");
...
}
DeepZoom 文件生成器的主入口点是从 Generate 按钮点击处理程序调用的。我们将输入扫描文件的路径和输出文件必须创建的目录的路径传递进去。ShowOutput
是一个简单的函数,它通过 ShellExecute 执行测试 HTML 页面,在浏览器中打开它。
生成过程概述
clsGenerateDeepZoom.cs 包含公共 Decos.DeepZoom.GenerateDeepZoom
类和一个非公共类 Decos.DeepZoom.PageBitmap
。PageBitmap
封装了为单个页面创建 DeepZoom 图像瓦片集的逻辑。在 GenerateFromScanFile
函数中,你会发现一个本地的 ArrayList
,alBitmaps
,它用于保存图像集中的所有 PageBitmap
对象。
生成过程遵循以下步骤:
- 读取页面位图,为每个页面创建一个
PageBitmap
对象。 - 为每个页面调用
PageBitmap.CreateDeepZoomImage
来创建其完整的 DeepZoom 图像瓦片集。 - 创建集合缩略图(调用
CreateCollectionThumbnails
)。 - 创建描述集合的根 XML 文件(调用
CreateSceneAndMetadataXml
)。
颜色表示和图像质量
由于我们的软件主要处理大量黑白扫描件,我对 Silverlight 2 beta 2 DeepZoom 中引入的新 PNG 功能很感兴趣。以前,只能使用 JPEG 瓦片,这不适合黑白文本。不幸的是,你只能为整个集合设置“jpg”/“png”属性,而不能为每个图像单独设置。我的解决方案是默认一个新的集合为黑白/png,并在读取扫描页面时发现至少一个彩色图像时回退到彩色/jpg。
为了最大化性能,该软件仅使用 15 位来表示颜色,这对于“商务图形”来说是可以的,但不太适合照片。要更改此设置,请转到 Decos.DeepZoom.GenerateDeepZoom.CreateTiles
方法并更改此行:
using (EditableBitmap bmScaled =
new EditableBitmap(bm, PixelFormat.Format16bppRgb555,
iWidth, iHeight, bSmoothScaling))
使用每像素位数更多的像素格式(例如,Format24bppRgb
),以改善颜色渲染。
类似地,所使用的向下缩放方法速度很快但质量相当低。唯一的“平滑”处理是 PixelOffsetMode.Half
,这是 System.Drawing
中最基本的抗锯齿方法。如果你不介意性能下降,可以通过编辑 *EditableBitmap.cs* 中的构造函数来提高质量。查找这段代码:
if (bSmoothScaling)
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
并替换为类似这样的代码:
if (bSmoothScaling)
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
}
显然,如果你将所有内容都设置为“高质量”,渲染速度会慢得多。特别是,InterpolationMode.HighQualityBicubic
对性能有很大影响(但也能明显改善结果)。
大图像渲染测试
为了进行一次极端的渲染测试,我下载了一张非常大的 NASA 图像,一张 火星全景图,其极端 JPEG 图像尺寸为 12,756 x 3487 像素(下载量 40 MB)。它在我的 PC(2.66 GHz Intel Core 处理器)上花费了 DecosDeepZoom 15 秒进行转换。有趣的是,转换后,我可以在加载 DeepZoom 图像后更早地放大它,并且比使用 Windows Picture and Fax Viewer 打开原始图像时更轻松、更流畅地进行平移,这是多尺度图像概念强大功能的绝佳演示!如果你比较这两张图像,你会注意到 DeepZoom 图像的颜色质量略低于原始图像(由于我只使用了 15bpp),但分辨率完全没有受到影响。
关注点
用于确定集合缩略图布局的 Morton 编号(文档)是一个有趣的数学难题。如果你想了解更多,这个维基百科页面 可能是一个不错的起点 :-).
你是否曾想过是否可以抑制 Internet Explorer 在本地硬盘上打开的 HTML 文件时显示的恼人的 JavaScript 安全警告?DeepZoomProjectTestPage.html 没有这个问题,而 html
标签下方这行就是原因:
<!-- saved from url=(0014)about:internet -->
未经记载的愚蠢之处...
历史
- 2008 年 6 月 29 日:创建第一个版本
- 2008 年 6 月 30 日,2008 年 7 月 1 日:小幅更新。
- 2008 年 7 月 9 日:改进了对大型 PNG 源图像的支持,允许在 UI 中设置 JPEG 质量和每像素位数。
- 2007 年 7 月 12 日:重写了
CreateCollectionThumbnails
以支持大型缩略图集。