65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ImageGear for Silverlight 构建多页图像查看器

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009年5月1日

CPOL

9分钟阅读

viewsIcon

26950

本文将通过开发一个完全在客户端通过托管代码运行的多页图像查看器,快速介绍 Accusoft Pegasus 的 ImageGear for Silverlight 工具包。

随着过去十年间对提供丰富 Web 内容和功能的期望不断提高,富 Internet 应用程序 (RIA) 技术变得越来越强大。不幸的是,由于涉及非平凡的学习曲线,许多这些技术对许多客户端应用程序开发人员来说仍然遥不可及。此外,面对可用的 RIA 技术数量,你甚至不知道从何开始?在许多情况下,没有“一刀切”的解决方案,因此 RIA 开发可能涉及 HTML、JavaScript、Adobe Flash 的混合,或许还会加上一点 AJAX(仅举几例)。幸运的是,微软已经进入了 RIA 框架领域,并通过引入 Microsoft Silverlight 2,提供了一个可以利用现有 .NET 开发人员才能的平台。随着 3.0 版本的发布,它提供了增强的图形支持、数据绑定,或许最重要的是,支持浏览器外运行,Silverlight 平台绝对值得新用户甚至现有用户在 RIA 开发中考虑。

Silverlight 包含许多与 .NET Framework 中相同的基本服务和类型。然而,由于它是一个专为 Web 构建的运行时,开发人员期望在小巧的包中拥有一个强大的平台,因此其桌面版本中的许多功能都缺失了。例如,Silverlight 中的图像类型 `System.Windows.Media.Imaging.BitmapImage` 只支持 JPEG 和 PNG 图像文件类型,并且不包含对灰度图的支持。这就是第三方工具供应商成为 Silverlight 生态系统的一部分的原因,它们根据市场需求提供对基础平台的扩展。在图像领域,Accusoft Pegasus 作为图像工具领域的领导者,通过为 Silverlight 开发人员提供首批图像工具包之一——ImageGear for Silverlight——延续了其声誉。

本文将在开发一个完全在客户端通过托管代码运行的多页图像查看器时,快速介绍 ImageGear for Silverlight 工具包。

构建查看器

要开始,请在此处下载 ImageGear for Silverlight SDK 和示例代码。此处。打开 Visual Studio 2008,然后打开“新建项目”对话框。在“Visual C#”标题下,选择“Silverlight”作为项目类型,然后选择“Silverlight 应用程序”作为项目模板。如果“Silverlight”不可用,则需要安装 Microsoft 提供的 Silverlight 2 SDK。最后,为你的项目输入名称,然后单击“确定”(图 1)。

ImageGear/image001.jpg

图 1:定义 Silverlight 项目

在你创建项目时显示的下一个屏幕,特别是对于 Silverlight 开发新手来说,值得解释一下。Silverlight 应用程序的部署单位是 XAP 包,它部署在 HTML 网页中,或作为 ASP.NET 项目的一部分。对于许多 Silverlight 应用程序来说,使用 HTML 网页作为宿主就足够了。然而,ImageGear for Silverlight 使用 Web 服务来验证其 SDK 许可证,并且调用该 Web 服务的 Silverlight 应用程序必须运行在托管该服务的域名上。因此,最好避免使用 HTML 网页选项,而是创建 ASP.NET 项目。项目向导会为你设置好一切(图 2),因此即使是最缺乏经验的 Web 开发人员也能胜任。

ImageGear/image002.jpg

图 2:选择 Silverlight 宿主

然后,只需单击“确定”按钮,就会创建一个解决方案,其中包含两个项目——Silverlight 应用程序(我们将花费大部分时间在这里)和一个 ASP.NET 宿主(设置为启动项目)。如果你现在编译并运行,应用程序就会执行;然而,它会相当乏味——在 IE 中只有一个空白页面。然而,这个页面并非空白。它里面运行着一个功能齐全的 Silverlight 应用程序。我们只需要构建它的布局来支持我们的图像查看器。

定义布局

