基于事件的 XPS 页面修改 | .NET

什么是基于事件的编程方法?

基于事件的编程方法是一种围绕事件和事件处理概念的范式。在此模型中,程序的流程由事件决定,这些事件可以是用户操作(例如鼠标点击或键盘按下)、系统生成的通知或来自其他应用程序的消息。以下是基于事件的方法的一些关键方面:

总的来说,基于事件的方法是管理程序内交互和工作流的有效方法,对于需要响应能力和用户交互的应用程序特别有效。

XPS 文档转换期间发生的事件

当您需要使用 Aspose.Page API 更改 XPS 文档的特定页面时,通常需要选择活动文档(如果 XPS 文件中有多个文档),然后选择活动页面,然后自行进行更改。

现在,假设您需要对 XPS 文件中的所有页面进行重复更改,然后将结果转换为 PDF 或图像格式。此类更改的一些示例包括在页面上添加水印或添加导航超链接。进行此类更改的直接方法是遍历 XPS 包中的文档,遍历当前活动文档中的页面,最后应用更改。因此,完成此任务的代码如下所示:

 1for (int i = 1; i <= document.DocumentCount; i++)
 2{
 3    document.SelectActiveDocument(i);
 4    for (j = 1; j <= document.PageCount; j++)
 5    {
 6        document.SelectActivePage(j);
 7        // Your changes ...
 8    }
 9}
10document.SaveAsPdf("file-name.pdf", saveOptions);

如果您还需要在重复的更改之前进行一些不规则的更改,这种方法可能会导致一些混乱或过度遍历文档和页面,更不用说这些循环看起来有点繁琐。

将 XPS 文档转换为 PDF 或图像时,该过程会逐页进行。当转换作业准备好处理下一页时,它会触发“before-page”事件。用户可以通过扩展 BeforePageSavingEventHandler 类来定义此类事件的处理,从而利用本文简介部分概述的一些优势。

添加导航超链接示例

在这里,我们将提供一个与导航超链接相关的示例。为了使任务稍微复杂一些,我们将仅将所有页面的子集转换为 PDF,如 PdfSaveOptions.PageNumbers 属性所指定。

事件处理程序类

以下是 BeforePageSavingEventHandler 类的扩展:

 1/// <summary>
 2/// The class to handle the before-page event while converting an XPS document.
 3/// </summary>
 4public class NavigationInjector : BeforePageSavingEventHandler
 5{
 6    // The font in which navigation hyperlinks and page numbers will be displayed.
 7    private readonly XpsFont _font;
 8    // The page numbers to convert.
 9    private readonly SortedList<int, int> _pageNumbers;
10
11    public NavigationInjector(XpsFont font, int[] pageNumbers)
12    {
13        _font = font;
14        if (pageNumbers == null)
15            return;
16
17        // Turn the page number array into a sorted collection of unique values.
18        _pageNumbers = new SortedList<int, int>();
19        foreach (int pn in pageNumbers)
20            _pageNumbers[pn] = 0;
21    }
22
23    public override void Handle(BeforeSavingEventArgs<PageAPI> args)
24    {
25        PageAPI api = args.ElementAPI;
26
27        XpsGlyphs glyphs;
28        // For all pages in the output PDF except the first one...
29        if (args.OutputPageNumber > 1)
30        {
31            // ...insert a hyperlink to the first page...
32            glyphs = api.CreateGlyphs(_font, 15f, 5f, api.Height - 10f, "[First]");
33            glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
34            glyphs.HyperlinkTarget = new XpsPageLinkTarget(_pageNumbers == null ? 1 : _pageNumbers.Keys[0]);
35            api.Add(glyphs);
36
37            // ...and to the previous page.
38            glyphs = api.CreateGlyphs(_font, 15f, 60f, api.Height - 10f, "[Prev]");
39            glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
40            glyphs.HyperlinkTarget = new XpsPageLinkTarget(
41                _pageNumbers == null ? args.AbsolutePageNumber - 1 : _pageNumbers.Keys[args.OutputPageNumber - 2]);
42            api.Add(glyphs);
43        }
44
45        // For all pages in the output PDF except the last one...
46        if ((_pageNumbers != null && args.OutputPageNumber < _pageNumbers.Count) ||
47            (_pageNumbers == null && args.OutputPageNumber < api.TotalPageCount))
48        {
49            // ...insert a hyperlink to the next page...
50            glyphs = api.CreateGlyphs(_font, 15f, 110f, api.Height - 10f, "[Next]");
51            glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
52            glyphs.HyperlinkTarget = new XpsPageLinkTarget(
53                _pageNumbers == null ? args.AbsolutePageNumber + 1 : _pageNumbers.Keys[args.OutputPageNumber]);
54            api.Add(glyphs);
55
56            // ...and to the last page.
57            glyphs = api.CreateGlyphs(_font, 15f, 160f, api.Height - 10f, "[Last]");
58            glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
59            glyphs.HyperlinkTarget = new XpsPageLinkTarget(
60                _pageNumbers == null ? api.TotalPageCount : _pageNumbers.Keys[_pageNumbers.Keys.Count - 1]);
61            api.Add(glyphs);
62        }
63
64        // Insert a page number in the bottom-right corner.
65        glyphs = api.CreateGlyphs(_font, 15f, api.Width - 20f, api.Height - 10f, args.OutputPageNumber.ToString());
66        glyphs.Fill = api.CreateSolidColorBrush(Color.Black);
67        api.Add(glyphs);
68
69        // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
70        api.AddOutlineEntry(string.Format("Page {0}", args.OutputPageNumber), 1, args.AbsolutePageNumber);
71    }
72}

