Modifica di una pagina XPS in base agli eventi | Java
Comprendere l’approccio basato sugli eventi nella programmazione
L’approccio basato sugli eventi nella programmazione è un paradigma incentrato sugli eventi e sulla loro gestione. In questo modello, il flusso del programma è dettato dagli eventi, che possono includere azioni dell’utente (come clic del mouse o pressione di tasti), notifiche generate dal sistema o messaggi provenienti da altre applicazioni. Di seguito sono riportati alcuni aspetti chiave dell’approccio basato sugli eventi:
Eventi: Gli eventi indicano eventi importanti all’interno di un programma. Possono comprendere interazioni dell’utente, modifiche dei dati o messaggi provenienti da diversi componenti di un sistema. Ad esempio, il clic di un pulsante o il caricamento di un file possono attivare eventi.
Listener di eventi: Per gestire gli eventi, i programmatori utilizzano i listener di eventi (o gestori). Si tratta di funzioni o metodi progettati per essere eseguiti al verificarsi di un determinato evento. Ad esempio, un listener di eventi può essere configurato per eseguire una funzione quando un utente fa clic su un pulsante.
Esecuzione asincrona: Il modello basato sugli eventi in genere facilita la programmazione asincrona, consentendo ai programmi di mantenere la reattività in attesa degli eventi. Ad esempio, un’applicazione web può continuare a funzionare mentre attende dati da un server.
Disaccoppiamento: L’approccio basato sugli eventi incoraggia il disaccoppiamento tra i vari componenti di un programma. Questi componenti possono interagire tramite eventi senza richiedere la conoscenza reciproca dei dettagli di implementazione, con conseguente creazione di codice più modulare e manutenibile.
Casi d’uso comuni: La programmazione basata sugli eventi è comunemente impiegata in interfacce utente grafiche (GUI), applicazioni web e sistemi che richiedono interazioni in tempo reale. Framework e librerie come Node.js, React e molti altri sfruttano pattern basati sugli eventi.
Gestione dello stato: In un sistema basato sugli eventi, una gestione efficace dello stato è essenziale, poiché l’applicazione può presentarsi in diversi stati a seconda delle interazioni dell’utente o degli eventi. In genere, vengono implementate strategie di gestione dello stato appropriate per garantire che l’applicazione funzioni come previsto.
Nel complesso, l’approccio basato sugli eventi è un metodo efficace per gestire le interazioni e i flussi di lavoro all’interno di un programma, rendendolo particolarmente adatto per applicazioni che richiedono reattività e interazioni con l’utente.
Conversione ed eventi del documento XPS
Quando è necessario modificare una pagina specifica di un documento XPS utilizzando l’API Aspose.Page, in genere si seleziona il documento attivo (se il file XPS contiene più documenti), si seleziona la pagina attiva e quindi si applicano le modifiche.
Ora, supponiamo di dover implementare modifiche ripetute su tutte le pagine di un file XPS e successivamente convertire il risultato in formato PDF o immagine. Esempi di tali modifiche potrebbero includere l’aggiunta di una filigrana alle pagine o l’inserimento di collegamenti ipertestuali di navigazione. Il metodo più semplice per apportare tali modifiche consiste nell’attraversare i documenti nel pacchetto XPS, le pagine del documento attivo corrente e infine applicare le modifiche. Pertanto, il codice per eseguire questa operazione sarebbe il seguente:
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 è necessario apportare anche modifiche irregolari prima di applicare quelle ricorrenti, questo approccio potrebbe generare confusione o richiedere un’eccessiva consultazione di documenti e pagine. Inoltre, questi cicli potrebbero apparire piuttosto macchinosi.
Quando si converte un documento XPS in PDF o un’immagine, il processo avviene una pagina alla volta. Mentre il processo di conversione si prepara a elaborare la pagina successiva, attiva un evento “before-page”. L’utente può definire il comportamento (gestione degli eventi) per tali eventi estendendo la classe BeforePageSavingEventHandler, sfruttando così alcuni dei vantaggi discussi nella sezione introduttiva di questo articolo.
Esempio di aggiunta di collegamenti ipertestuali di navigazione
In questa sezione, presenteremo un esempio che prevede l’uso di collegamenti ipertestuali di navigazione. Per rendere il compito un po’ più complicato, convertiremo solo un sottoinsieme di tutte le pagine in PDF, come definito dal metodo PdfSaveOptions.setPageNumbers()
.
La classe gestore eventi
Di seguito è riportata l’estensione della 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}
La classe gestore deve conoscere le pagine che intendiamo salvare in PDF per stabilire le destinazioni corrette del collegamento ipertestuale. Di conseguenza, il costruttore dovrebbe accettare la proprietà array getPageNumbers()
delle opzioni come argomento. Se viene fornito l’array dei numeri di pagina, ne creiamo una raccolta ordinata, escludendo allo stesso tempo i duplicati. Inoltre, la classe necessita di un oggetto XpsFont
che contenga i dati del font per il testo del collegamento ipertestuale.
Il metodo handle()
sovrascritto è dove avviene tutto. L’argomento del metodo è un oggetto che contiene l’API di modifica per la pagina corrente, il numero del documento all’interno del pacchetto XPS, il numero di pagina assoluto di tutti i documenti, il numero di pagina relativo all’interno del documento corrente (che è uguale al numero precedente se il pacchetto contiene un solo documento) e il numero di pagina di output (che è uguale al numero di pagina assoluto quando convertiamo l’intero pacchetto).
La logica dei due blocchi if
seguenti è piuttosto semplice. Analizza l’argomento dell’evento getOutputPageNumber()
per omettere alcuni link, ove appropriato: i link [First]
e [Prev]
non verranno aggiunti alla prima pagina, mentre i link [Next]
e [Last]
non appariranno nell’ultima pagina. La logica è inoltre progettata per gestire entrambi gli scenari, indipendentemente dal fatto che i numeri di pagina siano specificati o meno.
Dopo i blocchi if
, c’è del codice che aggiunge un numero di pagina nell’angolo in basso a destra della pagina.
L’ultima riga aggiunge la voce di struttura della pagina, che è l’elemento che verrà visualizzato nel riquadro di navigazione di un visualizzatore PDF (se supportato).
Codice per la conversione
Ora che il gestore dell’evento “before-page” è definito, possiamo scrivere il codice per la conversione del 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}
Apriamo un file XPS e creiamo un oggetto stream con il file di dati del font. Successivamente, istanziamo la classe PdfSaveOptions
e specifichiamo i numeri di pagina da convertire. La riga seguente “collega” il gestore dell’evento “before-page” al processo di conversione tramite la collection getBeforePageSavingEventHandlers()
.
Ora non ci resta che eseguire la conversione in PDF utilizzando il metodo saveAsPdf()
del documento.
Conclusione
In questo articolo abbiamo trattato gli aspetti fondamentali dell’approccio basato su eventi nella programmazione, esaminato il metodo diretto per modificare le pagine di un documento XPS e analizzato una tecnica più avanzata per apportare modifiche ripetute a tutte le pagine di output durante il processo di conversione, utilizzando come esempio l’inserimento di collegamenti ipertestuali di navigazione.
Per gli esempi completi, esplora il nostro Progetto di esempio.