如果你使用过 **Windows Presentation Foundation (WPF)** 或 **Windows Workflow Foundation (WF)**,你可能已经熟悉 XAML。XAML 仅仅是一种初始化一组 .NET 类型的方式,但它在微软提供的下一代 GUI 堆栈中非常流行,这在 Silverlight 中也得到了体现。为了定义我们多页图像查看器的布局,我们将修改生成的 XAML,指定一个比默认空白界面更合适的 UI。XAML 和 Silverlight GUI 堆栈的完整概述超出了本文的范围,但我们将简要解释我们正在做的事情。

为了帮助我们定位,下图 3 显示了 Visual Studio 生成的默认视图和 XAML。它定义了一个 Silverlight **UserControl**,其中包含一个空的 **Grid**。

ImageGear/image003.jpg

图 3:生成的 Page.xaml

对于我们的图像查看器,我们想在 **UserControl** 中添加几个控件——一个 `ImGearSilverlightPageView` 类型的实例用于显示图像,以及几个按钮用于支持打开文件和在页面之间导航。但是,在我们修改 XAML 之前,我们需要向项目添加一些引用,以确保对 ImageGear for Silverlight 的调用在编译时能够解析。ImageGear for Silverlight 允许开发人员只部署其特定应用程序所需的程序集。这使得开发人员可以保持部署包的小尺寸,同时支持非必要程序集的后台加载。ImageGear for Silverlight 中的程序集的完整列表和描述在工具包的文档中。现在,确保你的引用列表如图 4 所示就足够了。你会在你的 `\\ProgramFiles\Accusoft\ImageGear for Silverlight\Bin` 目录下找到 ImageGear for Silverlight 程序集。

ImageGear/image004.jpg

图 4:必需的引用

最后,列表 1(如下)显示了我们图像查看器布局的 XAML。列表 1 中的 XAML 在原始网格中添加了两行,一行用于容纳图像查看器,另一行用于容纳按钮。对于 `ImGearSilverlightPageView`,它直接放置在单元格中,因为它将简单地填充其可用空间。然而,按钮需要一些额外的布局容器来确保创建所需的布局。这是通过一个包含两列的第二个 **Grid** 来实现的。第一列将包含一个我们将用于调用“打开文件”操作的 **Button**。第二列将包含两个按钮——“上一页”和“下一页”——因此我们将使用一个 **StackPanel** 容器,并在其中放置两个按钮。我们 XAML 中另一个主要关注点是为我们的每个按钮使用 **Style** 资源。为了使我们的 XAML 更简洁、更高效,按钮的外观被定义了一次,作为包含在 **UserControl** 资源中的 **Style**,并应用于每个按钮。关于 Silverlight GUI 元素和 XAML,有许多出色的资源,如果你不熟悉这些技术,我鼓励你去看看。你将永远不想再拖放用户控件了!

列表 1:多页图像查看器 XAML

<UserControl x:Class="MultiPageImageViewer.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:IGSilverlightUI="clr-namespace:ImageGear.Silverlight.UI;assembly=IGSilverlightUIV16sn"
    MinWidth="640" MinHeight="480">
 
    <UserControl.Resources>
        <Style x:Key="ButtonStyle" TargetType="Button">
            <Setter Property="Width" Value="100"/>
            <Setter Property="Margin" Value="8,4,8,4"/>
        </Style>
    </UserControl.Resources>
 
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="9*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!-- Primary Image Viewer -->
        <Grid Grid.Row="0" Background="Gray">
            <IGSilverlightUI:ImGearSilverlightPageView Margin="8"
                x:Name="mPageView" Background="Gray"/>
        </Grid>
 
        <!-- Button Row -->
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="2*"/>
            </Grid.ColumnDefinitions>
 
            <Button x:Name="mOpenButton" Grid.Column="0"
                    Style="{StaticResource ButtonStyle}"
                    Click="mOpenButton_Click" HorizontalAlignment="Left"
                    IsEnabled="False">

               <TextBlock Text="Open File"/>
            </Button>
 
            <StackPanel Grid.Column="1" Orientation="Horizontal"
                 HorizontalAlignment="Right">
                <Button x:Name="mPreviousButton" Style="{StaticResource ButtonStyle}"
                        Click="mPreviousButton_Click" IsEnabled="False">
                    <TextBlock Text="<< Previous"/>
                </Button>
                <Button x:Name="mNextButton" Style="{StaticResource ButtonStyle}"
                        Click="mNextButton_Click" IsEnabled="False">
                    <TextBlock Text="Next >>"/>
                </Button>
            </StackPanel>
        </Grid>
    </Grid>
