Τεχνικό Άρθρο

Εξαγωγή Φύλλων Εργασίας Excel σε PDF στο Delphi Χωρίς το Office

Για να εξαγάγετε ένα φύλλο εργασίας Excel σε PDF από το Delphi ή το C++Builder χωρίς να έχετε εγκατεστημένο το Office, καλέστε το SaveAsPDF σε ένα φύλλο εργασίας ή βιβλίο εργασίας του HotXLS. Το HotXLS είναι ένα εγγενές στοιχείο VCL Excel, και η εξαγωγή του από φύλλο εργασίας σε PDF αποδίδει το χρησιμοποιούμενο εύρος (used range) του φύλλου σε ένα αυτόνομο αρχείο PDF 1.4, αντιστοιχίζοντας τα πλάτη των στηλών του Excel και το κείμενο εμφάνισης των κελιών σε σελίδες A4 με αυτόματη σελιδοποίηση πολλαπλών σελίδων. Κανένα αντίγραφο του Excel, κανένας οδηγός εκτυπωτή και καμία εξωτερική DLL δεν συμμετέχει στην απόδοση

Το HotXLS αντιμετωπίζει το PDF ως μορφή παρουσίασης δεδομένων, αδελφό των διαδρομών εξαγωγής CSV, TSV και HTML, και όχι ως μηχανή απόδοσης ακριβείας pixel (pixel-accurate rendering engine). Η εξαγωγή αναπαράγει το πινακοποιημένο περιεχόμενο και τη διάταξη: τις τιμές που βλέπετε στο πλέγμα (grid), τις αναλογίες των στηλών και τις γραμμές πλέγματος (gridlines) γύρω από τα κελιά. Αυτό το πλαίσιο έχει σημασία επειδή θέτει μια ειλικρινή προσδοκία εκ των προτέρων, και το υπόλοιπο αυτού του άρθρου αφορά ακριβώς το πού πέφτει η γραμμή

Πώς μετατρέπετε το Excel σε PDF στο Delphi χωρίς το Office;

Η συντομότερη διαδρομή είναι μια μεμονωμένη κλήση. Το TXLSWorksheet εκθέτει τα SaveAsPDF(FileName) και SaveAsPDF(Stream), και το TXLSWorkbook εκθέτει τις ίδιες δύο υπερφορτώσεις (overloads) που προωθούν την κλήση στο ενεργό φύλλο. Κάθε μία επιστρέφει έναν Integer, 1 σε περίπτωση επιτυχίας και -1 σε περίπτωση αποτυχίας, ώστε να μπορείτε να διακλαδωθείτε ανάλογα με το αποτέλεσμα χωρίς να χρειάζεται να τυλίξετε την κλήση στον δικό σας χειρισμό εξαιρέσεων (exception handling)

uses
  lxHandle;

var
  Book: TXLSWorkbook;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('sales-june.xlsx');
    // Αποδώστε το χρησιμοποιούμενο εύρος του ενεργού φύλλου απευθείας στο report.pdf.
    if Book.SaveAsPDF('report.pdf') = 1 then
      Writeln('PDF written');
  finally
    Book.Free;
  end;
end;

Όταν καλείτε το SaveAsPDF σε ένα φύλλο εργασίας, το HotXLS εξάγει το UsedRange αυτού του φύλλου, δηλαδή το πλαίσιο οριοθέτησης (bounding box) κάθε συμπληρωμένου κελιού. Η υπερφόρτωση του βιβλίου εργασίας είναι μια ευκολία που μεταβιβάζει την εργασία στο ενεργό φύλλο, οπότε μια αναφορά πολλαπλών φύλλων είτε εκτελεί βρόχο στα φύλλα που χρειάζεται είτε επιλέγει το ενεργό φύλλο πριν από την κλήση. Δεν υπάρχει λειτουργία ολόκληρου βιβλίου εργασίας (όλα σε ένα πέρασμα) που να συνενώνει κάθε καρτέλα. Κάθε κλήση αποδίδει ένα φύλλο ή ένα εύρος

Πώς μετατρέπει το HotXLS ένα χρησιμοποιούμενο εύρος σε σελίδες PDF;

