Modifiche basate su eventi nella pagina XPS | C++

Cos’è l’approccio basato sugli eventi nella programmazione?

L’approccio basato sugli eventi nella programmazione è un paradigma che ruota attorno al concetto di eventi e alla loro gestione. In questo modello, il flusso del programma è determinato dagli eventi, che possono essere azioni dell’utente (come clic del mouse o pressione di tasti), notifiche generate dal sistema o messaggi provenienti da altre applicazioni. Ecco alcuni aspetti chiave dell’approccio basato sugli eventi:

Nel complesso, l’approccio basato sugli eventi è un modo efficace per gestire le interazioni e i flussi di lavoro all’interno di un programma, rendendolo particolarmente efficace per le applicazioni che richiedono reattività e interazione con l’utente.

Eventi che si verificano durante la conversione di un documento XPS

Quando è necessario apportare modifiche a 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 apportano le modifiche.

Supponiamo ora di dover apportare modifiche ripetute a tutte le pagine di un file XPS e quindi convertire il risultato in PDF o in un formato immagine. Alcuni esempi di tali modifiche includono l’inserimento di una filigrana sulle pagine o l’aggiunta di collegamenti ipertestuali di navigazione. Il modo diretto 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 (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);

Se è necessario apportare modifiche irregolari prima di quelle ricorrenti, questo approccio potrebbe generare confusione o richiedere un’eccessiva esplorazione di documenti e pagine, per non parlare del fatto che questi cicli potrebbero apparire un po’ macchinosi.

Quando si converte un documento XPS in PDF o in un’immagine, il processo avviene pagina per pagina. Quando il processo di conversione è pronto per elaborare la pagina successiva, attiva un evento “before-page”. L’utente può definire la gestione di tali eventi estendendo la classe BeforePageSavingEventHandler, sfruttando così alcuni dei vantaggi descritti nella sezione introduttiva di questo articolo.

Esempio di aggiunta di collegamenti ipertestuali di navigazione

Qui forniremo un esempio relativo al caso dei collegamenti ipertestuali di navigazione. Per rendere il compito un po’ più complicato, convertiremo solo un sottoinsieme di tutte le pagine in PDF, come specificato dalla proprietà PdfSaveOptions.PageNumbers.

La classe gestore eventi

Di seguito è riportata l’estensione della classe 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}

La classe gestore deve conoscere le pagine che vogliamo salvare in PDF per creare le destinazioni corrette per i collegamenti ipertestuali. Pertanto, il costruttore dovrebbe accettare la proprietà array delle opzioni come argomento. Se viene specificato l’array dei numeri di pagina, ne creiamo una raccolta ordinata, evitando allo stesso tempo i duplicati. (A proposito, questa soluzione non è del tutto accurata. Riesci a capire cosa potrebbe causare incoerenza nell’output?) Avremo anche bisogno di un oggetto XpsFont contenente 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 in tutti i documenti, il numero di pagina relativo all’interno del documento corrente (che è uguale al numero precedente nel caso di un solo documento nel pacchetto) 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. Si basa sull’analisi dell’argomento dell’evento OutputPageNumber per omettere alcuni link ove appropriato: i link [First] e [Prev] verranno aggiunti a tutte le pagine di output tranne la prima, mentre i link [Next] e [Last] appariranno su tutte le pagine tranne l’ultima. La logica è inoltre adattata per entrambi i casi, indipendentemente dal fatto che i numeri di pagina siano specificati o meno.

Dopo i blocchi if, c’è il codice per aggiungere un numero di pagina nell’angolo in basso a destra della pagina.

L’ultima riga aggiunge la voce di struttura della pagina, l’elemento che verrà visualizzato nel riquadro di navigazione di un visualizzatore PDF (se supportato).

Il codice di conversione

Ora che il gestore dell’evento “before-page” è definito, possiamo scrivere il codice che converte il documento:

 1    // ExStart:ModifyingXpsPageOnConversion
 2    // The path to the documents directory.
 3    System::String dataDir = RunExamples::GetDataDir_WorkingWithPages();
 4    // Open an XPS document
 5    {
 6        System::SharedPtr<XpsDocument> doc = System::MakeObject<XpsDocument>(dataDir + u"Sample3.xps");
 7        // Clearing resources under 'using' statement
 8        System::Details::DisposeGuard<1> __dispose_guard_1({ doc});
 9        // ------------------------------------------
10        
11        try{
12            System::SharedPtr<System::IO::Stream> fontStream = System::IO::File::OpenRead(dataDir + u"arialbd.ttf");
13            // Clearing resources under 'using' statement
14            System::Details::DisposeGuard<1> __dispose_guard_0({ fontStream});
15            // ------------------------------------------
16            
17            try
18            {
19                // Create options for conversion to PDF
20                System::SharedPtr<PdfSaveOptions> options = System::MakeObject<PdfSaveOptions>();
21                // Set the filter for the pages that need conversion
22                options->set_PageNumbers(System::MakeArray<int32_t>({2, 6, 7, 13}));
23                // Add the event handler that will execute right before the conversion of each page
24                options->get_BeforePageSavingEventHandlers()->Add(System::MakeObject<ModifyXpsPageOnConversion::NavigationInjector>(doc->CreateFont(fontStream), options->get_PageNumbers()));
25                // Save resultant XPS document
26                doc->SaveAsPdf(dataDir + u"ModifyPageOnConversion_out.pdf", options);
27            }
28            catch(...)
29            {
30                __dispose_guard_0.SetCurrentException(std::current_exception());
31            }
32        }
33        catch(...)
34        {
35            __dispose_guard_1.SetCurrentException(std::current_exception());
36        }
37    }
38    // ExEnd:ModifyingXpsPageOnConversion

Apriamo un file XPS e istanziamo un oggetto stream con il file di dati del font. Successivamente, creiamo un’istanza della classe PdfSaveOptions e specifichiamo il numero di pagine da convertire. La riga successiva è quella in cui il gestore dell’evento “before-page” viene “connesso” al processo di conversione tramite l’opzione di raccolta BeforePageSavingEventHandlers.

Non ci resta che eseguire la conversione in PDF utilizzando il metodo SaveAsPdf() del documento.

Conclusione

In questo articolo abbiamo esplorato i punti chiave dell’approccio basato su eventi nella programmazione, esaminato il metodo diretto per modificare le pagine di un documento XPS e appreso una tecnica più avanzata e sofisticata per apportare modifiche ripetute a tutte le pagine di output durante il processo di conversione, utilizzando l’inserimento di collegamenti ipertestuali di navigazione come esempio.

Per gli esempi completi, esplora il nostro Progetto di esempio.

Have any questions about Aspose.Page?



Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.