ConvertToPDFA zet een gewoon document in één aanroep om in een archiefversie: het verwijdert wat het gekozen deel verbiedt, voegt toe wat het deel vereist, stelt het deel vast dat het document claimt, en controleert daarna het resultaat. De claim wordt alleen als voldaan gerapporteerd wanneer de controle slaagt, en GetPDFAConversionReport somt op wat is gedaan en wat nog in de weg staat
Die laatste eigenschap is de ontwerpbeslissing die de moeite van het overdenken waard is. Een converter die de claim stempelt zonder te controleren is erger dan helemaal geen converter, omdat een bestand dat zegt archief te zijn en dat niet is, rechtstreeks door de systemen glipt die het anders zouden hebben gevangen. De fout doemt jaren later op, in een audit, bij een document dat niemand meer kan regenereren
Waarom faalt een geldig uitziende PDF een PDF/A-controle?
Meestal omdat de twee plaatsen waar een PDF zegt wie hem schreef, het oneens zijn. Een validator leest zowel het document-information-dictionary als het XMP-pakket en wijst een bestand af waar ze verschillen — en de meeste bestanden die hierop falen, hebben gewoon nooit de XMP-helft gekregen
RepairDocumentMetadata brengt ze overeen en retourneert hoeveel entries het herstelde. Waar slechts één helft een waarde meedraagt, wordt de andere ermee gevuld, zodat niets van wat al was vastgelegd verloren gaat. Niemand hoeft te beslissen welke kopie gezaghebbend is, want in de praktijk is één kopie leeg
Een tweede reparatie in dezelfde aanroep vangt een subtieler geval. Een document dat in een PDF/A-mode staat, krijgt zijn standaardidentificatie terug indien die verloren was, wat gebeurt wanneer een aanroeper een eigen XMP-pakket levert. Zonder die identificatie leest een validator het bestand als een gewone PDF en rapporteert elke regel van het geclaimde deel als onvervuld — een spectaculair uitziende faal met één kleine oorzaak
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;
Het deel kiezen vóór de conversie
SetPDFAMode en ConvertToPDFA delen dezelfde modenummering, en drie van de waarden zijn recent. Mode 9 is PDF/A-4, het deel dat op PDF 2.0 is gebouwd. Mode 10 is PDF/A-4e, dat bovendien 3D en rich media toestaat, en mode 11 is PDF/A-4f, dat een ingesloten bestand van elk formaat toestaat
Deel 4 identificeert zich anders dan de delen ervoor: met deelnummer en het jaar waarin het deel werd gepubliceerd, zonder conformance-letter voor gewoon PDF/A-4 en met de letter E of F voor de twee extensies. De controle herkent deel 4, beoordeelt de bestanden ervan tegen PDF 2.0 in plaats van 1.7, en rapporteert een deel-4-bestand dat zijn revisiejaar niet vermeldt
Elk ingesloten bestand in een deel-4-document vermeldt hoe het zich tot het document verhoudt, zoals zowel deel 3 als deel 4 vereist. Dit is de regel die vroeger gewone bijlagen ving: de relatie werd alleen geschreven voor bijlagen na de eerste en nooit voor de laatste, zodat een document met één bijlage — het gebruikelijke geval — er helemaal geen meedroeg en op precies dat punt faalde bij validatie
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;
Waar het conversierapport voor dient
Beslissen wat de volgende stap is. Een conversie die slaagt heeft geen rapport nodig; een conversie die niet slaagt is de hele reden dat het rapport bestaat. Sommige obstakels zijn door een converter verwijderbaar en andere niet — versleuteling, verboden content die betekenis draagt, een font-program dat eenvoudigweg nergens op de machine aanwezig is. Het rapport onderscheidt wat is gedaan van wat overblijft, wat "conversie mislukt" omzet in een werkitem
Behandel het verdict als de poort in een batchpijplijn. Converteer, lees het verdict en routeer het bestand: archiveer de bestanden die slaagden, zet de rest in de wachtrij voor een mens met het rapport erbij. Wat je niet moet doen is de uitvoer van een mislukte conversie opslaan in het archief omdat hij er mooier uitziet dan de invoer — hij draagt nu een claim die de controle weigerde te bevestigen
Het merk aflezen dat een bestand al meedraagt
Voordat je iets converseert, weet wat het document over zichzelf zegt. Een PDF/A-controle die het bestaande standaardmerk niet kan lezen, beoordeelt elk bestand tegen deel 1 ongeacht wat het declareert, wat betekent dat een perfect geldig PDF/A-2- of PDF/A-3-document wordt gerapporteerd als dragend geen merk en met een te hoge versie — het tegendeel van de waarheid
Het merk wordt gelezen ongeacht of de producent het als XMP-element of als attribuut schreef. Beide vormen zijn gewone XMP, en slechts één ervan accepteren laat bestanden van andere producenten er ongemarkeerd uitzien. Als je ooit hebt afgevraagd waarom een document dat elders valideert faalt in je eigen pijplijn, dit is een goede plek om eerst te kijken
Sanitair vóór archivering, en de bug die de moeite waard is om te kennen
Archiefconversie en sanitair lopen vaak samen, omdat de content die een beveiligingsbeleid wil verwijderen sterk overlapt met de content die PDF/A verbiedt. SanitizeDocument verwijdert JavaScript, en het verwijderen van het laatste script verwijdert ook de lege naamruimteboom die het achterlaat — een boom die anders nog steeds aan een reader vertelt dat het document scripts meedroeg
Die tweede helft is op de harde manier geleerd: een off-by-one in de pakketlijst betekende dat sanitisatie rapporteerde scripts te verwijderen terwijl er geen werden verwijderd, zodat een gesanitiseerd document nog steeds zijn scripts uitvoerde bij openen. Het is een goed argument voor het algemene principe waarop dit hele artikel rust — verifieer het resultaat in plaats van de operatie te vertrouwen, in je eigen pijplijn net zo veel als in de bibliotheek
Voor het omringende archiefwerk, zie de doorlopen van PDF/A- en PDF/UA-preflight, echte redaction en contentverwijdering, en PDF/A-3 XMP-extensieschema voor Factur-X, dat de metagegevenenkant behandelt wanneer het gearchiveerde document ook gestructureerde factuurgegevens meedraagt
PDFlibPas is een native Pascal PDF-bibliotheek voor Delphi, C++Builder en Lazarus, zodat conversie, reparatie en validatie allemaal binnen je eigen proces plaatsvinden zonder externe tool in de keten — zie de PDFlibPas-productpagina voor de ondersteunde PDF/A-delen en platforms