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