修改 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/**
2 * The class to handle the before-page event while converting an XPS document.
3 */
4public static class NavigationInjector extends BeforePageSavingEventHandler
5{
6 private final XpsFont _font;
7 private List<Integer> _pageNumbers;
8
9 public NavigationInjector(XpsFont font, int[] pageNumbers)
10 {
11 _font = font;
12 if (pageNumbers == null || pageNumbers.length == 0)
13 return;
14
15 // Turn the page number array into a sorted collection of unique values.
16 SortedMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
17 for (int pn : pageNumbers)
18 map.put(pn, 0);
19 _pageNumbers = new ArrayList<Integer>(map.keySet());
20 }
21
22 /**
23 * The action itself to be triggered on a before-page event.
24 * @param args The even arguments.
25 */
26 @Override
27 public void handle(BeforeSavingEventArgs<PageAPI> args)
28 {
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 {
35 // ...insert a hyperlink to the first page...
36 glyphs = api.createGlyphs(_font, 15f, 5f, api.getHeight() - 10f, "[First]");
37 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
38 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(_pageNumbers == null ? 1 : _pageNumbers.get(0)));
39 api.add(glyphs);
40
41 // ...and to the previous page.
42 glyphs = api.createGlyphs(_font, 15f, 60f, api.getHeight() - 10f, "[Prev]");
43 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
44 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
45 _pageNumbers == null ? args.getAbsolutePageNumber() - 1 : _pageNumbers.get(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 {
53 // ...insert a hyperlink to the next page...
54 glyphs = api.createGlyphs(_font, 15f, 110f, api.getHeight() - 10f, "[Next]");
55 glyphs.setFill(api.createSolidColorBrush(Color.BLUE));
56 glyphs.setHyperlinkTarget(new XpsPageLinkTarget(
57 _pageNumbers == null ? args.getAbsolutePageNumber() + 1 : _pageNumbers.get(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() : _pageNumbers.get(_pageNumbers.size() - 1)));
65 api.add(glyphs);
66 }
67
68 // Insert a page number in the bottom-right corner.
69 glyphs = api.createGlyphs(_font, 15f, api.getWidth() - 20f, api.getHeight() - 10f, Integer.toString(args.getOutputPageNumber()));
70 glyphs.setFill(api.createSolidColorBrush(Color.BLACK));
71 api.add(glyphs);
72
73 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
74 api.addOutlineEntry(MessageFormat.format("Page {0}", args.getOutputPageNumber()), 1, args.getAbsolutePageNumber());
75 }
76}
处理程序类需要知道我们打算保存为 PDF 的页面,以便建立正确的超链接目标。因此,构造函数应该将选项的 getPageNumbers()
数组属性作为参数。如果提供了页码数组,我们将创建一个已排序的页码集合,同时排除重复项。此外,该类需要一个 XpsFont
对象,其中包含超链接文本的字体数据。
所有操作都发生在重写的 handle()
方法中。该方法的参数是一个对象,其中包含当前页面的修改 API、XPS 包中的文档编号、所有文档的 绝对页码、当前文档中的 相对页码(如果包中只有一个文档,则等于之前的页码)以及 输出页码(当我们转换整个包时,它等于绝对页码)。
以下两个 if
块的逻辑非常简单。它分析 getOutputPageNumber()
事件参数,并在适当的情况下省略一些链接:[First]
和 [Prev]
链接不会添加到第一页,而 [Next]
和 [Last]
链接不会出现在最后一页。该逻辑也设计为同时适应这两种情况,无论是否指定页码。
在 if
块之后,有一段代码用于在页面的右下角添加页码。
最后一行添加了页面的大纲条目,该条目将显示在 PDF 查看器(如果支持)的导航窗格中。
转换代码
现在“before-page”事件处理程序已定义,我们可以编写文档转换的代码了:
1// For complete examples and data files, please go to https://github.com/aspose-page/Aspose.Page-for-Java
2// The path to the documents directory.
3String dataDir = Utils.getDataDir();
4String fontDir = dataDir + "necessary_fonts/";
5// Open an XPS Document
6final XpsDocument doc = new XpsDocument(dataDir + "Sample3.xps");
7try {
8 // Create a font
9 final InputStream fontStream = new FileInputStream(fontDir + "arialbd.ttf");
10 try {
11 // Create options for conversion to PDF
12 PdfSaveOptions options = new PdfSaveOptions();
13 // Set the filter for the pages that need conversion
14 options.setPageNumbers(new int[] { 2, 6, 7, 13 });
15 // Add the event handler that will execute right before the conversion of each page
16 options.getBeforePageSavingEventHandlers().add(new NavigationInjector(doc.createFont(fontStream), options.getPageNumbers()));
17 // Save resultant XPS document
18 doc.saveAsPdf(dataDir + "ModifyPageOnConversion_out.pdf", options);
19 } finally {
20 if (fontStream != null)
21 fontStream.close();
22 }
23} finally {
24 if (doc != null)
25 doc.close();
26}
我们打开一个 XPS 文件,然后使用字体数据文件创建一个流对象。接下来,我们实例化 PdfSaveOptions
类并指定需要转换的页码。以下代码通过 getBeforePageSavingEventHandlers()
集合将“before-page”事件处理程序“连接”到转换作业。
现在剩下要做的就是使用文档的 saveAsPdf()
方法运行 PDF 转换。
结论
在本文中,我们介绍了基于事件的编程方法的基本方面,研究了修改 XPS 文档页面的直接方法,并探索了一种更高级的技术,用于在转换过程中对所有输出页面进行重复更改,并以插入导航超链接为例。
有关完整示例,请探索我们的 示例项目。