PDFlibPas konwertuje treść PDF na dwa edytowalne formaty bez automatyzacji Office. ExportPageMarkdown i ExportDocumentMarkdown zwracają semantyczny Markdown z wywnioskowanymi nagłówkami, listami numerowanymi i nienumerowanymi oraz tabelami w formacie pipe, natomiast SaveDOCXToFile i SaveDOCXToStream zapisują pakiet WordprocessingML zawierający akapity, nagłówki, natywną numerację list, wykryte tabele, stylizację czcionek, podziały stron i pozycjonowane obrazy PNG
Obie funkcje działają całkowicie w Pascalu, na serwerze, bez zainstalowanego Worda i bez COM. To ograniczenie jest powodem, dla którego funkcja istnieje w bibliotece PDF, a nie w narzędziu desktopowym
Dlaczego konwersja PDF na Word jest naprawdę trudna?
Ponieważ strona PDF nie zawiera akapitów. Zawiera operatory wyświetlania tekstu, które umieszczają ciągi glifów w określonych współrzędnych, w takiej kolejności, w jakiej wypisał je producent, bez żadnego obowiązku wskazania, że dwa ciągi należą do tego samego zdania, a tym bardziej do tego samego elementu listy. Format zaprojektowano tak, aby dokładnie opisywał wydrukowaną stronę, i osiąga to, odrzucając strukturę, która tę stronę wygenerowała
Dlatego każdy konwerter musi odtworzyć to, co generator wyrzucił. Grupowanie wierszy pochodzi z odstępów pionowych i wyrównania linii bazowej. Granice akapitów pochodzą ze zmian odstępów i wcięć. Nagłówek to wiersz, którego czcionka jest większa lub grubsza niż tekst główny i który wyróżnia się na tle tego, co następuje. Lista to seria akapitów zaczynających się od znaku wypunktowania lub wzorca numeracji. Tabela to siatka bloków tekstu, których krawędzie wyrównują się w wierszach i kolumnach. Każdy z tych przypadków to wnioskowanie, a wnioskowanie oznacza dobry wynik na dokumentach trzymających się zwykłych konwencji typograficznych i przeciętny na dokumentach, które ich nie przestrzegają
Oznaczone pliki PDF są wyjątkiem, i to dużym. Gdy dokument niesie drzewo struktury, role akapitu, nagłówka, listy i tabeli są zapisane, a nie odgadywane, dlatego praca nad dostępnością opisana w strukturze dostępności oznaczonych plików PDF opłaca się także w jakości konwersji. Jeśli kontrolujesz producenta, otagowanie własnego wyjścia to najbardziej opłacalna rzecz, jaką możesz zrobić dla każdego, kto będzie musiał je później skonwertować
Eksport do Markdown, strona po stronie
Ścieżka Markdown to ta, po którą warto sięgnąć, gdy celem jest potok tekstowy: witryna dokumentacji, indeks wyszukiwania, korpus wyszukiwawczy dla asystenta. Opcje to maska bitowa: PDF_MARKDOWN_INCLUDE_PAGE_MARKERS, PDF_MARKDOWN_DETECT_HEADINGS, PDF_MARKDOWN_PRESERVE_STYLES, przy czym PDF_MARKDOWN_DEFAULT łączy wszystkie trzy
var
Pdf: TPDFlib;
Md: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.LoadFromFile('handbook.pdf', '');
// Jedna strona, jako łańcuch znaków
Md := Pdf.ExportPageMarkdown(1, PDF_MARKDOWN_DEFAULT);
// Zakres stron, strumieniowany na dysk jako UTF-8 bez BOM
Pdf.SaveMarkdownToFile('1-40',
PDF_MARKDOWN_DETECT_HEADINGS or PDF_MARKDOWN_PRESERVE_STYLES,
'handbook.md');
finally
Pdf.Free;
end;
end;
Znaczniki stron zwracają się w pracy wyszukiwawczej. Fragment tekstu niosący stronę, z której pochodzi, można precyzyjnie zacytować, a czytelnik podążający za cytatem trafia dokładnie tam, gdzie dane twierdzenie się znajduje. Wyłącz je, gdy Markdown jest przeznaczony do czytania przez człowieka, gdzie granice stron z układu źródłowego są tylko szumem
Punkty wejścia do strumieniowania mają znaczenie przy dużych dokumentach. SaveMarkdownToStream i SaveMarkdownToFile zapisują UTF-8 stronę po stronie i nie buforują całego wyjścia, więc 900-stronicowy podręcznik nie zamienia się najpierw w 900-stronicowy łańcuch znaków w pamięci. Brak znacznika kolejności bajtów też jest celowy: BOM w pliku Markdown myli zaskakująco wiele generatorów statycznych witryn i narzędzi do porównywania różnic
DOCX bez Office na maszynie
Zapisywacz DOCX tworzy pakiet samodzielnie: wpisy ZIP zapisane jako surowy Deflate z sumami kontrolnymi CRC, części WordprocessingML i relacje, które je wiążą. Nic nie wywołuje Worda, co oznacza, że konwersja działa na bezgłowym serwerze, wewnątrz konta usługi, w kontenerze, wszędzie tam, gdzie automatyzacja Office jest albo nielicencjonowana, albo niestabilna, albo zabroniona
var
Pdf: TPDFlib;
Target: TFileStream;
begin
Pdf := TPDFlib.Create;
Target := TFileStream.Create('handbook.docx', fmCreate);
try
Pdf.LoadFromFile('handbook.pdf', '');
Pdf.SaveDOCXToStream('1-40',
PDF_DOCX_INCLUDE_IMAGES or PDF_DOCX_DETECT_HEADINGS or
PDF_DOCX_PRESERVE_STYLES or PDF_DOCX_PRESERVE_PAGE_BREAKS,
Target);
finally
Target.Free;
Pdf.Free;
end;
end;
Dane obrazu są zapisywane w miarę przetwarzania każdej strony, a nie zbierane i dołączane na końcu, więc szczytowe zużycie pamięci odpowiada jednej stronie, a nie całemu dokumentowi. Zachowana jest jawna kolejność stron, a wybrana strona PDF zostaje przywrócona po zakończeniu, co ma znaczenie, gdy eksport jest jednym krokiem w dłuższym zadaniu, w którym strona była wybrana z innych powodów
Co daje deterministyczne pakowanie?
Powtarzalność bajt po bajcie. Dwie konwersje tego samego wejścia z tymi samymi opcjami tworzą ten sam pakiet, co oznacza, że możesz zahaszować wyjście, aby wykryć zmianę, porównać dwie kompilacje wygenerowanego dokumentu i agresywnie buforować bez obawy, że identyczne wejście dało inny artefakt
Automatyzacja Office nie może tego obiecać. Osadza znaczniki czasu, identyfikatory wersji i metadane zależne od maszyny, więc ten sam dokument skonwertowany dwukrotnie różni się w sposób, który uniemożliwia haszowanie. To samo rozumowanie stoi za deterministycznymi identyfikatorami plików omówionymi w deterministycznych identyfikatorach PDF dla powtarzalnych kompilacji: gdy wyjście jest powtarzalne, weryfikacja staje się porównaniem zamiast inspekcją
Gdzie wyjście jest dobre, a gdzie nie
Bądź szczery wobec swoich użytkowników w tej sprawie, ponieważ jakość konwersji zależy bardziej od wejścia niż od konwertera. Oznaczone pliki PDF i czysto wygenerowane dokumenty biznesowe, faktury, raporty, umowy, konwertują się dobrze: nagłówki lądują jako nagłówki, tabele przetrwają, listy poprawnie się przenumerowują w Wordzie. Dwukolumnowe układy akademickie konwertują się akceptowalnie, jeśli geometria kolumn jest regularna. Tabele rozciągnięte na kilka stron są odtwarzane przez wnioskowanie i czasem się rozdzielają. Mocno zaprojektowane materiały marketingowe, gdzie tekst jest umieszczony dla efektu wizualnego, a nie w kolejności czytania, konwertują się słabo, i żadna ilość wnioskowania tego nie naprawi
Zeskanowane dokumenty to zupełnie osobny przypadek. Strona będąca jednym wielkim obrazem nie zawiera żadnych obiektów tekstowych, więc nie ma czego eksportować, dopóki nie powstanie warstwa tekstowa; ścieżka OCR, która ją tworzy, jest warunkiem wstępnym, a nie opcją. Przed uruchomieniem dużej partii sprawdź próbkę kilkunastu reprezentatywnych plików i przyjrzyj się wynikowi, a rozważ wcześniejsze wyliczenie elementów strony, jak opisano w wyszukiwaniu tekstu i wyliczaniu elementów strony, aby zobaczyć, co strony faktycznie zawierają
Dla potoków asystentów i wyszukiwania ścieżka Markdown jest zwykle lepszym celem: nagłówki stają się granicami fragmentów, tabele pozostają czytelne jako tabele pipe, a znaczniki stron dają każdemu fragmentowi lokalizację, którą można zacytować. Do edycji przez człowieka odpowiedzią jest DOCX, ponieważ użytkownikowi zależy nie na samym tekście, lecz na możliwości jego zmiany
PDFlibPas to biblioteka PDF dla Delphi, C++Builder i Lazarus z odpowiadającymi jej interfejsami DLL i ActiveX, dzięki czemu te same wywołania eksportu są dostępne z C#, C++ lub hostów skryptowych. Pełna dokumentacja i wersja próbna znajdują się na stronie biblioteki PDFlibPas dla Delphi