基于事件的 XPS 页面修改 | C++

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

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

总而言之,基于事件的方法是管理程序内交互和工作流的有效方法,对于需要响应能力和用户交互的应用程序尤其有效。

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

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

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

 1for (uint32_t i = 1; i <= document->DocumentCount(); i++)
 2{
 3    document->SelectActiveDocument(i);
 4    for (uint32_t j = 1; j <= document->PageCount(); j++)
 5    {
 6        document->SelectActivePage(j);
 7        // Your changes ...
 8    }
 9}
10document->SaveAsPdf(u"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>
 4    class NavigationInjector : public Aspose::Page::XPS::Features::EventBasedModifications::BeforePageSavingEventHandler
 5    {
 6        typedef NavigationInjector ThisType;
 7        typedef Aspose::Page::XPS::Features::EventBasedModifications::BeforePageSavingEventHandler BaseType;
 8        
 9        typedef ::System::BaseTypesInfo<BaseType> ThisTypeBaseTypesInfo;
10        RTTI_INFO_DECL();
11        
12    public:
13    
14        NavigationInjector(System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> font, System::ArrayPtr<int32_t> pageNumbers);
15        
16        /// <summary>
17        /// The action itself to be triggered on a before-page event.
18        /// </summary>
19        /// <param name="args">The event arguments.</param>
20        void Handle(System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::BeforeSavingEventArgs<System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::PageAPI>>> args) override;
21        
22    private:
23    
24        System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> _font;
25        System::SharedPtr<System::Collections::Generic::SortedList<int32_t, int32_t>> _pageNumbers;
26        
27    };
 1ModifyXpsPageOnConversion::NavigationInjector::NavigationInjector(System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> font, System::ArrayPtr<int32_t> pageNumbers)
 2{
 3    _font = font;
 4    if (pageNumbers == nullptr)
 5    {
 6        return;
 7    }
 8    
 9    // Turn the page number array into a sorted collection of unique values.
10    _pageNumbers = System::MakeObject<System::Collections::Generic::SortedList<int32_t, int32_t>>();
11    for (int32_t pn : pageNumbers)
12    {
13        _pageNumbers->idx_set(pn, 0);
14    }
15    
16}
17
18void ModifyXpsPageOnConversion::NavigationInjector::Handle(System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::BeforeSavingEventArgs<System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::PageAPI>>> args)
19{
20    System::SharedPtr<PageAPI> api = args->get_ElementAPI();
21    
22    System::SharedPtr<XpsGlyphs> glyphs;
23    // For all pages in the output PDF except the first one...
24    if (args->get_OutputPageNumber() > 1)
25    {
26        // ...insert a hyperlink to the first page...
27        glyphs = api->CreateGlyphs(_font, 15.f, 5.f, api->get_Height() - 10.f, u"[First]");
28        glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
29        glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? 1 : _pageNumbers->get_Keys()->idx_get(0)));
30        api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
31        
32        // ...and to the previous page.
33        glyphs = api->CreateGlyphs(_font, 15.f, 60.f, api->get_Height() - 10.f, u"[Prev]");
34        glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
35        glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? args->get_AbsolutePageNumber() - 1 : _pageNumbers->get_Keys()->idx_get(args->get_OutputPageNumber() - 2)));
36        api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
37    }
38    
39    // For all pages in the output PDF except the last one...
40    if ((_pageNumbers != nullptr && args->get_OutputPageNumber() < _pageNumbers->get_Count()) || (_pageNumbers == nullptr && args->get_OutputPageNumber() < api->get_TotalPageCount()))
41    {
42        // ...insert a hyperlink to the next page...
43        glyphs = api->CreateGlyphs(_font, 15.f, 110.f, api->get_Height() - 10.f, u"[Next]");
44        glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
45        glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? args->get_AbsolutePageNumber() + 1 : _pageNumbers->get_Keys()->idx_get(args->get_OutputPageNumber())));
46        api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
47        
48        // ...and to the last page.
49        glyphs = api->CreateGlyphs(_font, 15.f, 160.f, api->get_Height() - 10.f, u"[Last]");
50        glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
51        glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? api->get_TotalPageCount() : _pageNumbers->get_Keys()->idx_get(_pageNumbers->get_Keys()->get_Count() - 1)));
52        api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
53    }
54    
55    // Insert a page number in the bottom-right corner.
56    glyphs = api->CreateGlyphs(_font, 15.f, api->get_Width() - 20.f, api->get_Height() - 10.f, System::Convert::ToString(args->get_OutputPageNumber()));
57    glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Black()));
58    api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
59    
60    // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
61    api->AddOutlineEntry(System::String::Format(u"Page {0}", args->get_OutputPageNumber()), 1, args->get_AbsolutePageNumber());
62}

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

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

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

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

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

转换代码

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

我们打开一个 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.