为了创建正确的超链接目标,处理程序类应该知道我们想要保存为 PDF 的页面。因此,构造函数应该将 options 的数组属性作为参数。如果指定了页码数组,我们会创建一个已排序的页码集合,同时避免重复。(顺便说一句,这个解决方案并不完全准确。你能找出导致输出不一致的原因吗?)我们还需要一个 XpsFont 对象,其中包含超链接文本的字体数据。

所有操作都发生在重写的 Handle() 方法中。该方法的参数是一个对象,其中包含当前页面的修改 API、XPS 包中的文档编号、所有文档的 绝对页码、当前文档中的 相对页码(如果包中只有一个文档,则等于之前的页码)以及 输出页码(当我们转换整个包时,它等于绝对页码)。

以下两个 if 块的逻辑非常简单。它基于对 OutputPageNumber 事件参数的分析,在适当的情况下省略了一些链接:[First][Prev] 链接将添加到除第一个页面之外的所有输出页面,而 [Next][Last] 链接将出现在除最后一个页面之外的所有页面上。无论是否指定页码,该逻辑都针对这两种情况进行了定制。

if 块之后是用于在页面右下角添加页码的代码。

最后一行添加了页面的大纲条目,该条目将显示在 PDF 查看器的导航窗格中(如果支持)。

转换代码

既然已经定义了“before-page”事件处理程序,我们就可以编写转换文档的代码了:

 1// The path to the documents directory.
 2string dataDir = RunExamples.GetDataDir_WorkingWithPages();
 3// Open an XPS document
 4using (XpsDocument doc = new XpsDocument(dataDir + "Sample3.xps"))
 5// Create a font
 6using (Stream fontStream = File.OpenRead(dataDir + "arialbd.ttf"))
 7{
 8    // Create options for conversion to PDF
 9    PdfSaveOptions options = new PdfSaveOptions();
10    // Set the filter for the pages that need conversion
11    options.PageNumbers = new int[] { 2, 6, 7, 13 };
12    // Add the event handler that will execute right before the conversion of each page
13    options.BeforePageSavingEventHandlers.Add(new NavigationInjector(doc.CreateFont(fontStream), options.PageNumbers));
14    // Save resultant XPS document
15    doc.SaveAsPdf(dataDir + "ModifyPageOnConversion_out.pdf", options);
16}

我们打开一个 XPS 文件,然后使用字体数据文件实例化一个流对象。接下来,我们创建 PdfSaveOptions 类的实例,并指定需要转换的页数。下一行代码中,“before-page”事件处理程序通过 BeforePageSavingEventHandlers 集合选项与转换任务“连接”。

接下来只需使用文档的 SaveAsPdf() 方法将文件转换为 PDF 格式即可。

结论

在本文中,我们探讨了基于事件的编程方法的关键点,研究了直接修改 XPS 文档页面的方法,并学习了一种更高级、更复杂的技术,用于在转换过程中对所有输出页面进行重复更改,并以插入导航超链接为例。

如需查看完整示例,请探索我们的 示例项目

Have any questions about Aspose.Page?



Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.