Articol tehnic

Exportarea foilor de calcul Excel în PDF în Delphi fără Office

Pentru a exporta o foaie de calcul Excel în PDF din Delphi sau C++Builder fără Office instalat, apelați SaveAsPDF pe o foaie de calcul sau un registru de calcul HotXLS. HotXLS este o componentă nativă VCL Excel, iar exportul foii de calcul în PDF randează intervalul utilizat (used range) al foii într-un fișier PDF 1.4 autonom, mapând lățimile coloanelor Excel și textul afișat în celule pe pagini A4 cu paginare automată pe mai multe pagini. În procesul de randare nu este implicată nicio copie a Excel, niciun driver de imprimantă și nicio bibliotecă DLL externă

HotXLS tratează formatul PDF ca pe un format de prezentare a datelor, o variantă similară cu căile sale de export CSV, TSV și HTML, mai degrabă decât ca pe un motor de randare cu precizie la nivel de pixel. Exportul reproduce conținutul tabelar și aspectul: valorile pe care le vedeți în grilă, proporțiile coloanelor și liniile de grilă (gridlines) din jurul celulelor. Această abordare este importantă deoarece stabilește o așteptare corectă de la început, iar restul acestui articol detaliază limitele specifice ale acestei funcții

Cum se convertește Excel în PDF în Delphi fără Office?

Cea mai scurtă cale este un singur apel. TXLSWorksheet expune metodele SaveAsPDF(FileName) și SaveAsPDF(Stream), iar TXLSWorkbook expune aceleași două supraîncărcări (overloads) care redirecționează comanda către foaia activă. Fiecare returnează o valoare de tip Integer, 1 în caz de succes și -1 în caz de eșec, astfel încât să puteți lua decizii pe baza rezultatului fără a fi nevoie să includeți apelul în structuri proprii de tratare a excepțiilor

uses
  lxHandle;

var
  Book: TXLSWorkbook;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('sales-june.xlsx');
    // Render the active sheet's used range straight to report.pdf.
    if Book.SaveAsPDF('report.pdf') = 1 then
      Writeln('PDF written');
  finally
    Book.Free;
  end;
end;

Când apelați SaveAsPDF pe o foaie de calcul, HotXLS exportă intervalul UsedRange al acelei foi, adică zona de delimitare a fiecărei celule populate. Supraîncărcarea de la nivelul registrului de calcul este o facilitate care deleagă sarcina către foaia activă, așa că pentru un raport cu mai multe foi puteți parcurge foile necesare într-o buclă sau puteți selecta foaia activă înainte de apel. Nu există o modalitate de export a întregului registru de calcul într-un singur pas care să concateneze toate foile: fiecare apel randează o singură foaie sau un singur interval

Cum transformă HotXLS un interval utilizat în pagini PDF?

HotXLS parcurge intervalul utilizat celulă cu celulă și îl organizează ca pe o grilă paginată. Geometria coloanelor este preluată direct din Excel: lățimea fiecărei coloane este convertită din unitatea de lățime Excel în puncte tipografice, existând o limită minimă pentru ca nicio coloană să nu se reducă la o linie fină. Când coloanele sunt cumulat mai late decât pagina utilizabilă, HotXLS le scalează proporțional pentru a se încadra; când acestea se încadrează deja, le lasă la lățimea lor naturală, în loc să le extindă pe lățimea paginii

Rândurile curg apoi pe pagină până când următorul ar depăși marja de jos, moment în care HotXLS deschide o pagină nouă și continuă randarea, astfel încât o foaie de calcul cu o mie de rânduri se paginează singură, fără a fi nevoie să gestionați manual marcajele de sfârșit de pagină. Fiecare celulă tipărește textul său FormattedText, adică șirul afișat după aplicarea formatului numeric, astfel încât o dată apare exact așa cum este pe foaie, iar o celulă monetară își păstrează separatorii de mii și simbolul. Textul care depășește lățimea coloanei este trunchiat la dimensiunea celulei, în loc să se suprapună peste celula vecină

Controlul orientării, marjelor și dimensiunii fontului

Pentru orice personalizare dincolo de aspectul implicit, controlați direct exportatorul. TXLSPDFExport este clasa aflată în spatele metodelor ajutătoare, expunând trei proprietăți: Orientation (cu valorile xlsPdfPortrait sau xlsPdfLandscape, fiind portrait în mod implicit), Margin (în puncte, implicit 40) și FontSize (în puncte, implicit 9). Setați-le înainte de a apela SaveAsPDF, iar întregul document le va prelua

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;  // fit wide sheets on the page
      Exporter.Margin := 28;                     // tighter page margin, in points
      Exporter.FontSize := 8;                    // denser rows
      Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

