Изменение XPS-страницы событий | Java
Понимание событийного подхода в программировании
Событийный подход в программировании — это парадигма, ориентированная на события и их обработку. В этой модели ход программы определяется событиями, которые могут включать действия пользователя (например, щелчки мыши или нажатия клавиш), уведомления, генерируемые системой, или сообщения от других приложений. Ниже приведены некоторые ключевые аспекты событийно-ориентированного подхода:
События: События обозначают важные события в программе. Они могут включать взаимодействие с пользователем, изменения данных или сообщения от различных компонентов системы. Например, нажатие кнопки или загрузка файла могут вызвать события.
Прослушиватели событий. Для обработки событий программисты используют прослушиватели событий (или обработчики). Это функции или методы, предназначенные для запуска при возникновении определенного события. Например, прослушиватель событий можно настроить на выполнение функции, когда пользователь нажимает кнопку.
Асинхронное выполнение. Модель на основе событий обычно облегчает асинхронное программирование, позволяя программам сохранять оперативность во время ожидания событий. Например, веб-приложение может продолжать работать, ожидая данных от сервера.
Развязка. Подход, основанный на событиях, способствует разделению различных компонентов программы. Эти компоненты могут взаимодействовать посредством событий, не требуя знания деталей реализации друг друга, что приводит к созданию более модульного и удобного в сопровождении кода.
Распространенные случаи использования. Программирование, управляемое событиями, обычно применяется в графических интерфейсах пользователя (GUI), веб-приложениях и системах, требующих взаимодействия в реальном времени. Платформы и библиотеки, такие как Node.js, React и многие другие, используют шаблоны, управляемые событиями.
Управление состоянием. В системе, управляемой событиями, крайне важно эффективное управление состоянием, поскольку приложение может находиться в различных состояниях в зависимости от действий пользователя или событий. Соответствующие стратегии управления состоянием обычно реализуются для обеспечения правильной работы приложения.
В целом, подход, основанный на событиях, является эффективным методом управления взаимодействиями и рабочими процессами внутри программы, что делает его особенно подходящим для приложений, требующих оперативности и взаимодействия с пользователем.
Преобразование документов XPS и события
Когда вам нужно изменить определенную страницу документа XPS с помощью API Aspose.Page, вы обычно выбираете активный документ (если в файле 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 или изображение, процесс происходит по одной странице за раз. Когда задание преобразования готовится к обработке следующей страницы, оно запускает событие «до страницы». Пользователь может определить поведение (обработку событий) для таких событий, расширив класс 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, чтобы установить правильные цели гиперссылок. Следовательно, конструктор должен принимать свойство массива options getPageNumbers() в качестве аргумента. Если предоставлен массив номеров страниц, мы создаем их отсортированную коллекцию, одновременно исключая дубликаты. Кроме того, классу нужен объект XpsFont, содержащий данные шрифта для текста гиперссылки.
Все это происходит в переопределенном методе handle(). Аргументом метода является объект, который содержит API модификации для текущей страницы, номер документа в пакете XPS, абсолютный номер страницы во всех документах, относительный номер страницы в текущем документе (который равен предыдущий номер, если в пакете только один документ) и номер выходной страницы (который равен абсолютному номеру страницы при преобразовании всего пакета).
Логика следующих двух блоков if довольно проста. Он анализирует аргумент события getOutputPageNumber(), чтобы опустить некоторые ссылки, где это необходимо: ссылки [First] и [Prev] не будут добавлены на первую страницу, а [Next] и Ссылки [Last] не будут отображаться на последней странице. Логика также предназначена для реализации обоих сценариев, независимо от того, указаны номера страниц или нет.
После блоков if идет код, который добавляет номер страницы в правом нижнем углу страницы.
Последняя строка добавляет запись структуры страницы, которая представляет собой элемент, который будет отображаться в области навигации средства просмотра PDF (если поддерживается).
Код для конвертации
Теперь, когда обработчик события «перед страницей» определен, мы можем написать код для преобразования документа:
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 и указываем номера страниц, которые нам нужно преобразовать. Следующая строка «подключает» обработчик событий «before-page» к заданию преобразования через коллекцию getBeforePageSavingEventHandlers().
Все, что осталось сделать, это запустить преобразование в PDF, используя метод saveAsPdf() документа.
Заключение
В этой статье мы рассмотрели фундаментальные аспекты событийно-ориентированного подхода в программировании, рассмотрели прямой метод изменения страниц документа XPS и изучили более продвинутый метод внесения повторяющихся изменений во все выходные страницы в процессе преобразования. , на примере вставки навигационных гиперссылок.
Полные примеры можно найти в нашем Пример проекта.