</UserControl>

现在,仅凭 XAML 定义很难直观地看到我们的图像查看器。幸运的是,Visual Studio 支持分屏视图,这样你就可以在进行的同时看到 XAML 的结果。下图 5 显示了列表 1 中 XAML 生成的布局。

ImageGear/image005.jpg

图 5:多页图像查看器布局

我们离空白页面已经走了很远,但现在我们需要编写应用程序运行的代码。如果你现在编译并运行,你会遇到各种错误(其中之一是缺少单击事件处理程序),所以让我们来处理这些问题,让我们的图像查看器运行起来!

代码

我们将从初始化代码开始,该代码包含在下面的列表 2 所示的 **Page** 构造函数中。ImageGear for Silverlight 需要许可证才能运行,在你开发应用程序时,它会使用 Web 服务进行验证。[1] `ImGearLicense.SetService` 调用允许你指定此 Web 服务的地址,并且它需要从与工具包相同机器上的 URL 运行。接下来,设置一个匿名委托,以便在 `LicenseRequest` 事件触发后立即运行,稍后将详细介绍。最后,调用 `ImGearLicense.SetSolutionName`,将评估解决方案名称作为参数传递。

`LicenseRequest` 事件发生时执行的匿名委托是其余初始化的发生地。由于涉及 Web 服务,因此需要该事件;当向 Web 服务发出许可证请求时,响应不是同步的。因此,我们必须等到请求被授予后才能继续。在委托体内部,执行 PNG 和 Windows(位图)编解码器的初始化,以及 CCITT TIFF、TIFF 和 JPEG。虽然工具包在 `ImGearSilverlightPageView` 中显示图像需要 PNG 和 Windows 格式,但所有其他格式都是可选的。开发人员可以自行选择。

列表 2:Page 构造函数和 ImageGear for Silverlight 初始化

public Page()
{
    InitializeComponent();
 
    // ImageGear for Silverlight Development licensing. This licensing
    // requires the sample to be run from a URL hosted on the same machine
    // ImageGear for Silverlight was installed on.
    string webServiceUrl = string.Format("http://{0}/{1}",
        App.Current.Host.Source.DnsSafeHost,
        "SilverlightWebService/SilverlightWebService.svc");
 
    ImGearLicense.SetService(webServiceUrl);
    ImGearLicense.LicenseRequest =
        new ImGearLicense.DelegateLicenseRequest(delegate(Exception error)
       {
          // Initialize format components
            // Required for ImGearSilverlightPageView
            ImGearFormatsPNGIFComponent.Initialize();
            ImGearFormatsWindowsComponent.Initialize();
               
            // Common formats
            ImGearFormatsCCITTComponent.Initialize();
            ImGearFormatsTIFFComponent.Initialize();
            ImGearFormatsJPEGComponent.Initialize();  
 
          // ImageGear Initialized and Licensed; Enable the Open Button
              this.mOpenButton.IsEnabled = true;
        });
 
     ImGearLicense.SetSolutionName("AccuSoft 5-44-16");
}

工具包初始化后,我们可以为每个按钮编写处理程序,并获取一些图像在应用程序中显示。`mOpenButton` 处理程序(列表 3)执行大部分工作。大多数代码都是现成的,熟悉使用 `OpenFileDialog` 类型的人都会很熟悉。创建的 **Stream** 作为参数传递给 `ImGearFileFormats.LoadDocument` 进行加载。如果工具包知道与文件类型对应的编解码器(通过上面的初始化),它就会加载;否则,会抛出 `ImGearException`。

在文档加载并获取 `ImGearDocument` 实例后,会创建一个 `ImGearPageDisplay` 实例来指定 `ImGearSilverlightPageView` 的可显示页面。将这些概念联系起来的最简单方法是:将 `ImGearDocument` 视为文件的内存表示,将 `ImGearPageDisplay` 视为用于显示的页面的逻辑表示。换句话说,`ImGearPageDisplay` 类型包含 `ImGearSilverlightPageView` 正确显示页面的指令。示例可能包括分辨率、剪裁矩形或所需的转换。最后,为了显示页面,将 `ImGearPageDisplay` 分配给 `ImGearSilverlightPageView.Display` 属性,并调用 `ImGearSilverlightPageView.Update` 来强制重绘。

