A PDFiumPas, a Google PDFium motorja körüli Delphi és C++Builder burkoló, egy dokumentumot pontos PDF-verzióban ment 1.3-tól 1.7-ig a TPdf.SaveAs metódus PdfVersion paraméterén keresztül. Maga a PDFium FPDF_SaveWithVersion hívása csak a %PDF-M.m fejlécet írja át, anélkül hogy ellenőrizné, a dokumentum tényleges tartalma legális-e azon a verzión. A PDFiumPas ezt a rést egy mentés-utáni megfelelőségi átfutással zárja be, amely bejárja az aktív kereszthivatkozás-revíziólánc, és ellenőrzi az Adobe Extension Level deklarációkat, mielőtt a fájl elhagyná a metódust
Ez a megkülönböztetés leginkább a nyomdai gyártásban számít, ahol egy PDF/X-profil pontos PDF-verziót nevez meg, és egy preflight eszköz vagy RIP elutasít bármit, ami csendben nem ért egyet a saját fejlécével, egy forgatókönyv, amelyet a kimeneti oldalról a nyomdakész PDF/X dokumentumok érvényesítése PDFiumPas-szal cikk tárgyal. A SaveAs a célt a TPdfVersion felsorolásként teszi elérhetővé, pv13-tól pv17-ig a régebbi pv10-től pv12-ig terjedő értékek mellett, plusz egy független TSaveOption az inkrementális vagy teljes újraírásokhoz. Add át a PdfVersion-t, és a PDFiumPas két munkát végez egyetlen hívásban: megkéri a PDFium-ot, hogy bélyegezze le a kért fejlécet, majd újraolvassa a frissen megírt bájtokat, és megtagadja egy olyan fájl visszaadását, amelynek aktív tartalma legálisan nem létezhet azon a verzión
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;
Miért rossz dolog megbízni a fájl utolsó objektumdefiníciójában?
Egy adott számú utolsó fizikai objektum egy PDF-fájlban nem feltétlenül az az objektum, amit egy szabványkövető olvasó ma feloldana arra a számra. Egy PDF, amely több inkrementális frissítésen ment át, nem egyetlen objektumgráffal rendelkezik, hanem azok egy történelmével, egyetlen fájlon belülre rétegezve, és minden hozzáfűzési ciklus felszabadíthat egy objektumot, újradefiniálhatja azt egy új generációszám alatt, vagy hagyhatja a régi fizikai testét két endobj jelölő között ülni, anélkül hogy bármely kereszthivatkozás-bejegyzés rá mutatna többé
A PDFiumPas pontosan ebbe a hibamódba ütközött, mielőtt kifejezetten nyomon követte volna az xref-revíziókat: egy Redact-annotáció, amelyet egy későbbi oldal-objektum-újraírás árvává tett, vagy egy /MarkInfo szótár, amely fizikailag jelen maradt, anélkül hogy bármely xref-bejegyzés rá mutatna, még mindig felbukkanhatott egy bájt-vizsgálatban, és még mindig kiválthatott egy verzió-funkció-ellenőrzést, amely már nem vonatkozott arra a dokumentumra, amit egy olvasó ténylegesen megnyitna. A hibairány hamis elutasítás volt, nem hamis elfogadás: egy fájl, amely valóban túllépett egy funkción az aktuális revíziójában, még mindig blokkolva lehetett a mentéstől egy alacsonyabb verzión olyan tartalom miatt, amit senki nem tudott többé elérni
Hogyan határozza meg a PDFiumPas, mely objektumdefiníciók aktívak ténylegesen?
A PDFiumPas ugyanúgy oldja fel az aktív objektumhalmazt, ahogyan egy szabványkövető olvasó teszi, a kereszthivatkozás-lánc bejárásával, nem pedig objektumfejlécek keresésével bájtokban. A feloldó a fájl utolsó startxref eltolásánál kezd, és minden /Prev linket visszafelé követ régebbi revíziókon át, útközben elemezve a klasszikus kereszthivatkozás-táblákat, a hibrid /XRefStm-linkelt streameket, és a tiszta kereszthivatkozás-streameket. A bejárás legújabbtól-legrégebbiig fut, és minden objektumszámot az első láttára telepít le, így egy szabad bejegyzés egy későbbi revízióban helyesen árnyékol egy objektumtestet, amit egy korábbiban írtak, és egy újradefiniálás egy új eltolás vagy generáció alatt mindig győz azzal szemben, amit lecserélt
Az objektumfolyam-tagok egy extra ellenőrzést kapnak, amit egy egyszerű eltolás-keresés önmagában nem tud biztosítani, egy mechanizmus, amelyet mélyebben a az objektum- és kereszthivatkozás-streamek érvényesítése PDFiumPas-szal cikk tárgyal. Egy tömörített objektumnak, amelyet egy /ObjStm-ből állítottak vissza, ugyanabban a bejárásban aktívnak kell megerősítenie szülő streamjét, és az indexének egyeznie kell a tag saját pozíciójával annak a streamnek a fejlécén belül, mielőtt a PDFiumPas élő tartalomként kezelné. Az ISO 32000-1 7.5.8.4. szakasza még le is ír egy hibrid-hivatkozási esetet, ahol egy klasszikus kompatibilitási tábla szabadnak jelöl meg egy objektumot, míg a lezáró (trailer) /XRefStm bejegyzése egyidejűleg tömörített tagként definiálja ugyanazt az objektumot máshol; a PDFiumPas egyesíti a kiegészítő xref-streamet ugyanabba a revízióba, mielőtt a klasszikus bejegyzések alkalmazásra kerülnének, így a tömörített definíció győz úgy, ahogyan a specifikáció szándékozza
Adobe Extension Levelek: a kapu a verziószám fölött
Egy %PDF-1.7 fejléc csak azt a funkciókészletet ígéri, amit az ISO 32000-1 2008-ban szabványosított, míg számos képesség, amelyre a PDF-előállítók ma támaszkodnak, ezt követően jelent meg, kizárólag Adobe-kiegészítésekként rétegezve ugyanarra a verziószámra. Az Adobe minden kiegészítést egy BaseVersion és ExtensionLevel párként regisztrált, a dokumentumkatalógus /Extensions szótárában rögzítve egy fejlesztői előtag alatt, ADBE a saját Adobe-kiegészítéseihez, így egy olvasó meg tudja különböztetni egy sima PDF 1.7-es fájlt egytől, amely egy számozott kiterjesztési szintet is megvalósít. A pv17-en való mentés e deklaráció nélkül önmagában nem hiba; csak akkor válik azzá, ha az aktív tartalom ténylegesen egy olyan funkciótól függ, amit a deklarációnak fedeznie kellene
Mely magas-verziójú funkciók váltják ki az explicit-verzió kaput?
A PDFiumPas egy konkrét, specifikáció-vezérelt listát ellenőriz, nem pedig csak a verziószámból találgat. A kép-szótárak, amelyek explicit /SMaskInData bejegyzést vagy 16-os /BitsPerComponent értéket hordoznak, mindkettő PDF 1.5-öt igényel, a tizenhat bites eset közvetlenül a PDF Reference 1.5 4.8. szakaszának kép-komponens szabályait követve. A RichMedia-annotációk és a RichMediaExecute akciók /BaseVersion /1.7-et igényelnek /ExtensionLevel 3-mal vagy magasabbal. A PRC 3D-streamek, amelyeket egy olyan szótár azonosít, amely mind /Type /3D-t, mind /Subtype /PRC-t hordoz, ugyanazt a bázisverziót igénylik, de csak /ExtensionLevel 1-et. A geotérbeli Measure szótárak és Projection-annotációk /BaseVersion /1.7-et igényelnek /ExtensionLevel 3-mal, ugyanaz az Adobe-kiegészítés, amitől a RichMedia is függ
A geotérbeli ellenőrzés egy specifikáció-olvasási részletet hordoz, amit érdemes ismerni, ha valaha is saját verzió-kapuzott logikát építesz a PDFiumPas tetejére. Az ISO 32000-1 254. táblázata opcionálisként jelöli meg a Measure szótár /Type bejegyzését, csak azt megjegyezve, hogy "ha jelen van, Measure-nek kell lennie", míg a 311. táblázat kötelezővé teszi a /Type-ot a 3D-stream szótárhoz, amelyben a PRC-tartalom él. A térképészeti eszközök valós GeoPDF-kimenete rutinszerűen kihagyja a /Type-ot a Measure szótáron, és csak /Subtype /GEO-t ír, így a PDFiumPas geotérbeli detektora csak a /Subtype-ra illeszkedik, nem pedig mindkét kulcsot igényli úgy, ahogyan a PRC 3D detektora biztonságosan megteheti. Ha mindkét szótáron megkövetelnénk a /Type-ot, az hagyta volna, hogy a szabványkövető GeoPDF-tartalom felismerés nélkül átcsússzon a kapun, egy sima PDF 1.7-es fájlban landolva, semmilyen kiterjesztésiszint-deklaráció nélkül, amely alátámasztaná
Automatikusan leértékeli a PDFiumPas a nem támogatott funkciókat?
Nem általános képességként, és annak feltételezése az a hiba, amit itt el kell kerülni. A SaveAs a célverziót egy belső rutinon keresztül tölcsérezi, a ValidatePdfVersionCompliance-en, és amikor az a rutin talál egy funkciót, amit a célverzió vagy annak kiterjesztésiszint-deklarációja nem tud támogatni, a SaveAs kivételt dob, amely hordozza a rutin hibaszövegét, ahelyett hogy megírná a fájlt; a hívó pontos, funkció-nevesített indoklást kap vissza, soha nem egy csendben átírt dokumentumot. Az egyetlen hely, ahol a PDFiumPas automatikusan átírja a tartalmat, egy PDF 1.3-as cél, ahol eltávolítja a szemantikailag semleges /BM /Normal, /CA 1, és /ca 1 átlátszóság-alapértelmezéseket, amiket a PDFium mindig beleír az ExtGState szótárakba, függetlenül a célverziótól, mert ezek a konkrét értékek semmilyen vizuális jelentést nem hordoznak, és a PDF 1.3 teljesen megelőzi a kulcsokat
// 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
A valódi, nem-alapértelmezett átlátszóság és kép-lágymaszkok még mindig teljesen elbuknak egy PDF 1.3-as célnál, mert eltávolításuk megváltoztatná, hogyan néz ki ténylegesen az oldal, és a PDFiumPas nem hozza meg ezt a döntést helyetted. Két rokon korlátot érdemes megtervezni, mielőtt egy pontos verzió bekerül egy kötegelt csővezetékbe. Az explicit-verziójú kimenet soha nem hordoz /Encrypt szótárat; a mentés azonnal elbukik, ha a forrás védett, ami véletlenül illeszkedik a PDF/X- és PDF/A-profilokhoz, amelyek amúgy is tiltják a titkosítást, de azt jelenti, hogy a visszafejtés egy külön lépés a munkafolyamatodban, nem valami, amit a SaveAs megtesz neked. A PDFiumPas-nak nincs nyilvános metódusa egy /Extensions /ADBE deklaráció egy katalógusra írásához sem, így egy forrásfájl, amely RichMedia-, PRC 3D-, vagy geotérbeli tartalmat tartalmaz, de nem rendelkezik azzal a deklarációval, nem fog átjutni a kapun, bármilyen PdfVersion-t is kérsz; a deklarációnak már léteznie kell a forrásban, jellemzően azért, mert a szerzői eszköz megírta, vagy a funkciónak ki kell kerülnie a mentés előtt. A csak-olvasható TPdf.PdfVersion tulajdonságot érdemes ellenőrizni, mielőtt egyáltalán megkísérelnénk egy pontos-verziós mentést, mivel ugyanazt a katalógus-tudatos hatékony verziót oldja fel, a fejléc vagy a /Version felülbírálás, bármelyik is aktuális, amire maga a mentés-idejű érvényesítő is támaszkodik
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);
Kezeld a SaveAs kivételt egy pontos-verziós cél esetén preflight jelentésként, ne hibaként: az üzenet megnevezi a pontos záradékot, amit a forrásdokumentum megsért, ami pontosan az az információ, amire egy nyomdának vagy archiváló csővezetéknek szüksége van, mielőtt egy fájl tovább megy. Az itt leírt explicit-verziós mentési útvonal, az aktív xref-revízió-feloldó, és az Adobe Extension Level ellenőrzések a Delphihez és C++Builderhez készült szabványos PDFiumPas Komponens részeként érkeznek; a termékoldal hordozza a teljes TPdf.SaveAs referenciát a megfelelőségi és form-API többi részével együtt