Teknisk artikkel

Eksakte PDF-versjonslagringer i Delphi: PDFiumPas-konformitet

PDFiumPas, Delphi- og C++Builder-wrapperen rundt Googles PDFium-motor, lagrer et dokument ved en eksakt PDF-versjon fra 1.3 til 1.7 gjennom TPdf.SaveAs-metodens PdfVersion-parameter. PDFiums egen FPDF_SaveWithVersion-kall skriver bare om %PDF-M.m-headeren, uten å sjekke om dokumentets faktiske innhold er lovlig ved den versjonen. PDFiumPas lukker det gapet med en etter-lagring-konformitetspassering som går gjennom den aktive kryssreferanse-revisjonskjeden og sjekker Adobe Extension Level-deklarasjoner før filen forlater metoden

Det skillet betyr mest i trykkeriproduksjon, der en PDF/X-profil navngir en eksakt PDF-versjon og et preflight-verktøy eller en RIP avviser alt som stille er uenig med sin egen header, et scenario dekket fra utdatasiden i å validere trykkeklare PDF/X-dokumenter med PDFiumPas. SaveAs eksponerer målet som TPdfVersion-enumen, pv13 til pv17 ved siden av de eldre pv10-til-pv12-verdiene, pluss en uavhengig TSaveOption for inkrementelle eller fulle omskrivinger. Send PdfVersion, og PDFiumPas gjør to jobber i ett kall: den ber PDFium stemple den forespurte headeren, leser deretter de ferskt skrevne bytene på nytt og nekter å overlevere en fil hvis aktive innhold ikke lovlig kan eksistere ved den versjonen

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;

Hvorfor er den siste objektdefinisjonen i filen feil ting å stole på?

Det siste fysiske objektet med et gitt nummer i en PDF-fil er ikke nødvendigvis objektet en konform leser ville løst for det nummeret i dag. En PDF som har gått gjennom flere inkrementelle oppdateringer, har ikke én objektgraf, den har en historie av dem lagvis inne i én fil, og hver tilleggssyklus kan frigjøre et objekt, omdefinere det under et nytt generasjonsnummer, eller la den gamle fysiske kroppen dets bli liggende mellom to endobj-markører uten noen kryssreferanse-oppføring som peker på det lenger

PDFiumPas traff nøyaktig den feilmodusen før den sporet xref-revisjoner eksplisitt: en Redact-annotering foreldreløs gjort av en senere side-objekt-omskriving, eller en /MarkInfo-ordbok latt fysisk til stede uten noen xref-oppføring som peker på den, kunne fortsatt dukke opp i en byte-skanning og fortsatt utløse en versjons-funksjons-sjekk som ikke lenger gjaldt for dokumentet en leser faktisk ville åpne. Feilretningen var falsk avvisning, ikke falsk aksept: en fil som genuint hadde beveget seg forbi en funksjon i sin gjeldende revisjon, kunne fortsatt bli blokkert fra å lagre ved en lavere versjon på grunn av innhold ingen lenger kunne nå

Hvordan avgjør PDFiumPas hvilke objektdefinisjoner som faktisk er aktive?

PDFiumPas løser det aktive objektsettet på samme måte som en konform leser gjør, ved å gå gjennom kryssreferansekjeden i stedet for å skanne byte etter objektheadere. Løseren starter ved den siste startxref-forskyvningen i filen og følger hver /Prev-lenke bakover gjennom eldre revisjoner, og parser klassiske kryssreferansetabeller, hybride /XRefStm-lenkede strømmer, og rene kryssreferansestrømmer underveis. Gjennomgangen kjører nyest-til-eldst og avgjør hvert objektnummer første gang det sees, slik at en fri oppføring i en senere revisjon korrekt overskygger en objektkropp skrevet i en tidligere, og en omdefinering under en ny forskyvning eller generasjon vinner alltid over det den erstattet

Objektstrøm-medlemmer får en ekstra sjekk et rent forskyvningsoppslag ikke kan gi på egen hånd, en mekanisme dekket mer i dybden i å validere objekt- og kryssreferansestrømmer med PDFiumPas. Et komprimert objekt gjenopprettet fra en /ObjStm må ha sin overordnede strøm bekreftet aktiv i den samme gjennomgangen, og indeksen dets må stemme overens med medlemmets egen posisjon inne i den strømmens header før PDFiumPas behandler det som levende innhold. ISO 32000-1 avsnitt 7.5.8.4 beskriver til og med et hybrid-referanse-tilfelle der en klassisk kompatibilitetstabell markerer et objekt fritt mens trailerens /XRefStm-oppføring samtidig definerer det samme objektet som et komprimert medlem et annet sted; PDFiumPas fletter den supplerende xref-strømmen inn i den samme revisjonen før de klassiske oppføringene anvendes, slik at den komprimerte definisjonen vinner slik spesifikasjonen tilsier

Adobe Extension Levels: sperren over versjonsnummeret

En %PDF-1.7-header lover bare funksjonssettet ISO 32000-1 standardiserte i 2008, mens flere muligheter PDF-produsenter er avhengige av i dag, ble levert etterpå som Adobe-eksklusive tillegg lagt oppå det samme versjonsnummeret. Adobe registrerte hvert tillegg som et BaseVersion- og ExtensionLevel-par registrert i dokumentkatalogens /Extensions-ordbok under et utviklerprefiks, ADBE for Adobes egne utvidelser, slik at en leser kan skille en ren PDF 1.7-fil fra en som også implementerer et nummerert utvidelsesnivå. Å lagre ved pv17 uten den deklarasjonen er ikke en feil i seg selv; det blir først en feil i det øyeblikket det aktive innholdet faktisk avhenger av en funksjon deklarasjonen er ment å dekke

