Artykuł techniczny

Biblioteki PDF losLab dla Delphi: przewodnik po wyborze

Trzy biblioteki. Trzy różne zadania. Wybranie niewłaściwej kosztuje cię tygodnie obejść (workarounds), a wybranie wszystkich trzech, gdy potrzebujesz tylko jednej, kosztuje cię narzut na utrzymanie (maintenance overhead), którego nie uwzględniłeś w budżecie. Oto bezpośrednia relacja o tym, co właściwie robi każda biblioteka PDF losLab, gdzie pasuje i gdzie przekazuje pałeczkę swojemu rodzeństwu

Diagram porównujący trzy biblioteki PDF losLab dla Delphi: HotPDF generujący nowe dokumenty, PDFium Component renderujący i ekstrahujący istniejące pliki oraz PDF Library for Delphi scalający i podpisujący zgodność
HotPDF pisze nowe PDF z kodu, PDFium Component czyta i renderuje istniejące pliki, a PDF Library for Delphi scala, podpisuje i zarządza tym, co już istnieje

HotPDF: pisanie PDF od zera w Delphi

HotPDF to natywny komponent VCL do generowania dokumentów PDF. Jego model jest imperatywny i skupiony na stronach: konstruujesz instancję THotPDF, ustawiasz właściwości dokumentu, wywołujesz BeginDoc, rysujesz na CurrentPage, dodajesz strony w miarę potrzeb i zamykasz przez EndDoc. Kolejność ma znaczenie, bo BeginDoc zatwierdza słownik szyfrowania i ustawienia kompresji w chwili wykonania; cokolwiek przypisanego później jest po cichu ignorowane, a nie dorysowane wstecz

Powierzchnia rysowania pokrywa pełny zestaw operatorów PDF na poziomie Delphi: TextOut do pozycjonowanego tekstu Unicode, SetFont z osadzaniem TrueType, prymitywy wektorowe (linie, krzywe Béziera, elipsy, prostokąty), umieszczanie obrazów z pliku lub z pamięci i generowanie kodów kreskowych. Współrzędne są w punktach od lewego górnego rogu z osią Y rosnącą w dół, tak jak działa kanwa VCL, co zaskoczy każdego, kto przychodzi od surowych strumieni zawartości PDF, gdzie początek leży w lewym dolnym rogu. Stan czcionki nie przetrwa AddPage, więc po każdym podziale strony wymagane jest wywołanie SetFont

Diagram cyklu życia generowania PDF w HotPDF dla Delphi: od utworzenia THotPDF przez BeginDoc, rysowanie i AddPage po EndDoc, z zasadą, że opcje dokumentu zatwierdzają się w BeginDoc
Opcje na poziomie dokumentu blokują się w chwili BeginDoc, współrzędne rosną od lewego górnego rogu, a stan czcionki resetuje się przy każdym AddPage

Pola AcroForm są tu obywatelami pierwszej kategorii. Pola tekstowe, pola wyboru, przyciski radiowe, listy rozwijane, pola list i przyciski push dodasz bezpośrednio do obiektu strony, po jednym wywołaniu na pole. HotPDF potrafi też wczytać istniejący PDF przez LoadFromFile i wypełniać lub odczytywać wartości pól, co czyni go użytecznym w dwóch osobnych przepływach: budowania formularzy i automatyzacji ich wypełniania

Szyfrowanie też jest obsłużone na poziomie dokumentu. CryptKeyLength wybiera schemat (od 40-bitowego RC4 po AES-256), ActivateProtection go uzbraja, a ProtectOptions ustawia flagi uprawnień ISO. Dwa tryby rewizji AES-256 (R5 i R6, sterowane przez UseAES256R6) istnieją, bo rewizja 5 była rozszerzeniem Adobesa, którego sprawdzenie hasła okazało się słabe i zostało później wycofane, a rewizja 6 to forma ustandaryzowana przez ISO 32000-2. Acrobat X i nowsze oraz większość aktualnych przeglądarek otwiera pliki R6, więc R6 to rozsądny wybór domyślny; R5 ma znaczenie tylko wtedy, gdy odbiorca siedzi na starszej przeglądarce

Obsługa podpisów cyfrowych w HotPDF pokrywa profile bazowe PAdES, więc nadaje się do przepływów, w których podpis musi spełniać wymagania ETSI EN 319 142. Jeśli twoja potrzeba ogranicza się do generowania wyniku, HotPDF to biblioteka, po którą sięgasz w pierwszej kolejności

PDFium Component: renderowanie, podgląd i odczyt istniejących PDF

PDFium Component owija silnik PDFium firmy Google jako komponent VCL, co nadaje mu fundamentalnie inną rolę niż HotPDF. Tam, gdzie HotPDF pisze, PDFium Component czyta i renderuje. Głównym obiektem jest TPdf, menedżer dokumentu, który otwiera plik poprzez ustawienie FileName i następnie Active := True. Niepowodzenia ładowania nie są rzucane jako wyjątki; Active po prostu pozostaje na wartości False, więc sprawdzanie jej po przypisaniu nie jest opcjonalne

Renderowanie idzie przez TPdfView, komponent wizualny, który upuszczasz na formularz i łączysz z instancją TPdf przez PdfView.Pdf := Pdf. Zoom i tryb dopasowania mieszkają na widoku, nie na dokumencie. Jedna subtelność, na której ludzie się potykają: Pdf.PageNumber i PdfView.PageNumber to niezależne właściwości. Ustawienie jednej nie aktualizuje drugiej, a API ekstrakcji oparte na widoku (ramki słów, jednostki czytania) używają bieżącej strony widoku, nie dokumentu

