修改 XPS 页面事件 | Java
理解基于事件的编程方法
基于事件的编程方法是一种专注于事件及其处理的范式。在此模型中,程序的流程由事件决定,这些事件可以包括用户操作(例如鼠标点击或键盘按下)、系统生成的通知或来自其他应用程序的消息。以下是基于事件的方法的一些关键方面:
事件:事件表示程序中发生的重要事件。这些事件可以包括用户交互、数据更改或来自系统不同组件的消息。例如,按钮点击或文件加载都可以触发事件。
事件监听器:为了处理事件,程序员使用事件监听器(或处理程序)。这些是指定在特定事件发生时运行的函数或方法。例如,可以配置事件监听器以在用户点击按钮时执行某个函数。
异步执行:基于事件的模型通常有利于异步编程,使程序能够在等待事件的同时保持响应能力。例如,Web 应用程序可以在等待服务器数据的同时保持正常运行。
解耦:基于事件的方法鼓励程序中各个组件之间的解耦。这些组件可以通过事件进行交互,而无需了解彼此的实现细节,从而生成更加模块化且易于维护的代码。
常见用例:事件驱动编程通常用于图形用户界面 (GUI)、Web 应用程序以及需要实时交互的系统。Node.js、React 等框架和库都利用了事件驱动模式。
状态管理:在事件驱动系统中,有效的状态管理至关重要,因为应用程序可能根据用户交互或事件处于各种状态。通常会实施适当的状态管理策略,以确保应用程序按预期运行。
总体而言,基于事件的方法是一种管理程序内交互和工作流的有效方法,尤其适用于需要响应能力和用户交互的应用程序。
XPS 文档转换和事件
当您需要使用 Aspose.Page API 修改 XPS 文档的特定页面时,通常需要选择活动文档(如果 XPS 文件中有多个文档),然后选择活动页面,然后应用更改。
现在,假设您需要在 XPS 文件的所有页面上实施重复更改,然后将结果转换为 PDF 或图像格式。此类更改的示例可能包括在页面上添加水印或插入导航超链接。进行此类更改的直接方法是遍历 XPS 包中的文档,遍历当前活动文档中的页面,最后应用更改。因此,实现此任务的代码如下所示:
1for (int i = 1; i <= document.getDocumentCount(); i++)
2{
3 document.selectActiveDocument(i);
4 for (j = 1; j <= document.getPageCount(); j++)
5 {
6 document.selectActivePage(j);
7 // Your changes ...
8 }
9}
10document.saveAsPdf("file-name.pdf", saveOptions);如果您还需要在应用重复更改之前进行一些不定期的更改,这种方法可能会导致混乱或过度遍历文档和页面。此外,这些循环可能看起来有些繁琐。
将 XPS 文档转换为 PDF 或图像时,该过程一次进行一页。当转换作业准备处理下一页时,它会触发“before-page”事件。用户可以通过扩展 BeforePageSavingEventHandler 类来定义此类事件的行为(事件处理),从而利用本文简介部分讨论的一些优势。
添加导航超链接的示例
在本节中,我们将介绍一个涉及导航超链接的示例。为了使任务稍微复杂一些,我们将仅将所有页面的子集转换为 PDF,如 PdfSaveOptions.setPageNumbers() 方法所定义。
事件处理程序类
以下是 BeforePageSavingEventHandler 类的扩展:
1// The class to handle the before-page event while converting an XPS document.
2private static class NavigationInjector extends BeforePageSavingEventHandler {
3 // The font in which navigation hyperlinks and page numbers will be displayed.
4 private final XpsFont font;
5 // The page numbers to convert.
6 private final TreeMap<Integer, Integer> pageNumbers;
7
8 public NavigationInjector(XpsFont font, int[] pageNumbers) {
9 this.font = font;
10 if (pageNumbers == null) {
11 this.pageNumbers = null;
12 return;
13 }
14
15 // Turn the page number array into a sorted collection of unique values.
16 this.pageNumbers = new TreeMap<>();
17 for (int pn : pageNumbers) {
18 this.pageNumbers.put(pn, 0);
19 }
20 }
21
22 /**
23 * The action itself to be triggered on a before-page event.
24 *
25 * @param args The event arguments.
26 */
27 @Override
28 public void handle(BeforeSavingEventArgs<PageAPI> args) {
29 PageAPI api = args.getElementAPI();
30
31 XpsGlyphs glyphs;
32 // For all pages in the output PDF except the first one...
33 if (args.getOutputPageNumber() > 1) {
34 // ...insert a hyperlink to the first page...
35 glyphs = api.createGlyphs(font, 15f, 5f, api.getHeight() - 10f, "[First]");
36 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
37 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(pageNumbers == null ? 1 : pageNumbers.firstKey()));
38 api.add(glyphs);
39
40 // ...and to the previous page.
41 glyphs = api.createGlyphs(font, 15f, 60f, api.getHeight() - 10f, "[Prev]");
42 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
43 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
44 pageNumbers == null ? args.getAbsolutePageNumber() - 1 :
45 pageNumbers.keySet().toArray(new Integer[0])[args.getOutputPageNumber() - 2]));
46 api.add(glyphs);
47 }
48
49 // For all pages in the output PDF except the last one...
50 if ((pageNumbers != null && args.getOutputPageNumber() < pageNumbers.size()) ||
51 (pageNumbers == null && args.getOutputPageNumber() < api.getTotalPageCount())) {
52 // ...insert a hyperlink to the next page...
53 glyphs = api.createGlyphs(font, 15f, 110f, api.getHeight() - 10f, "[Next]");
54 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
55 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
56 pageNumbers == null ? args.getAbsolutePageNumber() + 1 :
57 pageNumbers.keySet().toArray(new Integer[0])[args.getOutputPageNumber()]));
58 api.add(glyphs);
59
60 // ...and to the last page.
61 glyphs = api.createGlyphs(font, 15f, 160f, api.getHeight() - 10f, "[Last]");
62 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
63 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
64 pageNumbers == null ? api.getTotalPageCount() :
65 pageNumbers.lastKey()));
66 api.add(glyphs);
67 }
68
69 // Insert a page number in the bottom-right corner.
70 glyphs = api.createGlyphs(font, 15f, api.getWidth() - 20f, api.getHeight() - 10f,
71 String.valueOf(args.getOutputPageNumber()));
72 glyphs.setFill(api.createSolidColorBrush(Color.BLACK));
73 api.add(glyphs);
74
75 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
76 api.addOutlineEntry(String.format("Page %d", args.getOutputPageNumber()), 1, args.getAbsolutePageNumber());
77 }
78}处理程序类需要知道我们打算保存为 PDF 的页面,以便建立正确的超链接目标。因此,构造函数应该将选项的 getPageNumbers() 数组属性作为参数。如果提供了页码数组,我们将创建一个已排序的页码集合,同时排除重复项。此外,该类需要一个 XpsFont 对象,其中包含超链接文本的字体数据。
所有操作都发生在重写的 handle() 方法中。该方法的参数是一个对象,其中包含当前页面的修改 API、XPS 包中的文档编号、所有文档的 绝对页码、当前文档中的 相对页码(如果包中只有一个文档,则等于之前的页码)以及 输出页码(当我们转换整个包时,它等于绝对页码)。
以下两个 if 块的逻辑非常简单。它分析 getOutputPageNumber() 事件参数,并在适当的情况下省略一些链接:[First] 和 [Prev] 链接不会添加到第一页,而 [Next] 和 [Last] 链接不会出现在最后一页。该逻辑也设计为同时适应这两种情况,无论是否指定页码。
在 if 块之后,有一段代码用于在页面的右下角添加页码。
最后一行添加了页面的大纲条目,该条目将显示在 PDF 查看器(如果支持)的导航窗格中。
转换代码
现在“before-page”事件处理程序已定义,我们可以编写文档转换的代码了:
1// Modify page on conversion event.
2
3// Open an XPS document
4try (XpsDocument doc = new XpsDocument(getDataDir() + "Sample3.xps");
5 // Create a font
6 FileInputStream fontStream = new FileInputStream(getDataDir() + "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.setPageNumbers(new int[] { 2, 6, 7, 13 });
12 // Add the event handler that will execute right before the conversion of each page
13 options.getBeforePageSavingEventHandlers().add(new NavigationInjector(doc.createFont(fontStream), options.getPageNumbers()));
14 // Save resultant XPS document
15 doc.saveAsPdf(getOutputDir() + "ModifyPageOnConversion_out.pdf", options);
16}我们打开一个 XPS 文件,然后使用字体数据文件创建一个流对象。接下来,我们实例化 PdfSaveOptions 类并指定需要转换的页码。以下代码通过 getBeforePageSavingEventHandlers() 集合将“before-page”事件处理程序“连接”到转换作业。
现在剩下要做的就是使用文档的 saveAsPdf() 方法运行 PDF 转换。
结论
在本文中,我们介绍了基于事件的编程方法的基本方面,研究了修改 XPS 文档页面的直接方法,并探索了一种更高级的技术,用于在转换过程中对所有输出页面进行重复更改,并以插入导航超链接为例。
有关完整示例,请探索我们的 示例项目。