Hvilke høyversjons-funksjoner utløser den eksplisitte-versjon-sperren?

PDFiumPas sjekker en spesifikk, spesifikasjonsdrevet liste snarere enn å gjette bare fra versjonsnummeret. Bildeordbøker som bærer en eksplisitt /SMaskInData-oppføring eller en /BitsPerComponent-verdi på 16, krever begge PDF 1.5, med seksten-bit-tilfellet som følger PDF Reference 1.5 avsnitt 4.8s bildekomponent-regler direkte. RichMedia-annoteringer og RichMediaExecute-handlinger krever /BaseVersion /1.7 med /ExtensionLevel 3 eller høyere. PRC 3D-strømmer, identifisert ved en ordbok som bærer både /Type /3D og /Subtype /PRC, krever den samme basisversjonen, men bare /ExtensionLevel 1. Geospatiale Measure-ordbøker og Projection-annoteringer krever /BaseVersion /1.7 med /ExtensionLevel 3, det samme Adobe-tillegget RichMedia avhenger av

Den geospatiale sjekken bærer en spesifikasjonslesnings-detalj verdt å kjenne til hvis man noensinne bygger sin egen versjons-sperrede logikk oppå PDFiumPas. ISO 32000-1 Tabell 254 markerer Measure-ordbokens /Type-oppføring som valgfri, og bemerker bare at «hvis til stede, skal være Measure», mens Tabell 311 gjør /Type obligatorisk for 3D-strøm-ordboken PRC-innhold bor i. Virkelig GeoPDF-utdata fra kartleggingsverktøy utelater rutinemessig /Type på Measure-ordboken og skriver bare /Subtype /GEO, så PDFiumPas' geospatiale detektor matcher på /Subtype alene i stedet for å kreve begge nøklene slik PRC 3D-detektoren dets trygt kan. Å kreve /Type på begge ordbøkene ville latt konformt GeoPDF-innhold smette forbi sperren uoppdaget, og landet i en ren PDF 1.7-fil uten noen utvidelsesnivå-deklarasjon til å støtte det

Nedgraderer PDFiumPas automatisk ustøttede funksjoner?

Ikke som en generell mulighet, og å anta noe annet er feilen å unngå her. SaveAs kanaliserer målversjonen gjennom en intern rutine, ValidatePdfVersionCompliance, og når den rutinen finner en funksjon målversjonen eller dens utvidelsesnivå-deklarasjon ikke kan støtte, kaster SaveAs et unntak som bærer rutinens feiltekst i stedet for å skrive filen; kalleren får en presis, funksjonsnavngitt grunn tilbake, aldri et stille omskrevet dokument. Det ene stedet PDFiumPas faktisk skriver om innhold automatisk, er et PDF 1.3-mål, der den fjerner de semantisk nøytrale /BM /Normal-, /CA 1-, og /ca 1-transparens-standardverdiene PDFium alltid skriver inn i ExtGState-ordbøker uansett målversjon, fordi de spesifikke verdiene ikke bærer noen visuell mening og PDF 1.3 går forut for nøklene fullstendig

// 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

Genuin ikke-standard transparens og bilde-softmasker feiler fortsatt rett ut ved et PDF 1.3-mål, fordi å fjerne dem ville endre hvordan siden faktisk ser ut, og PDFiumPas vil ikke ta den avgjørelsen på dine vegne. To relaterte grenser er verdt å planlegge rundt før en eksakt versjon går inn i en batch-pipeline. Eksplisitt-versjon-utdata bærer aldri en /Encrypt-ordbok; lagringen feiler umiddelbart hvis kilden er beskyttet, noe som tilfeldigvis stemmer overens med PDF/X- og PDF/A-profiler som forbyr kryptering uansett, men det betyr at dekryptering er et separat trinn i arbeidsflyten din snarere enn noe SaveAs gjør for deg. PDFiumPas har heller ingen offentlig metode for å skrive en /Extensions /ADBE-deklarasjon inn på en katalog, så en kildefil som inneholder RichMedia-, PRC 3D-, eller geospatialt innhold, men mangler den deklarasjonen, vil ikke passere sperren uansett hvilken PdfVersion du forespør; deklarasjonen må allerede finnes i kilden, typisk fordi forfatterverktøyet skrev den, eller funksjonen må fjernes før lagringen. Den skrivebeskyttede TPdf.PdfVersion-egenskapen er verdt å sjekke før et eksakt-versjon-lagringsforsøk i det hele tatt gjøres, ettersom den løser den samme katalog-bevisste effektive versjonen, header eller /Version-overstyring, hvilken som enn er gjeldende, som selve lagringstids-validatoren er avhengig av

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);

Behandle et SaveAs-unntak på et eksakt-versjon-mål som en preflight-rapport snarere enn en bug: meldingen navngir den eksakte klausulen kildedokumentet bryter, noe som er nøyaktig informasjonen et trykkeri eller en arkivpipeline trenger før en fil går noe videre. Den eksplisitt-versjon-lagringsveien, den aktive xref-revisjons-løseren, og Adobe Extension Level-sjekkene beskrevet her, følger med som en del av den standard PDFiumPas-komponenten for Delphi og C++Builder; produktsiden bærer den fulle TPdf.SaveAs-referansen sammen med resten av konformitets- og skjema-API-et