Ekstrakcja tekstu to teren, na którym PDFium Component nie ma bezpośredniego konkurenta w ofiercie losLab. ReadablePageContent zwraca tekst strukturalny ze świadomością kolejności czytania, PageWordBoxes daje prostokąty otaczające na poziomie słów, a DocumentReadingUnits przechodzi cały dokument. Do pracy z dostępnością IsTagged mówi ci, czy drzewo struktury jest obecne, a ValidatePdfUa uruchamia kontrolę zgodności UA. Te API czynią PDFium Component naturalnym wyborem dla każdego przepływu, który musi zrozumieć, co siedzi wewnątrz istniejącego PDF, zamiast wyprodukować nowy

Wypełnianie formularzy działa również po stronie PDFium, przez tę samą warstwę AcroForm, którą odsłania macierzysty silnik. Jest to odpowiednie rozwiązanie, gdy dokument źródłowy już istnieje, a ty automatyzujesz jego uzupełnianie, zamiast samemu konstruować pola formularza

PDF Library for Delphi: manipulacja, podpisywanie zgodności i bezpośredni dostęp do pliku

PDF Library for Delphi siedzi na drugim końcu spektrum złożoności. Wystawia trzy warstwy API ponad tym samym modelem dokumentu: płaską fasadę na uchwytach (TPDFlib) zgodną z konwencją wywołań Quick-PDF, pełną warstwę drzewa obiektów (TPDFDocument) i parser strumieniowy (TSmartPDFReader / TSmartPDFWriter), który pracuje bezpośrednio na bajtach pliku bez ładowania pełnego grafu obiektów

Diagram architektury PDF Library for Delphi: fasada TPDFlib, drzewo obiektów TPDFDocument i parser strumieniowy TSmartPDFReader oraz TSmartPDFWriter ponad jednym plikiem dokumentu
Płaska fasada pasuje do krótkich sekwencji wywołań, drzewo obiektów ogarnia edycje strukturalne, a parser strumieniowy dopisuje aktualizacje przyrostowe i znaczniki PAdES bez pełnego ponownego wczytania

Warstwa strumieniowa jest tym, co czyni PDF Library for Delphi właściwym wyborem dla dużych dokumentów. TSmartPDFWriter może dołączyć do pliku na dysku aktualizację przyrostową (incremental update) bez rekonstrukcji całej tabeli odsyłaczy (cross-reference table), co jest mechanizmem leżącym u podstaw zarówno wydajnego ponownego zapisywania, jak i długoterminowych znaczników walidacji (long-term validation stamps) PAdES. W przypadku procesów podpisywania zapewniających rygorystyczne normy zgodności, gdzie podpisany hash musi obejmować określony zakres bajtów, a podpis jest stosowany bez przepisywania dokumentu, ta warstwa jest jedyną opłacalną ścieżką

Manipulacja dokumentem na poziomie TPDFDocument obejmuje łączenie (merging) za pomocą Merge, selektywne kopiowanie stron przez CopyPagesFromDoc z łańcuchem znaków określającym zakres oraz zarządzanie wersją za pomocą SetMinimumVersion i LockSaveVersion. Blokada wersji (version lock) zgłasza błąd 602, jeśli spróbujesz zapisać funkcjonalność, która popchnęłaby plik wyjściowy powyżej zablokowanej wersji, co jest przydatne, gdy musisz zagwarantować, że plik wyjściowy pozostanie w konkretnej rewizji PDF w celu zgodności archiwizacyjnej

Wsparcie dla PDF/A (ISO 19005) znajduje się w pulpicie roboczym zgodności (conformance workbench) biblioteki PDF Library for Delphi. Zauważ, że szyfrowanie i PDF/A wzajemnie się wykluczają (mutually exclusive) zgodnie ze specyfikacją: nie możesz mieć obu w jednym pliku. Procesy, które potrzebują zaszyfrowanej kopii do dystrybucji i kopii archiwalnej PDF/A, muszą wyprodukować dwa osobne artefakty

Wybór między nimi

Typowe drzewo decyzyjne jest krótkie. Jeśli generujesz nowy dokument z danych, użyj HotPDF. Jeśli renderujesz lub wyodrębniasz tekst z istniejącego dokumentu w aplikacji Delphi VCL, użyj PDFium Component. Jeśli manipulujesz, łączysz lub podpisujesz zgodnie z normami istniejące pliki PDF na dużą skalę lub z wykorzystaniem konwencji aktualizacji przyrostowych (incremental-save semantics), użyj PDF Library for Delphi. Wiele systemów produkcyjnych używa dwóch z tych trzech bibliotek: HotPDF do generowania wyników, a PDF Library for Delphi do zastosowania na nim znacznika długoterminowej walidacji przed archiwizacją, na przykład, lub PDFium Component do podglądu tego, co wyprodukował HotPDF przed wysłaniem tego dalej w dół strumienia (downstream)

Wszystkie trzy są dostarczane jako natywne źródła Pascal dla Delphi i C++Buildera. HotPDF i PDF Library for Delphi nie mają zależności uruchomieniowych poza VCL; PDFium Component dostarcza też bibliotekę DLL PDFium, która wykonuje renderowanie i parsowanie po stronie silnika. Strona produktowa każdej biblioteki niesie pełne odniesienie API i bieżącą historię wersji

Szczegóły dotyczące poszczególnych bibliotek: HotPDF Delphi Component, PDFium Component oraz PDF Library for Delphi