ConvertToPDFA zamienia zwykły dokument w archiwalny jednym wywołaniem: usuwa to, czego zabrania wybrana część, dodaje to, czego wymaga, deklaruje część, którą dokument rości, a następnie sprawdza wynik. Roszczenie jest raportowane jako spełnione dopiero wtedy, gdy sprawdzanie przejdzie, a GetPDFAConversionReport wylicza, co zostało zrobione i co wciąż stoi na przeszkodzie
Ta ostatnia właściwość to decyzja projektowa, której warto się przyjrzeć. Konwerter, który stempluje roszczenie bez sprawdzania, jest gorszy niż brak konwertera w ogóle, ponieważ plik twierdzący, że jest archiwalny, a nie będący nim, przechodzi prosto przez te same systemy, które inaczej by go złapały. Porażka ujawnia się latem później, w audycie, na dokumencie, którego nikt nie potrafi wygenerować ponownie
Dlaczego poprawnie wyglądający PDF nie przechodzi sprawdzenia PDF/A?
Najczęściej dlatego, że dwa miejsca, w których PDF mówi, kto go napisał, się nie zgadzają. Walidator czyta zarówno słownik informacji dokumentu, jak i pakiet XMP oraz odrzuca plik, w którym się różnią — a większość plików, które zawodzą na tym punkcie, po prostu nigdy nie miała zapisanej połowy XMP
RepairDocumentMetadata doprowadza je do zgody i zwraca liczbę naprawionych wpisów. Gdy tylko jedna połowa niesie wartość, druga jest z niej wypełniana, więc nic już zapisanego nie jest wyrzucane. Nikt nie musi decydować, która kopia jest wiążąca, bo w praktyce jedna kopia jest pusta
W tym samym wywołaniu siedzi druga naprawa, która wychwytuje subtelniejszy przypadek. Dokument ustawiony w tryb PDF/A odzyskuje identyfikację norm, jeśli została utracona, co następuje zawsze, gdy wywołujący dostarczy własny pakiet XMP. Bez tej identyfikacji walidator czyta plik jako zwykły PDF i raportuje każdą regułę rozczonej części jako niespełnioną — spektakularnie wyglądająca porażka o jednej małej przyczynie
var
Lib: TPDFlib;
Repaired: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('incoming.pdf', '');
Repaired := Lib.RepairDocumentMetadata;
Log(Format('%d metadata entries brought into agreement', [Repaired]));
Lib.SaveToFile('incoming-fixed.pdf');
finally
Lib.Free;
end;
end;
Wybór części przed konwersją
SetPDFAMode i ConvertToPDFA współdzielą tę samą numerację trybów, a trzy z wartości są niedawne. Tryb 9 to PDF/A-4, część zbudowana na PDF 2.0. Tryb 10 to PDF/A-4e, który dodatkowo dopuszcza treści 3D i rich media, a tryb 11 to PDF/A-4f, który dopuszcza osadzony plik dowolnego formatu
Część 4 identyfikuje się inaczej niż części przed nią: numerem części i rokiem publikacji tej części, bez litery zgodności dla czystego PDF/A-4 oraz z literą E lub F dla dwóch rozszerzeń. Sprawdzenie rozpoznaje część 4, ocenia jej pliki wobec PDF 2.0 zamiast 1.7 i raportuje plik części 4, który nie podaje swojego roku rewizji
Każdy osadzony plik w dokumencie części 4 deklaruje swoją relację wobec dokumentu, czego wymagają zarówno części 3, jak i 4. To jest reguła, która kiedyś łapała zwykłe załączniki: relację zapisywano tylko dla załączników po pierwszym i nigdy dla ostatniego, więc dokument z jednym załącznikiem — częsty przypadek — nie niósł jej wcale i nie przechodził walidacji dokładnie na tym punkcie
var
Verdict: Integer;
begin
Lib.LoadFromFile('report.pdf', '');
Verdict := Lib.ConvertToPDFA(9); // 9 = PDF/A-4, 10 = 4e, 11 = 4f
Memo1.Lines.Text := Lib.GetPDFAConversionReport;
if Verdict = 1 then
Lib.SaveToFile('report-pdfa4.pdf')
else
Log('conversion incomplete - see the report for what stands in the way');
end;
Po co jest raport konwersji
By zdecydować, co dalej. Konwersja, która się udaje, nie potrzebuje raportu; konwersja, która się nie udaje, to cały powód istnienia raportu. Niektóre przeszkody są usuwalne przez konwerter, a niektóre nie — szyfrowanie, zabroniona treść niosąca znaczenie, program czcionki, którego po prostu nigdzie na maszynie nie ma. Raport rozróżnia to, co zostało zrobione, od tego, co pozostaje, co zamienia „konwersja nieudana" w element pracy
Traktuj werdykt jako bramkę w potoku wsadowym. Konwertuj, czytaj werdykt i kieruj plik: archiwizuj te, które przeszły, kolejkuj resztę dla człowieka z dołączonym raportem. Czego nie powinieneś robić, to zapisywać wyniku nieudanej konwersji do archiwum, bo wygląda lepiej niż wejście — niesie teraz roszczenie, którego sprawdzenie odmówiło potwierdzić
Odczytywanie znacznika, jaki plik już niesie
Zanim cokolwiek przekonwertujesz, wiedz, co dokument mówi o sobie. Sprawdzenie PDF/A, które nie potrafi odczytać istniejącego znacznika norm, ocenia każdy plik wobec części 1 cokolwiek deklaruje, co oznacza, że doskonale zgodny dokument PDF/A-2 lub PDF/A-3 zostaje raportowany jako nieniosący żadnego znacznika i jako zbyt wysokiej wersji — odwrotność prawdy
Znacznik jest czytany niezależnie od tego, czy producent zapisał go jako element XMP, czy jako atrybut. Obie formy to zwykły XMP, a akceptowanie tylko jednej z nich zostawia pliki od innych producentów wyglądające jako nieotagowane. Jeśli kiedykolwiek zastanawiałeś się, dlaczego dokument, który przechodzi walidację gdzie indziej, zawodzi we własnym potoku, to jest dobre miejsce, by zajrzeć najpierw
Sanityzacja przed archiwizacją i błąd, o którym warto wiedzieć
Konwersja archiwalna i sanityzacja często biegną razem, ponieważ treść, jaką chce usunąć polityka bezpieczeństwa, mocno pokrywa się z treścią zabronioną przez PDF/A. SanitizeDocument usuwa JavaScript, a usunięcie ostatniego skryptu usuwa też puste drzewo nazw, które po sobie zostawia — drzewo, które inaczej wciąż mówiłoby czytnikowi, że dokument niósł skrypty
Ta druga połowa została nauczona na własnych błędach: błąd off-by-one w liście pakietów sprawiał, że sanityzacja raportowała usunięcie skryptów, nie usuwając żadnego, więc dokument, który został zsanityzowany, uruchamiał nadal swoje skrypty po otwarciu. To dobry argument za ogólną zasadą, na której opiera się cały ten artykuł — weryfikuj wynik zamiast ufać operacji, w swoim potoku tak samo jak w bibliotece
W sprawie otaczającej pracy archiwalnej zobacz przewodniki po preflighcie PDF/A i PDF/UA, prawdziwym redoagowaniu i usuwaniu treści oraz schematach rozszerzeń XMP PDF/A-3 dla Factur-X, który obejmuje stronę metadanych, gdy archiwizowany dokument niesie także ustrukturyzowane dane faktury
PDFlibPas to natywna biblioteka PDF w Pascalu dla środowisk Delphi, C++Builder i Lazarus, więc konwersja, naprawa i walidacja odbywają się wewnątrz własnego procesu bez zewnętrznego narzędzia w łańcuchu — zobacz stronę produktu PDFlibPas, by poznać obsługiwane części PDF/A i platformy