PDFiumPas, obal pre Delphi a C++Builder okolo enginu PDFium od Googlu, ukladá dokument na presnú verziu PDF od 1.3 po 1.7 cez parameter PdfVersion metódy TPdf.SaveAs. Vlastné volanie FPDF_SaveWithVersion od PDFium iba prepíše hlavičku %PDF-M.m, bez kontroly, či je skutočný obsah dokumentu na danej verzii legálny. PDFiumPas túto medzeru uzatvára prechodom kontroly zhody po uložení, ktorý prejde aktívny reťazec revízií krížových odkazov a skontroluje deklarácie Adobe Extension Level ešte predtým, než súbor opustí metódu
Toto rozlíšenie je najdôležitejšie v tlačovej produkcii, kde profil PDF/X pomenúva presnú verziu PDF a nástroj na preflight alebo RIP odmietne čokoľvek, čo sa ticho odlišuje od vlastnej hlavičky, scenár pokrytý zo strany výstupu v validácii tlačovo pripravených dokumentov PDF/X pomocou PDFiumPas. SaveAs sprístupňuje cieľ ako výčtový typ TPdfVersion, pv13 až pv17 popri starších hodnotách pv10 až pv12, plus nezávislý TSaveOption pre inkrementálne alebo plné prepisy. Odovzdajte PdfVersion a PDFiumPas vykoná dve úlohy v jednom volaní: požiada PDFium o vytlačenie požadovanej hlavičky, potom znova prečíta čerstvo zapísané bajty a odmietne vrátiť súbor, ktorého aktívny obsah nemôže na danej verzii legálne existovať
var
Pdf: TPdf;
begin
Pdf:= TPdf.Create(nil);
try
Pdf.FileName:= 'source.pdf';
Pdf.Active:= True;
try
Pdf.SaveAs('press-ready.pdf', saNoIncremental, pv17);
except
on E: Exception do
// E.Message names the offending feature and the version or
// extension level it actually needs, for example:
// "RichMedia annotations and RichMediaExecute actions require
// /Extensions /ADBE with /BaseVersion /1.7 and /ExtensionLevel 3
// or newer."
raise;
end;
finally
Pdf.Free;
end;
end;
Prečo je posledná definícia objektu v súbore nesprávna vec na dôverovanie?
Posledný fyzický objekt s daným číslom v súbore PDF nie je nutne objekt, ktorý by normu rešpektujúca čítačka pre toto číslo dnes vyriešila. PDF, ktoré prešlo niekoľkými inkrementálnymi aktualizáciami, nemá jeden graf objektov, má ich históriu vrstvenú vnútri jediného súboru, a každý cyklus pripojenia môže objekt uvoľniť, znova ho definovať pod novým generačným číslom, alebo nechať jeho staré fyzické telo sedieť medzi dvomi značkami endobj bez akéhokoľvek záznamu krížového odkazu, ktorý by naň ešte ukazoval
PDFiumPas narazil presne na tento režim zlyhania ešte predtým, než výslovne sledoval revízie xref: osirotená anotácia Redact po neskoršom prepísaní objektu stránky, alebo slovník /MarkInfo ponechaný fyzicky prítomný bez akéhokoľvek záznamu xref, ktorý by naň ukazoval, sa stále mohli objaviť pri skenovaní bajtov a stále vyvolať kontrolu funkcie viazanej na verziu, ktorá sa už na dokument, aký by čítačka v skutočnosti otvorila, nevzťahovala. Smer zlyhania bol falošné odmietnutie, nie falošné prijatie: súbor, ktorý v aktuálnej revízii naozaj funkciu prekonal, mohol byť stále zablokovaný pred uložením na nižšiu verziu kvôli obsahu, ku ktorému sa už nikto nevedel dostať
Ako PDFiumPas určuje, ktoré definície objektov sú v skutočnosti aktívne?
PDFiumPas rieši aktívnu množinu objektov rovnako, ako to robí normu rešpektujúca čítačka, prechodom reťazca krížových odkazov namiesto skenovania bajtov na hlavičky objektov. Resolver začína na poslednom posune startxref v súbore a sleduje každý odkaz /Prev smerom dozadu cez staršie revízie, pričom cestou parsuje klasické tabuľky krížových odkazov, hybridné prúdy prepojené cez /XRefStm, aj čisté prúdy krížových odkazov. Prechod beží od najnovšieho k najstaršiemu a usadí každé číslo objektu pri prvom uvidení, takže voľný záznam v neskoršej revízii správne zatieni telo objektu zapísané v skoršej, a znovudefinovanie pod novým posunom alebo generáciou vždy vyhráva nad tým, čo nahradilo
Členovia prúdu objektov dostávajú dodatočnú kontrolu, ktorú obyčajné vyhľadanie posunu samo osebe nedokáže poskytnúť, mechanizmus opísaný do hĺbky vo validácii prúdov objektov a krížových odkazov pomocou PDFiumPas. Komprimovaný objekt obnovený z /ObjStm musí mať svoj nadradený prúd potvrdený ako aktívny v tom istom prechode, a jeho index sa musí zhodovať s vlastnou pozíciou člena vnútri hlavičky tohto prúdu ešte predtým, než ho PDFiumPas považuje za živý obsah. ISO 32000-1 sekcia 7.5.8.4 dokonca opisuje prípad hybridných odkazov, kde klasická kompatibilná tabuľka označí objekt ako voľný, zatiaľ čo záznam /XRefStm trailera súčasne definuje ten istý objekt ako komprimovaného člena inde; PDFiumPas zlúči doplnkový prúd xref do tej istej revízie ešte predtým, než sa aplikujú klasické záznamy, takže komprimovaná definícia vyhráva presne tak, ako to špecifikácia zamýšľa
Úrovne rozšírenia Adobe: brána nad číslom verzie
Hlavička %PDF-1.7 sľubuje iba súbor funkcií, ktorý ISO 32000-1 štandardizovala v roku 2008, zatiaľ čo niekoľko schopností, na ktoré sa dnes producenti PDF spoliehajú, vyšlo neskôr ako doplnky výhradne od Adobe navrstvené na tom istom čísle verzie. Adobe zaregistroval každý doplnok ako dvojicu BaseVersion a ExtensionLevel zaznamenanú v slovníku /Extensions katalógu dokumentu pod prefixom vývojára, ADBE pre vlastné rozšírenia Adobe, takže čítačka dokáže rozlíšiť obyčajný súbor PDF 1.7 od takého, ktorý implementuje aj číslovanú úroveň rozšírenia. Uloženie na pv17 bez tejto deklarácie samo osebe nie je chyba; stáva sa ňou až vo chvíli, keď aktívny obsah v skutočnosti závisí od funkcie, ktorú má deklarácia pokrývať
Ktoré funkcie vysokej verzie spustia bránu explicitnej verzie?
PDFiumPas kontroluje konkrétny zoznam vychádzajúci zo špecifikácie, nie hádanie iba podľa čísla verzie. Slovníky obrázkov nesúce explicitnú položku /SMaskInData alebo hodnotu /BitsPerComponent 16 obe vyžadujú PDF 1.5, pričom šestnásťbitový prípad priamo nasleduje pravidlá pre zložky obrázka v PDF Reference 1.5 sekcii 4.8. Anotácie RichMedia a akcie RichMediaExecute vyžadujú /BaseVersion /1.7 s /ExtensionLevel 3 alebo vyšším. Prúdy PRC 3D, identifikované slovníkom nesúcim aj /Type /3D, aj /Subtype /PRC, vyžadujú tú istú základnú verziu, no iba /ExtensionLevel 1. Geopriestorové slovníky Measure a anotácie Projection vyžadujú /BaseVersion /1.7 s /ExtensionLevel 3, ten istý doplnok Adobe, od ktorého závisí RichMedia
Geopriestorová kontrola nesie detail z čítania špecifikácie, ktorý sa oplatí poznať, ak niekedy staviate vlastnú logiku bránenú verziou nad PDFiumPas. Tabuľka 254 ISO 32000-1 označuje položku /Type slovníka Measure ako voliteľnú, pričom uvádza iba, že „ak je prítomná, musí byť Measure“, zatiaľ čo tabuľka 311 robí /Type povinným pre slovník prúdu 3D, v ktorom žije obsah PRC. Skutočný výstup GeoPDF z mapovacích nástrojov bežne vynecháva /Type na slovníku Measure a zapisuje iba /Subtype /GEO, takže geopriestorový detektor PDFiumPas sa zhoduje iba na /Subtype namiesto toho, aby vyžadoval oba kľúče, ako to bezpečne dokáže jeho detektor PRC 3D. Vyžadovanie /Type na oboch slovníkoch by dovolilo, aby zhodujúci sa obsah GeoPDF prekĺzol popri bráne nezistený, pristáve v obyčajnom súbore PDF 1.7 bez akejkoľvek deklarácie úrovne rozšírenia, ktorá by to podložila
Znižuje PDFiumPas automaticky nepodporované funkcie?
Nie ako všeobecná schopnosť, a predpokladať opak je práve tá chyba, ktorej sa treba tu vyhnúť. SaveAs presmerováva cieľovú verziu cez internú rutinu ValidatePdfVersionCompliance, a keď táto rutina nájde funkciu, ktorú cieľová verzia alebo jej deklarácia úrovne rozšírenia nedokáže podporiť, SaveAs vyvolá výnimku nesúcu text chyby tejto rutiny namiesto zápisu súboru; volajúci dostane späť presný, podľa funkcie pomenovaný dôvod, nikdy ticho prepísaný dokument. Jediné miesto, kde PDFiumPas obsah skutočne automaticky prepisuje, je cieľ PDF 1.3, kde odstráni sémanticky neutrálne predvolené hodnoty priehľadnosti /BM /Normal, /CA 1, a /ca 1, ktoré PDFium vždy zapisuje do slovníkov ExtGState bez ohľadu na cieľovú verziu, pretože tieto konkrétne hodnoty nenesú žiadny vizuálny význam a PDF 1.3 tieto kľúče úplne predchádza
// PDF 1.3 targets rewrite the saved bytes to strip transparency
// defaults PDFium always emits, so incremental mode cannot apply
Pdf.SaveAs('legacy-archive.pdf', saIncremental, pv13);
// raises: PDF 1.3 normalization is incompatible with incremental
// save mode
Skutočná nepredvolená priehľadnosť a mäkké masky obrázkov stále úplne zlyhajú pri cieli PDF 1.3, pretože ich odstránenie by zmenilo, ako stránka v skutočnosti vyzerá, a PDFiumPas toto rozhodnutie za vás neurobí. S dvomi súvisiacimi limitmi sa oplatí počítať ešte pred tým, než sa presná verzia dostane do dávkovej pipeline. Výstup s explicitnou verziou nikdy nenesie slovník /Encrypt; uloženie okamžite zlyhá, ak je zdroj chránený, čo sa náhodou zhoduje s profilmi PDF/X a PDF/A, ktoré aj tak zakazujú šifrovanie, no znamená to, že dešifrovanie je vo vašom pracovnom postupe samostatný krok, nie niečo, čo za vás urobí SaveAs. PDFiumPas tiež nemá žiadnu verejnú metódu na zápis deklarácie /Extensions /ADBE do katalógu, takže zdrojový súbor, ktorý obsahuje RichMedia, PRC 3D, alebo geopriestorový obsah, no tejto deklarácii chýba, neprejde bránou bez ohľadu na to, akú PdfVersion požiadate; deklarácia už musí existovať v zdroji, typicky preto, že ju zapísal autorský nástroj, alebo funkcia musí von skôr, než sa uloženie spustí. Vlastnosť TPdf.PdfVersion iba na čítanie sa oplatí skontrolovať ešte pred tým, než sa vôbec pokúsite o uloženie na presnú verziu, keďže rieši tú istú efektívnu verziu vedomú si katalógu, hlavičku alebo prepísanie /Version, ktorákoľvek je aktuálna, na akú sa spolieha aj sám validátor v čase uloženia
Pdf.FileName:= 'incoming.pdf';
Pdf.Active:= True;
// PdfVersion resolves the same catalog-aware effective version the
// save-time validator uses, so a mismatch here is worth investigating
// before spending a full SaveAs attempt on it
LogSourceVersion('incoming.pdf', Pdf.PdfVersion);
Berte výnimku SaveAs pri cieli presnej verzie ako preflight report, nie ako chybu: správa pomenúva presnú klauzulu, ktorú zdrojový dokument porušuje, čo je presne tá informácia, akú tlačiareň alebo archívna pipeline potrebuje ešte predtým, než súbor pôjde ďalej. Cesta ukladania s explicitnou verziou, resolver aktívnej revízie xref, a kontroly úrovne rozšírenia Adobe opísané tu sa dodávajú ako súčasť štandardného komponentu PDFiumPas pre Delphi a C++Builder; stránka produktu nesie plnú referenciu TPdf.SaveAs spolu so zvyškom API pre zhodu a formuláre