Οι γραμμές στη συνέχεια ρέουν προς τα κάτω στη σελίδα μέχρι η επόμενη να ξεπεράσει το κάτω περιθώριο, οπότε το HotXLS ανοίγει μια νέα σελίδα και συνεχίζει, έτσι ώστε ένα φύλλο χιλίων γραμμών να σελιδοποιείται μόνο του χωρίς εσείς να χρειάζεται να κρατάτε λογαριασμό για τις αλλαγές σελίδας. Κάθε κελί εκτυπώνει το FormattedText του, δηλαδή τη συμβολοσειρά εμφάνισης που παράγεται μετά την εφαρμογή της μορφής αριθμού, οπότε μια ημερομηνία εμφανίζεται όπως τη δείχνει το φύλλο και ένα κελί νομίσματος διατηρεί τα διαχωριστικά χιλιάδων και το σύμβολό του. Το κείμενο που υπερβαίνει τη στήλη του περικόπτεται στο πλάτος του κελιού αντί να χύνεται στο διπλανό

Έλεγχος προσανατολισμού, περιθωρίων και μεγέθους γραμματοσειράς

Για οτιδήποτε πέρα από την προεπιλεγμένη διάταξη, καθοδηγήστε τον εξαγωγέα απευθείας. Η κλάση TXLSPDFExport είναι η κλάση πίσω από τις βοηθητικές μεθόδους μίας γραμμής, και δημοσιεύει τρεις ιδιότητες: Orientation (xlsPdfPortrait ή xlsPdfLandscape, με προεπιλογή το portrait), Margin (σε typographic points, με προεπιλογή 40) και FontSize (σε points, με προεπιλογή 9). Ορίστε τις προτού καλέσετε το SaveAsPDF και ολόκληρο το έγγραφο θα τις υιοθετήσει

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;  // προσαρμογή φαρδιών φύλλων στη σελίδα
      Exporter.Margin := 28;                     // στενότερο περιθώριο σελίδας, σε points
      Exporter.FontSize := 8;                    // πυκνότερες γραμμές
      Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

Το TXLSPDFExport δέχεται επίσης ένα εύρος (range) αντί για ολόκληρο το φύλλο μέσω του SaveAsPDF(Range: IXLSRange; ...), που είναι ο τρόπος με τον οποίο εξάγετε ένα μπλοκ σύνοψης από ένα φύλλο που περιέχει επίσης πρόχειρους υπολογισμούς. Αυτή η υπερφόρτωση εύρους είναι η ίδια στην οποία βασίζεται εσωτερικά το βοηθητικό πρόγραμμα του φύλλου εργασίας, οπότε η διάταξη, η κλιμάκωση και η σελιδοποίηση συμπεριφέρονται πανομοιότυπα είτε του δώσετε ένα πλήρες χρησιμοποιούμενο εύρος είτε μια χειροκίνητα επιλεγμένη περιοχή

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
  Summary: IXLSRange;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    // Εξαγάγετε μόνο το μπλοκ σύνοψης, όχι τις πρόχειρες στήλες δίπλα του
    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;

Γιατί το HotXLS δεν ενσωματώνει γραμματοσειρά: Ο συμβιβασμός Helvetica και WinAnsi

Το HotXLS γράφει το κείμενο με την ενσωματωμένη Helvetica του PDF και το WinAnsiEncoding, μια σκόπιμη επιλογή μηδενικών εξαρτήσεων με ένα πραγματικό όριο. Επειδή η Helvetica είναι μία από τις 14 τυπικές γραμματοσειρές που φέρει ήδη κάθε συμβατό πρόγραμμα ανάγνωσης PDF, ο εξαγωγέας δεν ενσωματώνει καθόλου πρόγραμμα γραμματοσειράς. Το αρχείο παραμένει μικρό και ανοίγει οπουδήποτε, χωρίς να χρειάζεται άδεια χρήσης ή αποστολή αρχείων μαζί του. Το κόστος αυτής της επιλογής είναι το ρεπερτόριο χαρακτήρων που μπορεί να εμφανίσει η σελίδα

Το WinAnsiEncoding καλύπτει το σύνολο Windows-1252, οπότε το λατινικό κείμενο, τα κοινά σημεία στίξης και οι συνήθεις δυτικοευρωπαϊκοί τόνοι αποδίδονται σωστά, και το HotXLS αναδιπλώνει μια χούφτα τυπογραφικών χαρακτήρων, καμπύλων εισαγωγικών, παυλών en και em, και το σύμβολο του ευρώ στις θέσεις τους στο CP1252. Χαρακτήρες εκτός αυτού του εύρους, CJK ιδεογράμματα, κυριλλικά, ελληνικά και αραβικά, καταλήγουν σε ερωτηματικό στη σελίδα. Εάν τα φύλλα σας περιέχουν μη λατινικό κείμενο, αυτός ο εξαγωγέας είναι το λάθος εργαλείο, και ένας αποδότης PDF πλήρους μορφοποίησης είναι η λύση που ταιριάζει

