Kirjoitat (You write a) pienen (small validator. It) validaattorin. Se avaa (opens a PDF, seeks) PDF:n, etsii tiensä (to the end, finds) loppuun, löytää (startxref, reads) startxref-sanan, lukee (the offset, and) siirtymän ja odottaa päätyvänsä avainsanaan (expects to land on the keyword) xref (xref with a), jonka (fixed-width cross-reference table) alla on (beneath it. From) kiinteäleveyksinen ristiviittaustaulukko. Tuosta (that table it) taulukosta (collects object) se kerää objektien (offsets, then) siirtymät ja selaa sitten taaksepäin (scans backward for) trailer-avainsanaa (the trailer keyword to) saadakseen (learn the) selville (/Root and) /Root- (/Size. It) ja /Size-arvot (works perfectly). Se toimii (on every file) täydellisesti (you generated to) jokaisella (test it. Then) tiedostolla, jonka olet luonut testataksesi (a file produced by a) sitä. Sitten (current version of) saapuu (Word, or by a library) tiedosto, jonka on (that targets PDF) tuottanut Wordin (1.5, arrives, and) nykyinen versio (the validator) tai kirjasto, joka kohdistuu (declares it) PDF (broken. There) 1.5 -versioon, ja validaattori (is no) julistaa sen (xref keyword) rikkinäiseksi. Siellä ei ole (where the offset) xref-avainsanaa, johon (points, no trailer) siirtymä osoittaa (dictionary anywhere), ei trailer-sanakirjaa (and the) missään, ja (object table the) validaattorin rakentama objektitaulukko on (validator built is) lähes (nearly empty. The) tyhjä. Tiedosto on (file is) pätevä (valid. The). Validaattori lukee (validator is) sitä viisitoista vuotta (reading it) vanhan (through a fifteen-year-old) linssin läpi (lens)
Tämä (This is the) on (single most) yleisin yksittäinen (common reason a byte-level) syy siihen, miksi (PDF check) klassista asettelua (written against) vastaan kirjoitettu (the classic layout) tavutason (fails on) PDF-tarkistus (modern documents. The) epäonnistuu moderneissa asiakirjoissa (structure it). Rakenne, josta se riippuu (depends on, the), selkokielinen ristiviittaustaulukko (plaintext cross-reference table) ja trailer-avainsana (and the trailer keyword, was), muutettiin valinnaisiksi (made optional) PDF (in PDF) 1.5 -versiossa, ja ne puuttuvat (1.5 and is) usein (frequently absent. Two). Kaksi (features replaced) ominaisuutta korvasi sen: ristiviittausvirta (it: the cross-reference stream) ja pakattu objektivirta (and the compressed object stream. Both). Molemmat on (are described) kuvattu (in ISO) ISO 32000-1 -standardissa (32000-1, and), ja validaattori, joka ei tiedä (a validator that does) niistä (not know about), näkee terveen tiedoston (them sees a) puuttuvien objektien kasana (healthy file as a heap of missing objects)
Mitä (What PDF) PDF (1.5 changed) 1.5 (about the file) muutti tiedoston hännästä (tail)
ISO 32000-1 §7.5.8 määrittelee (defines the cross-reference) ristiviittausvirran (stream, and), ja §7.5.7 määrittelee (defines the object) /ObjStm-tyyppisen (stream of type /ObjStm. Together) objektivirran. Yhdessä ne (they let) antavat kirjoittajalle (a writer) mahdollisuuden jättää (drop the) pois (two structures a) kaksi (classic parser keys) rakennetta (on. A PDF 1.5), joihin klassinen (file may) jäsennin nojautuu. PDF 1.5 (end with no xref) -tiedosto voi päättyä ilman (table at all. In) minkäänlaista xref-taulukkoa. Sen tilalla (its place, the) objekti, johon (object that startxref) startxref osoittaa (points to is), on tavallinen (an ordinary) virtakohde (stream object whose), jonka sanakirjassa on (dictionary carries /Type) /Type /XRef, ja tuo virta (/XRef, and that) pitää ristiviittaustietoja kompaktissa (stream holds the) binäärimuodossa. Myöskään (cross-reference data in a compact binary form. There is) trailer-avainsanaa (no trailer) ei ole (keyword either), koska (because the) traileri on nyt virran (trailer is now) oma (the stream's own) sanakirja. Avaimet, joita klassinen jäsennin metsästi (dictionary. The keys a classic parser hunted for,), /Root, /Size ja (and /ID) /ID, asuvat (live inside) tuon sanakirjan sisällä (that dictionary)
Toinen muutos siirtää (The second change moves) itse objektit (the objects themselves. Instead). Sen sijaan, että jokainen epäsuora (of writing every indirect) objekti kirjoitettaisiin omalle (object at its) tavusiirtymälleen (own byte offset), kirjoittaja (a writer) voi (can pack) pakata monta pientä (many small) objektia (objects, the), sivusanakirjat (page dictionaries), merkintäsanakirjat, rakennepuun (the annotation dictionaries, the structure tree) yhteen (into a single) objektivirtaan (object stream and) ja (compress the) pakata (whole container) koko säilön Flate-algoritmilla (with Flate. The). Yksittäisillä objekteilla (individual objects no) ei enää ole (longer have a) tavusiirtymää tiedostossa (byte offset in). Niillä (the file. They) on sijainti (have a position) pakatun möykyn (inside a compressed blob. A) sisällä. Validaattori, joka skannaa (validator scanning the) raakatavuja etsien (raw bytes for) 1 0 obj -merkkijonoa, ei (never finds) koskaan (them, because) löydä niitä, koska (that text) tuo teksti on olemassa (only exists) vasta (after inflation. To) purkamisen jälkeen. Klassiselle jäsentimelle puolet (a classic parser, half) asiakirjasta (the document has) on yksinkertaisesti (simply vanished) kadonnut (vanished)
Traileriavaimet ovat (The trailer keys are) selkotekstiä, jopa pakatussa tiedostossa (plaintext, even in a compressed file)
Rauhoittava (The reassuring part) osa (is that) on, että (reading the trailer) ristiviittausvirran trailerin (of a cross-reference stream) lukeminen (does not require) ei vaadi minkään (inflating anything. A) purkamista. Virtakohde (stream object is) kirjoitetaan (written as a) sanakirjana, jota seuraa (dictionary followed by the) stream-avainsana ja (stream keyword and) sitten pakatut (then the compressed) tavut. Sanakirja (bytes. The dictionary) on selkotekstiä (is plaintext. So). Joten kun (when startxref points) startxref osoittaa (at a cross-reference stream) ristiviittausvirtaan, tavut heti (the bytes immediately) objektinumeron jälkeen näyttävät (after the object number look like) tavalliselta (an ordinary) sanakirjalta, ja (dictionary, and) /Root, /Size ja (and /ID) /ID istuvat siellä selvänä (sit there in the clear), ennen (before the) stream-avainsanaa ja (stream keyword and the) Flate-datan alkamista (Flate data begin)
Tämä (That means a) tarkoittaa, että validaattori voi (validator can learn) oppia (the three) kolme (facts it) faktaa, joita se (most needs, where) eniten (the catalog is) tarvitsee: missä luettelo on, kuinka (how many) monta (objects the file) objektia tiedosto väittää sisältävänsä, ja tiedostotunnisteen, vain (claims, and the) jäsentämällä virtasanakirjan (file identifier, by parsing only the stream dictionary. It). Sen ei tarvitse (does not have to) purkaa ristiviittaustietoja (decompress the cross-reference), eikä (data, and it) sen (does not have to) tarvitse tulkita (interpret the binary) sen sisällä olevia binäärimerkintöjä (entries inside it. The). Työ, joka nujertaa (work that defeats a) naiivin (naive parser) jäsentimen, ei (is not reading) ole trailerin (the trailer; it) lukeminen; se on objektien löytäminen (is finding the objects. Those). Nämä (are two) ovat kaksi erillistä ongelmaa, ja (separable problems, and solving the) ensimmäisen (first is) ratkaiseminen on halpaa (cheap)
Objektivirrat (Object streams: a header): otsikko, sitten (then a) Flate-möykky (Flate blob)
Objektivirta on säilö (An object stream is a container. Its). Sen sanakirjassa on (dictionary carries /Type /ObjStm) /Type /ObjStm, /N-merkintä, joka antaa (an /N entry giving the) sisään (number of) pakattujen (objects packed) objektien määrän (inside, and a), ja /First-merkintä, joka antaa tavusiirtymän (First entry giving the byte offset), puretun datan (within the inflated) sisällä, josta (data, where the) ensimmäisen objektin (first object's body starts) runko (starts. The) alkaa. Pakattu (compressed payload) hyötykuorma (once inflated) alkaa (begins with a) purkamisen jälkeen pienellä otsikolla, joka (small header of /N) koostuu /N:stä (integer pairs. Each pair) kokonaislukuparista. Jokainen (is an) pari on objektinumero ja (object number and the) kyseisen objektin (offset of) rungon (that object's body relative) siirtymä suhteessa /First-arvoon (to /First. After). Otsikon (the header) jälkeen (come the object) tulevat itse (bodies themselves, concatenated) objektien rungot peräkkäin yhdistettyinä (concatenated)
Sellaisen (Expanding one is) laajentaminen (mechanical once) on mekaanista (the bytes are), kun (inflated. You read) tavut (the dictionary to get) on purettu. Luet (N and /First, inflate) sanakirjan (the stream with) saadaksesi (a Flate decoder, walk) /N- (the leading /N) ja (pairs to) /First-arvot, purat virran (learn which object) Flate-dekooderilla (number lives), käyt läpi johtavat (at which offset, and then) /N-parit oppiaksesi (lift each), mikä (body out) objektinumero (as if) asuu (it were) missäkin siirtymässä, ja (an ordinary indirect) sitten (object. The) nostat jokaisen rungon (only real dependency) ulos (is the) ikään kuin (Flate decoder, and) se (you already) olisi (have one:) tavallinen epäsuora (Delphi ships) objekti. Ainoa todellinen riippuvuus on (System.ZLib, and) Flate-dekooderi (Free Pascal ships the), ja sinulla on jo sellainen (zstream unit, both): Delphi (of which wrap zlib and) toimittaa (inflate a) System.ZLib-yksikön (raw Flate stream), ja Free Pascal (without any third-party code. A) toimittaa zstream-yksikön (routine that appends), jotka molemmat kietovat (every extracted object) zlibin (to the validator's object) ja purkavat raa'an Flate-virran ilman mitään (table makes the rest of) kolmannen osapuolen koodia. Rutiini, joka liittää jokaisen puretun objektin validaattorin objektitaulukkoon (the validator, the part that walks /Root and checks the page tree, behave exactly as it would on a classic file), saa (makes) validaattorin loppuosan (the rest of the validator), osan, joka käy läpi (the part that walks) /Root-arvon ja tarkistaa (and checks the) sivupuun, käyttäytymään aivan (page tree, behave exactly as) samalla tavalla kuin se käyttäytyisi (it would on a) klassisessa (classic file) tiedostossa (file)
Mitä (What you do not have to implement) sinun ei tarvitse (have to) toteuttaa (implement)
Työmäärää (It is easy) on helppo yliarvioida (to overestimate the work. Reading). Traileriavaimien lukeminen pakatusta tiedostosta (the trailer keys from a compressed file does) ei vaadi ristiviittausvirran binäärimerkintöjen dekoodaamista (not require decoding the cross-reference stream's binary entries. The). §7.5.8-ristiviittausvirta (cross-reference stream uses) käyttää kolmea (three entry types) merkintätyyppiä (and the), ja tyypin (type 2) 2 merkintä, se (entry, the one), joka sanoo (that says) tämä objekti (this object) asuu objektivirran (lives inside object stream) N sisällä indeksissä (N at index) i
(i), on se (is what), jonka dekoodaisit täyden (you would decode to) siirtymäkartan (build a full offset) rakentamiseksi (map. You need). Tarvitset tuota (that map to) karttaa mielivaltaisten (resolve arbitrary objects) objektien ratkaisemiseen (by number. You do) numerolla. Et (not need it) tarvitse (to read /Root) sitä (Size and /ID) lukeaksesi /Root-, /Size- ja /ID-arvot (which are in the), jotka (plaintext dictionary, and you) ovat selkotekstisanakirjassa, etkä tarvitse (do not need it to) sitä (expand object) objektivirtojen (streams, because) laajentamiseen (each /ObjStm), koska (announces its own contents through) jokainen (N and /First) /ObjStm ilmoittaa omasta sisällöstään /N- ja /First-arvojen kautta
Sinun (You also do not have to) ei myöskään tarvitse käsitellä (handle the) PNG- (PNG and TIFF predictor) ja TIFF-ennustinfunktioita (functions that a), joita ristiviittausvirta (cross-reference stream may apply through) voi (its /DecodeParms) soveltaa /DecodeParms-parametrin kautta (just to get the trailer keys. Predictors) vain traileriavaimien (filter the binary) saamiseksi. Ennustimet (cross-reference rows to make them) suodattavat binäärisiä ristiviittausrivejä (compress better;) saadakseen (they have nothing) ne pakkautumaan (to do) paremmin; niillä (with the dictionary) ei (that precedes) ole mitään (the stream. The minimal) tekemistä virtaa (upgrade that) edeltävän sanakirjan kanssa (makes a classic validator modern-PDF aware is). Minimaalinen (therefore small: when startxref) päivitys (lands on a), joka (stream rather than the xref keyword) tekee (parse the stream dictionary) klassisesta (for the trailer keys, and expand) validaattorista (any /ObjStm) modernista (objects you encounter) PDF:stä (so their contents) tietoisen, on siksi (enter the object) pieni: kun (table. Decoding) startxref päätyy (type 2) virtaan xref-avainsanan (entries and) sijaan (predictors is a), jäsennä (separate, larger task you can) virtasanakirja (defer until you) traileriavaimia varten, ja laajenna (genuinely need random) kohtaamasi /ObjStm-objektit (object resolution), jotta niiden sisältö (so their contents enter the) pääsee (object table) objektitaulukkoon. Tyypin 2 (Decoding type 2 entries and predictors is a separate, larger task you can defer until you genuinely need random object resolution) merkintöjen (entries and) ja ennustimien (predictors is a) dekoodaus (Decoding type 2 entries and predictors) on (is a) erillinen (separate, larger task), suurempi tehtävä (larger task), jota voit lykätä (you can defer), kunnes todella tarvitset (until you genuinely need) satunnaista (random object) objektinratkaisua (resolution)
Miksi (Why a compliance check must expand) vaatimustenmukaisuuden tarkistuksen (compliance check) on laajennettava (must expand streams) virrat ensin (first)
Tämä (This stops being) lakkaa olemasta (academic the) akateemista (moment you) heti, kun suoritat (run a profile) profiilitarkistuksen (check. A). PDF/A- (PDF/A or) tai PDF/X-validaattori (PDF/X validator inspects) tarkastaa tiettyjä (specific objects:) objekteja: (the document catalog) asiakirjan (for an) luettelon /OutputIntents-taulukon (OutputIntents array) varalta, /Metadata-virran (the /Metadata stream for an) XMP-paketin varalta (XMP packet with), jolla (the right identifier, every) on oikea tunniste, jokaisen fonttikuvauksen (font descriptor for) upotetun fonttitiedoston varalta (an embedded font), trailerin (file, the trailer) /ID-arvon varalta (for an /ID. In a). Pakatussa (compressed file) tiedostossa useimmat noista (most of those) objekteista ovat (objects are inside) objektivirtojen (object streams. A) sisällä. Validaattori, joka (validator that) ei (has not) ole (expanded the) laajentanut objektivirtoja (object streams cannot), ei voi nähdä (see the) luettelon (catalog's keys) avaimia, ei (cannot find) löydä metadataa (the metadata, and cannot) eikä (enumerate the fonts. It) voi luetella (will report) fontteja. Se raportoi, että täysin (a perfectly conformant document as) vaatimustenmukaisesta asiakirjasta (missing its output) puuttuu (intent, missing) tulostustarkoitus (its XMP), XMP (and missing) ja puolet (half its) sen (structure, because) rakenteesta (the evidence it), koska (needs is) todisteet (still sitting) joita (in a) se tarvitsee (Flate blob it) istuvat (never inflated) yhä (still sitting in a Flate) Flate-möykyssä (blob it never inflated), jota se (it never) ei koskaan (inflated) purkanut
Järjestyksellä on väliä (The order matters. Expansion). Laajennuksen on (has to happen) tapahduttava (before the checks) ennen (run, not alongside) tarkistusten (them, because every) suorittamista, ei (check assumes it) niiden (can reach) rinnalla (an object by number. If), koska jokainen (you wire a profile) tarkistus olettaa voivansa saavuttaa (check directly onto) objektin (a raw byte scan) numerolla (it inherits). Jos kytket (the classic) profiilitarkistuksen (parser's blindness) suoraan raakatavujen (and produces) skannaukseen (false violations on), se (exactly the) perii (modern files) klassisen jäsentimen sokeuden (that are most) ja (likely to) tuottaa (be well) vääriä (formed, since) rikkomuksia (they came) juuri (out of) nykyaikaisissa (toolchains new enough) tiedostoissa (to write), jotka (cross-reference streams) ovat todennäköisimmin hyvin (in the) muodostettuja, koska (first place) ne (since they came out of) tulivat (toolchains new enough to) työkaluputkista (toolchains), jotka ovat tarpeeksi (new enough to) uusia (write cross-reference) kirjoittaakseen (streams in) ristiviittausvirtoja ylipäänsä (the first place)
Anna (Letting PDFium do) PDFiumin tehdä (the parsing for) jäsennys puolestasi (you)
PDFium (The PDFium Component) Component -komponentti jäsentää ristiviittausvirrat (parses cross-reference streams and) ja objektivirrat (object streams as) osana asiakirjan lataamista, mikä on (part of loading a document, which is the) käytännöllinen (practical way to) tapa välttää purkamis- ja laajentamisvaiheen (avoid hand-rolling the inflate-and-expand) tekeminen käsin (step. When you). Kun (load a file) lataat tiedoston (with the TPdf) TPdf-komponentilla (component, the), /ObjStm-säilöihin pakatut objektit (objects packed into /ObjStm containers) on jo ratkaistu (are already resolved), ja (and the) validointialoituspisteet (validation entry points) näkevät (see the) täysin laajennetun (fully expanded document.) asiakirjan. ValidatePdfA palauttaa (ValidatePdfA returns a) TPdfAValidationResult-tietueen, jonka (TPdfAValidationResult record whose) Conformance-kenttä (Conformance field is) on TPdfAConformance-arvo (a TPdfAConformance value), kuten (such as) pac1b tai pacNone (pac1b or pacNone,), jonka Issues-kenttä on (whose Issues) joukko löydetyistä (field is a set of the) erityisistä (specific problems) ongelmista (found, and whose), ja (IsCompliant method) jonka (is true only) IsCompliant-metodi on (when a) tosi (conformance level) vain, kun (was detected) vaatimustenmukaisuustaso havaittiin ja ongelmajoukko (and the issue) on (set is empty. Because) tyhjä. Koska objektit laajennettiin latauksen (the objects were expanded during load) aikana, objektivirran (an /OutputIntents array) sisällä asuva (or an embedded) /OutputIntents-taulukko (font that lived) tai upotettu fontti (inside an object stream is) löydetään (found, not), ei raportoida (reported missing) puuttuvana
uses
PDFium, FPdfPdfa;
function CheckPdfA(const FileName: string): TPdfAValidationResult;
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True; // jäsentää xref/objektivirrat ladattaessa
// parses xref/object streams on load
Result := Pdf.ValidatePdfA; // näkee laajennetun objektitaulukon
// sees the expanded object table
finally
Pdf.Free;
end;
end;
Sama koskee (The same applies to) ValidatePdfX-metodia (ValidatePdfX, which), joka palauttaa samannäköisen (returns a TPdfXValidationResult) TPdfXValidationResult-tietueen (with the same shape. The). PDFiumin kautta reitittämisen (point of routing) pointti on, että (through PDFium is that) yllä kuvattu rakenteellinen (the structural decompression) dekompressio tapahtuu (described above happens) kerran (once, correctly, inside), oikein (the loader, so), lataajan sisällä, joten validointikoodisi (your validation code never) ei koskaan (sees the) näe eroa klassisen tiedoston ja (difference between a classic file and a) täysin pakatun tiedoston (fully compressed one. Both) välillä. Molemmat (arrive at the) saapuvat (validator as) validaattoriin ratkaistuna objektijoukkona (a resolved set of objects)
function PdfXConformanceName(C: TPdfXConformance): string;
begin
case C of
pxc1a: Result := 'PDF/X-1a';
pxc3 : Result := 'PDF/X-3';
pxc4 : Result := 'PDF/X-4';
else
Result := 'ei mitään (none)';
end;
end;
var
Pdf: TPdf;
R : TPdfXValidationResult;
Issue: TPdfXValidationIssue;
IssueCount: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'Press_Ready.pdf';
Pdf.Active := True;
R := Pdf.ValidatePdfX;
if R.IsCompliant then
Writeln('PDF/X-vaatimustenmukaisuus (PDF/X conformance: ): ', PdfXConformanceName(R.Conformance))
else
begin
IssueCount := 0;
for Issue in R.Issues do // Issues on joukko: laske sen jäsenet
// Issues is a set: count its members
Inc(IssueCount);
Writeln('Ei vaatimustenmukainen; ongelmien määrä (Not conformant; issue count =) = ', IssueCount);
end;
finally
Pdf.Free;
end;
end;
Jos tavut ovat jo (If the bytes are) muistissa levyn sijaan (already in memory rather than on disk, the), sama lataa-sitten-validoi-sekvenssi (same load-then-validate sequence works) toimii (through the) LoadDocument(const Data: TBytes) -ylikuormituksen kautta, joka (overload, which) ottaa raa'an (takes the raw) tiedostosisällön (file content) ja jäsentää (and parses its) sen ristiviittaus- (cross-reference and) ja objektivirrat samalla (object streams the same) tavalla (way the) kuin (file path) tiedastopolkukin (does. The). Opetus (takeaway for) käsin kirjoitetulle (a hand-written validator) validaattorille (is the structural) on rakenteellinen (rule, not the) sääntö (API: read), ei (the trailer keys from) API: lue traileriavaimet virtasanakirjasta (the stream dictionary) selkotekstinä (in plaintext, expand), laajenna jokainen (every /ObjStm) /ObjStm Flate-dekooderilla ennen kuin (with a Flate decoder before you) käyt asiakirjan läpi (walk the document, and), ja (treat decoding the) käsittele binääristen ristiviittausmerkintöjen dekoodausta sinä suurempana (binary cross-reference entries as the larger, optional), valinnaisena työnä, joka se (job it) on (is)
Kun rakenne (Once the structure) on (is expanded, a) laajennettu, validaattori voi ajaa loput (validator can drive the rest of a workflow) työnkuluista (over it. For) sen (a command-line) yli. Komentoriviltä toimivaan (preflight harness) preflight-valjastukseen (that reports conformance), joka (across a folder) raportoi vaatimustenmukaisuuden koko (of inputs, see) syötekansiosta (our walkthrough on), katso läpikäyntimme (building a batch) eräajona toimivan preflight-raportin (preflight report CLI) komentorivisovelluksen (CLI) rakentamisesta. Kun validointi (When validation is) on portti ennen (a gate ahead of) suuren asiakirjan rikkomista osiin, (breaking a large document apart, the techniques) oppaassamme (in our guide to) PDF-asiakirjojen (splitting PDF documents into) jakamisesta (multiple files) useisiin tiedostoihin olevat (pair naturally) tekniikat sopivat (with the) luonnollisesti yhteen tässä (load-and-check pattern shown here. Both) esitetyn lataa-ja-tarkista-kuvion (load-and-check pattern) kanssa. Molemmat perustuvat (build on the) Delphi- ja C++Builder-ohjelmointikieliin (loading and validation surface of the) tarkoitetun PDFium Component -komponentin (PDFium Component for Delphi and) lataus- ja validointipintaan (C++Builder)