列表 3:打开按钮处理程序

private ImGearDocument mLoadedDocument = null;
private Int32 mCurrentPage = -1;
private ImGearPageDisplay mCurrentPageDisplay = null;
 
          .
          .
          .

private void mOpenButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    // Prompt the user to select an image file
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter =
        "Image files (*.tif;*.jpg;*.png;*.bmp)|*.tif;*.jpg;*.png;*.bmp|All files (*.*)|*.*";
    ofd.FilterIndex = 1;
    bool? result = ofd.ShowDialog();
           
    if (!result.GetValueOrDefault(false))
        return;
 
    try
    {
        using (Stream f = ofd.File.OpenRead())
        {
            // Open it with ImageGear, showing the first page by default
            this.mLoadedDocument = ImGearFileFormats.LoadDocument(f, 0, -1);
            this.mCurrentPage = 0;
 
            if (null == this.mCurrentPageDisplay)
            {
                this.mCurrentPageDisplay =
                   new ImGearPageDisplay(this.mLoadedDocument.Pages[this.mCurrentPage]);
            }
            else
            {
                this.mCurrentPageDisplay.Page =
                   this.mLoadedDocument.Pages[this.mCurrentPage];
            }
 
            mPageView.Display = this.mCurrentPageDisplay;
            mPageView.Update();
 
            // Update the previous\next buttons depending on page count
            this.UpdateButtonStates();
        }   
    }
    catch (ImGearException)
    {
        MessageBox.Show("The file selected is not supported by this sample.",
                "MultiPageTiffViewer Control", System.Windows.MessageBoxButton.OK);
    }
}

其余代码通过上一页和下一页按钮来操作显示的页面,修改由 `ImGearSilverlightPageView` 类型显示的页面。**ImGearDocument** 中的 **Pages** 集合允许你选择在 `ImGearPageDisplay` 中加载的页面。请记住,在更改页面显示时,务必调用 `ImGearSilverlightPageView.Update`,否则将不会发生重绘。

列表 4:上一页和下一页按钮处理程序,UpdateButtonStates 方法

private void mPreviousButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    if (this.mCurrentPage > 0)
    {
        this.mCurrentPageDisplay.Page = this.mLoadedDocument.Pages[--this.mCurrentPage];
        this.mPageView.Update();
    }
 
    // Update the previous\next buttons depending on page count
    this.UpdateButtonStates();           
}
 
private void mNextButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
    if (this.mCurrentPage < this.mLoadedDocument.Pages.Count - 1)
    {
        this.mCurrentPageDisplay.Page = this.mLoadedDocument.Pages[++this.mCurrentPage];
        this.mPageView.Update();
    }
 
    // Update the previous\next buttons depending on page count
    this.UpdateButtonStates();
}
 
private void UpdateButtonStates()
{
    this.mPreviousButton.IsEnabled =
        (this.mCurrentPage > 0 && mLoadedDocument.Pages.Count > 1) ? true : false;          
           
    this.mNextButton.IsEnabled =
        ((this.mCurrentPage < (this.mLoadedDocument.Pages.Count - 1) &&
        mLoadedDocument.Pages.Count > 1)) ? true : false;
}

至此,我们有了 Silverlight 的多页图像查看器!下图 6 显示了最终产品,其中添加了一些由 Web 设计师设计的“点缀”。借助 ImageGear for Silverlight,我们能够扩展基础平台以支持加载 TIFF 文件,并且我们有了一个适合文档成像显示的 RIA。最重要的是,这一切都是使用 XAML 和 C# 等当前 .NET 技术,利用生态系统中的工具完成的。当然,一个功能齐全的查看器可以做得更多,ImageGear for Silverlight 将帮助你实现这一目标。

ImageGear/image006.jpg

图 6:多页图像查看器

你可以在 www.accusoft.com 找到 Pegasus Imaging 的产品下载和功能。www.accusoft.com。有关更多信息,请通过 sales@accusoft.com 或 support@accusoft.com 联系我们。

[1] 有关部署许可的更多信息,请参阅 ImageGear for Silverlight 文档。

© . All rights reserved.