TXLSPDFExport acceptă, de asemenea, un interval în loc de o foaie completă prin SaveAsPDF(Range: IXLSRange; ...), mod utilizat pentru a exporta un bloc de sinteză dintr-o foaie care conține și calcule temporare. Această supraîncărcare de interval este aceeași pe care o folosește intern metoda ajutătoare a foii de calcul, astfel încât aspectul, scalarea și paginarea se comportă identic, indiferent dacă transmiteți un interval complet sau o selecție personalizată

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
  Summary: IXLSRange;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    // Export only the summary block, not the scratch columns beside it.
    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;

De ce nu încorporează HotXLS niciun font: compromisul între Helvetica și WinAnsi

HotXLS scrie textul folosind fontul încorporat Helvetica al PDF-ului și codificarea WinAnsiEncoding, o alegere deliberată pentru a elimina dependențele, care vine însă cu o limitare. Deoarece Helvetica este unul dintre cele 14 fonturi standard pe care orice cititor conform de PDF le deține deja, exportatorul nu încorporează deloc programul de font: fișierul rămâne mic și se deschide oriunde, fără a fi nevoie de licențiere sau de livrarea altor fișiere suplimentare. Prețul acestei decizii este repertoriul de caractere pe care pagina le poate afișa

Codificarea WinAnsiEncoding acoperă setul Windows-1252, astfel încât textul latin, punctuația comună și accentele vest-europene obișnuite se randează corect, iar HotXLS include câteva caractere tipografice, ghilimele rotunde, cratime en și em și simbolul euro în pozițiile lor CP1252. Caracterele din afara acestui interval, ideogramele CJK, caracterele chirilice, grecești și arabe devin semne de întrebare pe pagină. Dacă foile dvs. conțin text non-latin, acest exportator nu este instrumentul potrivit, fiind necesar un motor de randare PDF complet

Unde se oprește exportul foii de calcul în PDF

HotXLS randează conținutul și structura, nu stilul vizual complet al foii. Umplerile de celule, stilurile de margini pe fiecare latură, fonturile și culorile pe fiecare celulă, diagramele și imaginile încorporate sunt în afara a ceea ce desenează exportatorul; ceea ce obțineți este grila de text cu linii uniforme. Acesta este același comportament pe care îl respectă exportatorii în HTML și RTF și este cel potrivit pentru un raport sau un transfer de date unde cifrele poartă semnificația, nu stilul grafic

Când scopul este obținerea unui document stilizat, conform cu identitatea de brand, modelul de obicei este asamblarea mai întâi a cifrelor într-un șablon de foaie de calcul, proces acoperit în detaliu în fluxul de generare a rapoartelor pe bază de șablon. Și deoarece nimic din toate acestea nu implică COM sau o instanță activă de Excel, fluxul se încadrează în același model de automatizare fără Office pe care HotXLS îl folosește peste tot: cod Pascal pur, ce poate fi implementat pe un server headless, fără a fi nevoie de licențiere sau monitorizare

Fișierul PDF autonom, octet cu octet

HotXLS construiește manual structura fișierului PDF și își calculează tabelul de referințe încrucișate pe baza deplasărilor (offsets) exacte de octeți, acesta fiind motivul pentru care fișierul rezultat se deschide în orice cititor. Pe măsură ce serializează fiecare obiect, HotXLS înregistrează offset-ul de pornire al acelui obiect înainte de a adăuga octeții săi, apoi avansează poziția curentă cu lungimea pe care tocmai a scris-o, astfel încât tabelul xref indică precis fiecare obiect, iar startxref marchează unde începe acel tabel. Un cititor care găsește aceste offset-uri decalate chiar și cu un singur octet va respinge întregul fișier, ceea ce face ca offset-ul autocalculat să fie contractul de bază al exportatorului

Acest contract vine cu o consecință strictă ce merită cunoscută. Nodul Pages este scris primul ca obiectul 1, dar lista sa de pagini copii nu este cunoscută până când fiecare pagină nu a fost emisă, așa că HotXLS îl rezervă ca un substituent și adaugă elementele și contorul final înainte de rularea trecerii de offset-uri, niciodată după. Odată ce octeții unui obiect sunt măsurați pentru xref, aceștia sunt blocați: modificarea unui singur octet ulterior ar decala fiecare offset următor și ar corupe tabelul. Este o disciplină simplă care garantează un PDF 1.4 conform cu standardele, fără nicio bibliotecă auxiliară

Metodele SaveAsPDF și clasa TXLSPDFExport prezentate aici sunt livrate cu HotXLS Delphi Excel Component, alături de exportatorii CSV, HTML și RTF și de API-ul complet pentru foile de calcul în Delphi și C++Builder