Πού σταματά η εξαγωγή από φύλλο εργασίας σε PDF

Το HotXLS αποδίδει περιεχόμενο και δομή, και όχι το πλήρες οπτικό στυλ του φύλλου. Τα γεμίσματα κελιών, τα στυλ περιγράμματος ανά άκρη, οι γραμματοσειρές και τα χρώματα ανά κελί, τα γραφήματα και οι ενσωματωμένες εικόνες βρίσκονται εκτός των δυνατοτήτων σχεδίασης του εξαγωγέα. Αυτό που λαμβάνετε είναι το πλέγμα κειμένου με ομοιόμορφες γραμμές πλέγματος. Αυτό είναι το ίδιο συμβόλαιο που τηρούν οι εξαγωγείς HTML και RTF, και είναι το κατάλληλο για μια αναφορά ή μια παράδοση δεδομένων όπου οι αριθμοί μεταφέρουν το νόημα και όχι το θέμα

Όταν ο στόχος είναι ένα μορφοποιημένο έγγραφο με συνεπή εταιρική ταυτότητα, το σύνηθες μοτίβο είναι να συγκεντρώσετε πρώτα τους αριθμούς σε ένα πρότυπο υπολογιστικού φύλλου, το οποίο καλύπτει σε βάθος η ροή εργασίας παραγωγής αναφορών βάσει προτύπων. Και επειδή τίποτα από αυτά δεν αγγίζει το COM ή μια εκτελούμενη παρουσία του Excel, η ροή εργασίας ταιριάζει στο ίδιο μοντέλο αυτοματοποίησης χωρίς Office που χρησιμοποιεί το HotXLS παντού: καθαρή Pascal, με δυνατότητα ανάπτυξης σε διακομιστή χωρίς γραφικό περιβάλλον (headless), χωρίς ανάγκη για άδειες χρήσης interop

Το αυτόνομο PDF, byte προς byte

Το HotXLS κατασκευάζει τη δομή του αρχείου PDF με το χέρι και υπολογίζει τον πίνακα διασταυρούμενων αναφορών (cross-reference table) από ακριβείς μετατοπίσεις byte (byte offsets), ο οποίος είναι ο λόγος που η έξοδος ανοίγει σε κάθε πρόγραμμα ανάγνωσης. Καθώς σειριοποιεί κάθε αντικείμενο, το HotXLS καταγράφει την αρχική μετατόπιση αυτού του αντικειμένου πριν προσαρτήσει τα byte του, και στη συνέχεια προωθεί την τρέχουσα θέση κατά το μήκος που μόλις έγραψε, έτσι ώστε ο πίνακας xref να προσγειώνεται ακριβώς σε κάθε αντικείμενο και το startxref να σηματοδοτεί πού ξεκινά αυτός ο πίνακας. Ένας αναγνώστης που βρίσκει αυτές τις μετατοπίσεις έστω και ένα byte λάθος απορρίπτει ολόκληρο το αρχείο, γεγονός που καθιστά την αυτο-υπολογιζόμενη μετατόπιση το βασικό συμβόλαιο του εξαγωγέα

Αυτό το συμβόλαιο φέρει μια αυστηρή συνέπεια που αξίζει να γνωρίζετε. Ο κόμβος Pages γράφεται πρώτος ως αντικείμενο 1, αλλά η λίστα των θυγατρικών του σελίδων δεν είναι γνωστή μέχρι να εκπεμφθεί κάθε σελίδα, οπότε το HotXLS τον κρατά ως placeholder και συμπληρώνει τις τελικές σελίδες και τον αριθμό πριν εκτελεστεί το πέρασμα μετατόπισης, ποτέ μετά. Μόλις μετρηθούν τα byte ενός αντικειμένου για το xref, παγώνουν: η αλλαγή έστω και ενός byte αργότερα θα μετατόπιζε κάθε επόμενη μετατόπιση και θα κατέστρεφε τον πίνακα. Είναι μια μικρή πειθαρχία που εξασφαλίζει ένα έγκυρο κατά τα πρότυπα PDF 1.4 χωρίς καμία υποκείμενη βιβλιοθήκη

Οι μέθοδοι SaveAsPDF και η κλάση TXLSPDFExport που εμφανίζονται εδώ παρέχονται με το HotXLS Delphi Excel Component, μαζί με τους εξαγωγείς CSV, HTML και RTF και το πλήρες API φύλλου εργασίας για Delphi και C++Builder