Articolo tecnico

Esportare fogli di lavoro Excel in PDF in Delphi senza Office

Per esportare un foglio di lavoro Excel in PDF da Delphi o C++Builder senza Office installato, chiami SaveAsPDF su un foglio di lavoro o su una cartella di lavoro HotXLS. HotXLS è un componente Excel VCL nativo e la sua esportazione da foglio di lavoro a PDF esegue il rendering dell'intervallo utilizzato (used range) del foglio in un file PDF 1.4 autonomo, mappando le larghezze delle colonne di Excel e il testo visualizzato delle celle su pagine A4 con impaginazione multipagina automatica. Nessuna copia di Excel, driver di stampa o DLL externa prende parte al rendering

HotXLS tratta il PDF come un formato di presentazione dei dati, affine ai suoi percorsi di esportazione CSV, TSV e HTML, piuttosto che come un motore di rendering accurato al singolo pixel. L'esportazione riproduce il contenuto e la struttura tabellare: i valori visualizzati nella griglia, le proporzioni delle colonne e le griglie intorno alle celle. Questa impostazione è importante perché definisce sin da subito le aspettative corrette, e il resto di questo articolo descrive esattamente i dettagli di questo confine

Come convertire Excel in PDF in Delphi senza Office?

La via più breve è una singola chiamata. TXLSWorksheet espone SaveAsPDF(FileName) e SaveAsPDF(Stream), e TXLSWorkbook espone i medesimi due overload che reindirizzano al foglio attivo. Ciascuno restituisce un valore Integer, 1 in caso di successo e -1 in caso di errore, permettendoti di gestire il risultato senza dover racchiudere la chiamata in una gestione delle eccezioni personalizzata

uses
  lxHandle;

var
  Book: TXLSWorkbook;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('sales-june.xlsx');
    // Esegue il rendering dell'intervallo utilizzato del foglio attivo direttamente in report.pdf.
    if Book.SaveAsPDF('report.pdf') = 1 then
      Writeln('PDF scritto');
  finally
    Book.Free;
  end;
end;

Quando si chiama SaveAsPDF su un foglio di lavoro, HotXLS esporta l'intervallo UsedRange di quel foglio, ovvero il riquadro di delimitazione di ogni cella popolata. L'overload della cartella di lavoro è una comodità che delega al foglio attivo, quindi un report multifoglio deve scorrere i fogli necessari o selezionare il foglio attivo prima della chiamata. Non esiste una modalità globale per l'intera cartella di lavoro in un unico passaggio che concateni tutte le schede: ogni chiamata esegue il rendering di un singolo foglio o di un singolo intervallo

In che modo HotXLS trasforma un intervallo utilizzato in pagine PDF?

HotXLS percorre l'intervallo utilizzato cella per cella e lo imposta come una griglia impaginata. La geometria delle colonne proviene direttamente da Excel: ogni larghezza di colonna viene convertita dall'unità di misura di Excel in punti tipografici, con un limite minimo per evitare che una colonna si riduca a una linea sottile. Quando le colonne complessivamente risultano più larghe della pagina utilizzabile, HotXLS le ridimensiona uniformemente per adattarle; quando invece rientrano già nelle dimensioni, le lascia alla loro larghezza naturale anziché estenderle lungo la pagina

Le righe scorrono verso il basso della pagina finché la successiva non supera il margine inferiore, momento in cui HotXLS apre una nuova pagina e continua, cosicché un foglio di mille righe viene impaginato autonomamente senza bisogno di gestire i blocchi di interruzione di pagina. Ogni cella stampa il suo FormattedText, ossia la stringa visualizzata dopo l'applicazione del formato numerico, in modo che una data appaia esattamente come mostrata nel foglio e una cella di valuta mantenga il simbolo e i separatori delle migliaia. Il testo che eccede le dimensioni della colonna viene tagliato alla larghezza della cella anziché sconfinare in quella adiacente

Controllo dell'orientamento, dei margini e della dimensione del carattere

Per qualsiasi esigenza che vada oltre il layout predefinito, gestisci direttamente l'esportatore. TXLSPDFExport è la classe che supporta le funzioni helper a riga singola, ed espone tre proprietà: Orientation (xlsPdfPortrait o xlsPdfLandscape, verticale per impostazione predefinita), Margin (in punti, predefinito 40) e FontSize (in punti, predefinito 9). Configurale prima di chiamare SaveAsPDF in modo che l'intero documento le acquisisca

uses
  lxHandle, lxPDF;

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('wide-ledger.xlsx');
    Exporter := TXLSPDFExport.Create;
    try
      Exporter.Orientation := xlsPdfLandscape;  // adatta i fogli larghi alla pagina
      Exporter.Margin := 28;                     // margine di pagina più stretto, in punti
      Exporter.FontSize := 8;                    // righe più dense
      Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

