Modificar uma página XPS em eventos | Java
Compreender a abordagem baseada em eventos na programação
A abordagem baseada em eventos na programação é um paradigma focado nos eventos e no seu tratamento. Neste modelo, o fluxo do programa é ditado por eventos, que podem incluir ações do utilizador (como cliques do rato ou pressionamentos de teclas), notificações geradas pelo sistema ou mensagens de outras aplicações. Abaixo estão alguns aspetos-chave da abordagem baseada em eventos:
Eventos: Os eventos significam ocorrências importantes dentro de um programa. Podem abranger interações do utilizador, alterações de dados ou mensagens de diferentes componentes de um sistema. Por exemplo, um clique num botão ou o carregamento de um ficheiro podem desencadear eventos.
Ouvintes de eventos: Para tratar eventos, os programadores empregam ouvintes de eventos (ou manipuladores). São funções ou métodos designados para serem executados quando ocorre um evento específico. Por exemplo, um ouvinte de eventos pode ser configurado para executar uma função quando um utilizador clica num botão.
Execução Assíncrona: O modelo baseado em eventos facilita normalmente a programação assíncrona, permitindo que os programas mantenham a capacidade de resposta enquanto aguardam por eventos. Por exemplo, uma aplicação web pode continuar a funcionar enquanto aguarda dados de um servidor.
Desacoplamento: A abordagem baseada em eventos encoraja o desacoplamento entre os vários componentes de um programa. Estes componentes podem interagir através de eventos sem a necessidade de conhecimento dos detalhes de implementação uns dos outros, resultando num código mais modular e sustentável.
Casos de Uso Comuns: A programação orientada a eventos é comummente empregue em interfaces gráficas de utilizador (GUIs), aplicações web e sistemas que requerem interações em tempo real. Frameworks e bibliotecas como Node.js, React e muitas outras utilizam standards orientados a eventos.
Gestão de Estado: Num sistema orientado a eventos, a gestão eficaz de estado é essencial, uma vez que a aplicação pode existir em vários estados dependendo das interações do utilizador ou dos eventos. Estratégias de gestão de estado adequadas são normalmente implementadas para garantir que a aplicação funciona conforme o esperado.
De um modo geral, a abordagem baseada em eventos é um método eficaz para gerir interações e fluxos de trabalho dentro de um programa, tornando-a especialmente adequada para aplicações que requerem capacidade de resposta e interações do utilizador.
Conversão e eventos de documentos XPS
Quando necessita de modificar uma página específica de um documento XPS utilizando a API Aspose.Page, normalmente seleciona o documento ativo (se existirem vários documentos no ficheiro XPS), seleciona a página ativa e aplica as alterações.
Agora, digamos que precisa de implementar alterações repetidas em todas as páginas de um ficheiro XPS e, posteriormente, converter o resultado para PDF ou um formato de imagem. Exemplos destas alterações podem incluir a adição de uma marca de água às páginas ou a inserção de hiperligações de navegação. O método simples para fazer estas alterações implica percorrer os documentos no pacote XPS, percorrer as páginas do documento activo actual e, finalmente, aplicar as alterações. Assim sendo, o código para realizar esta tarefa seria o seguinte:
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);
Se também precisar de fazer algumas alterações irregulares antes de aplicar as repetidas, esta abordagem pode causar confusão ou percorrer excessivamente documentos e páginas. Além disso, estes loops podem parecer algo trabalhosos.
Ao converter um documento XPS em PDF ou imagem, o processo ocorre uma página de cada vez. À medida que a tarefa de conversão se prepara para processar a página seguinte, desencadeia um evento “before-page”. O utilizador pode definir o comportamento (manipulação de eventos) nestes eventos estendendo a classe BeforePageSavingEventHandler, aproveitando assim algumas das vantagens discutidas na secção introdutória deste artigo.
Exemplo de adição de hiperligações de navegação
Nesta secção, apresentaremos um exemplo que envolve hiperligações de navegação. E para complicar um pouco a tarefa, apenas converteremos um subconjunto de todas as páginas para PDF, tal como definido pelo método PdfSaveOptions.setPageNumbers()
.
A classe manipuladora de eventos
Abaixo está a extensão da classe 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}
A classe manipuladora necessita de estar ciente das páginas que pretendemos guardar como PDF para estabelecer os alvos corretos da hiperligação. Consequentemente, o construtor deve receber como argumento a propriedade getPageNumbers()
do array options. Se a matriz de números de página for fornecida, criamos uma coleção ordenada dos mesmos, excluindo os duplicados ao mesmo tempo. Além disso, a classe necessita de um objeto XpsFont
que contém os dados da fonte para o texto da hiperligação.
O método handle()
sobrescrito é onde tudo acontece. O argumento do método é um objeto que contém a API de modificação para a página atual, o número do documento dentro do pacote XPS, o número absoluto da página em todos os documentos, o número relativo da página dentro do documento atual (que é igual ao número anterior se existir apenas um documento no pacote) e o número da página de saída (que é igual ao número absoluto da página quando convertemos o pacote inteiro).
A lógica dos dois blocos if
seguintes é bastante simples. Analisa o argumento do evento getOutputPageNumber()
para omitir alguns dos links quando apropriado: os links [First]
e [Prev]
não serão adicionados à primeira página, enquanto os links [Next]
e [Last]
não aparecerão na última página. A lógica também foi concebida para acomodar ambos os cenários, independentemente de os números de página serem ou não especificados.
Após os blocos if
, existe um código que adiciona um número de página no canto inferior direito da página.
A última linha adiciona a entrada de estrutura de tópicos da página, que é o item que será apresentado no painel de navegação de um visualizador de PDF (se compatível).
Código para conversão
Agora que o manipulador de eventos “before-page” está definido, podemos escrever o código para a conversão do documento:
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}
Abrimos um ficheiro XPS e criamos um objeto de fluxo com o ficheiro de dados da fonte. De seguida, instanciamos a classe PdfSaveOptions
e especificamos os números de página que precisamos de converter. A linha seguinte “liga” o manipulador de eventos “before-page” à tarefa de conversão através da coleção getBeforePageSavingEventHandlers()
.
Agora, basta executar a conversão para PDF utilizando o método saveAsPdf()
do documento.
Conclusão
Neste artigo, abordamos os aspetos fundamentais da abordagem baseada em eventos em programação, examinamos o método direto para modificar páginas de um documento XPS e exploramos uma técnica mais avançada para fazer alterações repetidas em todas as páginas de saída durante o processo de conversão, utilizando a inserção de hiperligações de navegação como exemplo.
Para os exemplos completos, explore o nosso projeto de exemplo.