Модифікації сторінки XPS на основі подій | C++
Що таке подійний підхід у програмуванні?
Подійний підхід у програмуванні — це парадигма, яка обертається навколо концепції подій і обробки подій. У цій моделі потік програми визначається подіями, якими можуть бути дії користувача (наприклад, клацання мишею або натискання клавіш), сповіщення, створені системою, або повідомлення від інших програм. Ось деякі ключові аспекти подійного підходу:
Події: події представляють важливі події в програмі. Це можуть бути взаємодії користувача, зміни в даних або повідомлення з інших частин системи. Наприклад, натискання кнопки або завантаження файлу можуть викликати події.
Слухачі подій: щоб реагувати на події, програмісти використовують прослуховувачі подій (або обробники). Це функції або методи, які визначено для виконання, коли відбувається певна подія. Наприклад, слухач подій може бути налаштований на виконання функції, коли користувач натискає кнопку.
Асинхронне виконання: модель, заснована на подіях, часто підтримує асинхронне програмування, що дозволяє програмам залишатися чуйними в очікуванні подій. Наприклад, веб-програма може продовжувати працювати, очікуючи даних із сервера.
Відокремлення: підхід на основі подій сприяє відокремленню між різними частинами програми. Компоненти можуть спілкуватися за допомогою подій без необхідності знати подробиці реалізації один одного, що робить код більш модульним і простішим в обслуговуванні.
Поширені випадки використання: програмування, кероване подіями, широко використовується в графічних інтерфейсах користувача (GUI), веб-додатках і системах, які потребують взаємодії в реальному часі. Фреймворки та бібліотеки, такі як Node.js, React та багато інших, використовують шаблони, керовані подіями.
Керування станом: у системі, керованій подіями, керування станом може бути вирішальним, оскільки програма може перебувати в різних станах залежно від взаємодії користувача або подій. Належні стратегії управління станом часто застосовуються, щоб забезпечити належну поведінку програми.
Загалом, підхід, заснований на подіях, є потужним способом керування взаємодіями та робочими процесами в програмі, що робить його особливо ефективним для додатків, які вимагають швидкого реагування та взаємодії з користувачем.
Події, які відбуваються під час перетворення документа XPS
Коли вам потрібно внести зміни до певної сторінки документа XPS за допомогою API Aspose.Page, ви зазвичай вибираєте активний документ (якщо у файлі 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 або зображення, процес відбувається сторінка за сторінкою. Коли завдання перетворення готове до обробки наступної сторінки, воно запускає подію «до сторінки». Користувач може визначити обробку таких подій, розширивши клас 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, щоб створити правильні цілі гіперпосилань. Таким чином, конструктор повинен приймати властивість масиву опцій як аргумент. Якщо вказано масив номерів сторінок, ми створюємо їх відсортовану колекцію, водночас уникаючи дублікатів. (До речі, це рішення не зовсім точне. Чи можете ви зрозуміти, що може спричинити неузгодженість у виводі?) Нам також знадобиться об’єкт XpsFont
, який містить дані шрифту для тексту гіперпосилання.
Все це відбувається в перевизначеному методі Handle()
. Аргумент методу — це об’єкт, який містить API модифікації для поточної сторінки, номер документа в пакеті XPS, абсолютний номер сторінки в усіх документах, відносний номер сторінки в поточному документі (який дорівнює попередній номер, якщо в пакеті лише один документ), і номер вихідної сторінки (який дорівнює абсолютному номеру сторінки, коли ми конвертуємо весь пакет).
Логіка наступних двох блоків if
досить проста. Він базується на аналізі аргументу події OutputPageNumber
, щоб опустити деякі посилання, де це доречно: посилання [First]
і [Prev]
буде додано до всіх сторінок виводу, крім першої, тоді як Посилання [Далі]
та [Останнє]
відображатимуться на всіх сторінках, крім останньої. Логіка також адаптована для обох випадків, незалежно від того, чи вказано номери сторінок чи ні.
Після блоків if у нижньому правому куті сторінки є код для додавання номера сторінки.
Останній рядок додає структурний запис сторінки, елемент, який відображатиметься на панелі навігації програми перегляду PDF (якщо підтримується).
Код перетворення
Тепер, коли визначено обробник події «до сторінки», ми можемо написати код, який перетворює документ:
Ми відкриваємо файл XPS, а потім створюємо об’єкт потоку з файлом даних шрифту. Далі ми створюємо екземпляр класу PdfSaveOptions
і вказуємо кількість сторінок, які потрібно конвертувати. У наступному рядку обробник події «до сторінки» «підключається» до завдання перетворення за допомогою параметра колекції «BeforePageSavingEventHandlers».
Все, що залишилося зробити, це запустити перетворення в PDF за допомогою методу SaveAsPdf()
документа.
Висновок
У цій статті ми дослідили ключові моменти подієвого підходу в програмуванні, розглянули прямий метод зміни сторінок документа XPS і навчилися більш досконалої та витонченої техніки для внесення повторюваних змін до всіх вихідних сторінок під час процес перетворення, використовуючи вставку навігаційних гіперпосилань як приклад.
Щоб отримати повні приклади, перегляньте наш Приклад проекту.