TXLSPDFExport accetta anche un intervallo invece di un intero foglio tramite SaveAsPDF(Range: IXLSRange; ...), utile per esportare un blocco di riepilogo da un foglio che contiene anche calcoli di servizio. Questo overload dell'intervallo è lo stesso su cui si basa internamente l'helper del foglio di lavoro, pertanto il layout, il ridimensionamento e l'impaginazione si comportano allo stesso modo sia che si passi un intero intervallo utilizzato, sia che si passi una selezione specifica

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
  Summary: IXLSRange;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    // Esporta solo il blocco di riepilogo, non le colonne di calcolo adiacenti.
    Summary := Book.Sheets[1].Range['A1', 'F20'];
    Exporter := TXLSPDFExport.Create;
    try
      Exporter.SaveAsPDF(Summary, 'summary.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

Perché HotXLS non incorpora alcun font: il compromesso tra Helvetica e WinAnsi

HotXLS scrive il testo utilizzando il font integrato del PDF Helvetica e la codifica WinAnsiEncoding, una scelta intenzionale a zero dipendenze con un limite reale. Poiché Helvetica is one of the standard 14 fonts ogni lettore PDF conforme già possiede, l'esportatore non incorpora alcun programma di font: il file rimane di piccole dimensioni e si apre ovunque, senza nulla da concedere in licenza o da distribuire insieme ad esso. Il prezzo di questa scelta è il repertorio di caratteri che la pagina può mostrare

WinAnsiEncoding copre il set Windows-1252, pertanto il testo latino, la punteggiatura comune e i consueti accenti dell'Europa occidentale vengono visualizzati correttamente, e HotXLS inserisce una manciata di caratteri tipografici, virgolette inglesi, trattini brevi e lunghi e il simbolo dell'euro nelle rispettive posizioni CP1252. I caratteri al di fuori di questo intervallo, come ideogrammi CJK, caratteri cirillici, greci e arabi, vengono ridotti a un punto interrogativo sulla pagina. Se i tuoi fogli contengono testo non latino, questo esportatore non è lo strumento adatto, ed è preferibile optare per un renderer PDF con styling completo

Dove si ferma l'esportazione da foglio di lavoro a PDF

HotXLS renderizza il contenuto e la struttura, non lo stile visivo completo del foglio. I riempimenti delle celle, gli stili del bordo per bordo, i caratteri e i colori per cella, i grafici e le immagini incorporate esulano da ciò che viene disegnato dall'esportatore; il risultato è la griglia di testo con linee uniformi. Si tratta dello stesso contratto rispettato dagli esportatori HTML e RTF, ed è la scelta ideale per un report o un passaggio di dati in cui sono i numeri a trasmettere il significato, non il tema grafico

Quando l'obiettivo è un documento con stile e conforme al brand, la prassi abituale consiste nell'assemblare prima i numeri in un modello di foglio di calcolo, argomento trattato in dettaglio nel flusso di lavoro per la generazione di report basata su modelli. E poiché nulla di tutto ciò tocca COM o un'istanza di Excel in esecuzione, la pipeline si adatta allo stesso modello di automazione senza Office utilizzato globalmente da HotXLS: puro Pascal, distribuibile su un server headless, senza licenze di interop da gestire

Il PDF autonomo, byte per byte

HotXLS compila la struttura del file PDF a mano e calcola la sua tabella di riferimento incrociato a partire da offset di byte esatti, ed è questo il motivo per cui l'output si apre in ogni lettore. Durante la serializzazione di ciascun oggetto, HotXLS registra l'offset iniziale di quell'oggetto prima di aggiungerne i byte, quindi fa avanzare la posizione corrente in base alla lunghezza appena scritta, in modo che la tabella xref si posizioni precisamente su ogni oggetto e startxref contrassegni il punto di inizio di tale tabella. Un lettore che rileva questi offset errati anche di un solo byte rifiuta l'intero file, il che rende l'offset calcolato autonomamente il contratto fondamentale dell'esportatore

Questo contratto comporta una rigida conseguenza che vale la pena conoscere. Il nodo Pages viene scritto per primo come oggetto 1, ma il suo elenco di pagine figlie non è noto fino a quando non sono state emesse tutte le pagine, pertanto HotXLS lo riserva come segnaposto e introduce le pagine figlie definitive e il conteggio prima dell'esecuzione del passaggio dell'offset, mai dopo. Una volta misurati i byte di un oggetto per l'xref, questi vengono congelati: la modifica di un singolo byte in un secondo momento sposterebbe ogni offset successivo e corromperebbe la tabella. Si tratta di una piccola accortezza che garantisce un PDF 1.4 conforme agli standard senza alcuna libreria sottostante

I metodi SaveAsPDF e la classe TXLSPDFExport mostrati qui sono forniti con HotXLS Delphi Excel Component, insieme agli esportatori CSV, HTML e RTF e alle API complete per i fogli di lavoro per Delphi e C++Builder