Ako isporučite konverter koji svaki fajl obeleži kao PDF/A-1b, sistem za evidenciju kod klijenta ih uvozi godinu dana, a onda revizija pusti celu seriju kroz veraPDF i trećina ih se vrati kao neusaglašena. Ništa nije puklo, nijedan izuzetak nije podignut, fajlovi se otvaraju sasvim normalno u svakom pregledaču na vašem stolu. Jednostavno nisu bili standard koji ste na njih stavili. To je uobičajen način pada arhivskog PDF-a i zato tvrdnja "podesili smo zastavicu" nikada nije isto što i "proveru prolazi"
Prvo što treba razumeti kod PDFium-a i PDF/A jeste da motor tu nema nikakvu ulogu. PDFium prikazuje, parsira i upisuje PDF, ali njegovo javno sučelje nema ConvertToPDFA, nema upisivač OutputIntent-a, nema XMP API. Sav deo arhivske usklađenosti - XMP paket, OutputIntent i njegov ICC profil, oznake u katalogu, validacija - živi u samom PDFiumPas-u, u otprilike 2.000 linija čistog Pascal-a (FPdfPdfa.pas) koji parsira sačuvane bajtove i ponovo ih upisuje kroz inkrementalno ažuriranje. Znanje o tome gde se posao stvarno odvija govori vam gde se kriju bagovi, a oni se ne kriju u PDFium-u
Šta PDF/A zaista zahteva i gde vas sapliće
PDF/A nije jedan format. ISO 19005 definiše tri dela (PDF/A-1, -2, -3) i, unutar svakog, nivoe usklađenosti koji obećavaju različite stvari. Nivo B (basic) garantuje samo da je vizuelni izgled reproducibilan. Nivo A (accessible) dodaje označeno stablo strukture i mapiranje u Unicode preko B. Nivo U, koji postoji samo za delove 2 i 3, stoji između njih: pouzdan Unicode tekst bez punog stabla strukture. ISO 19005-1 nema nivo U, što je ograničenje koje biblioteka neposredno kodira
Mali broj pravila u formatu su upravo ona koja u praksi najčešće sapletu. Šifrovanje je potpuno zabranjeno (ISO 19005-1 §6.1.3 i njegovi naslednici): PDF/A fajl ne sme da nosi jedan /Encrypt rečnik. Dokument mora da objavi uslov prikaza kroz OutputIntent čije je odredište važeći ICC profil (§6.2.3.2). Sama tvrdnja o usklađenosti mora da se pojavi kao XMP metapodatak pod PDF/A identifikacionom šemom. Nivo A dodatno traži §6.8 logičku strukturu, stablo oznaka koje dokument čini mašinski čitljivim. Ako ijedno od toga izostane, verifier za usklađenost odbija fajl iako se on savršeno prikazuje
Jedan poziv koji stvara arhivu
PDFiumPas izlaže ceo pipeline iza TPdf.SaveAsPdfA. Jednostavno preklapanje uzima ciljnu usklađenost i podrazumevano postavlja PDF/A-1b, što je pravi izbor za uobičajen slučaj "učinite da se ovo može prikazivati zauvek"
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.LoadFromFile('invoice.pdf');
// Default conformance is pac1b (PDF/A-1b)
if Pdf.SaveAsPdfA('invoice_archive.pdf') then
// file now carries XMP, sRGB OutputIntent, and catalog markers
else
raise Exception.Create('PDF/A save failed');
finally
Pdf.Free;
end;
end;
Ispod haube ovo je dvofazni potez. SaveAsPdfA prvo traži od PDFium-a da serijalizuje dokument sa FPDF_SaveAsCopy, a zatim taj tok bajtova predaje InjectPdfAMarkers, koji dodaje XMP metapodatke, sRGB OutputIntent sa ugrađenim ICC profilom i ponovo upisan katalog kao inkrementalno ažuriranje. Izvor se čita sa pozicije nula, a odredište se upisuje od pozicije nula; originalno stablo objekata ostaje netaknuto, a markeri ulaze posle postojećeg %%EOF. Ako su vam potrebni bajtovi umesto fajla, SaveAsPdfAToStream uzima jedan TStream i iste opcije
Biranje usklađenosti pomoću zapisa opcija
Da biste ciljali određeni deo i nivo, prosledite TPdfASaveOptions zapis. Njegovo Conformance polje uzima TPdfAConformance vrednost. Enumeracija pokriva svaku važeću kombinaciju i ništa drugo: pac1b, pac1a za deo 1; pac2b, pac2u, pac2a za deo 2; pac3b, pac3u, pac3a za deo 3, plus pacUnknown i pacNone za stranu validacije. Nema pac1u, jer taj nivo ne postoji u standardu
var
Pdf: TPdf;
Opts: TPdfASaveOptions;
begin
Pdf := TPdf.Create(nil);
try
Pdf.LoadFromFile('report.pdf');
Opts := TPdfASaveOptions.Default;
Opts.Conformance := pac2u; // PDF/A-2u: reliable Unicode text
Opts.Title := 'Quarterly Report 2026';
Opts.Author := 'Finance';
// Leave IccProfileData empty to use the built-in sRGB IEC61966-2.1 profile
if not Pdf.SaveAsPdfA('report_a2u.pdf', Opts) then
raise Exception.Create('PDF/A-2u save failed');
finally
Pdf.Free;
end;
end;
Većina zapisa može da ostane prazna. Ostavite Title, Author, Subject, Keywords, Creator, and Producer prazna i SaveAsPdfA automatski ih popunjava iz dokumentovog Info rečnika preko FPDF_GetMetaTextOstavite CreationDate i ModDate prazna i koristi trenutni UTC za oba XMP datuma. Ostavite DocumentId i InstanceId prazna i biblioteka ih unapred popunjava iz FPDF_GetFileIdentifier, uz povratak na deterministički ID izveden iz izvornog bajt toka. Polje koje možda namerno želite da prepišete je IccProfileData: prazno znači ugrađeni sRGB IEC61966-2.1 profil, ali CMYK ili grayscale radni tok treba da obezbedi sopstveni
Zašto nivo A degradira i zašto je to pošten izbor
Evo jedne začkoljice koja sapliće ljude koji očekuju da je zastavica isto što i garancija. Možete da zatražite pac1a na dokumentu koji nema stablo oznaka, ali PDF/A-1a zahteva §6.8 logičku strukturu, a biblioteka ne može da proizvede stablo strukture iz neoznačenog PDF-a. Umesto da izbaci fajl koji tvrdi da je nivo A, a pada na njemu, SaveAsPdfA proverava stvarnu označenu strukturu (/StructTreeRoot plus /MarkInfo sa /Marked true) i, ako je nema, spušta tvrdnju: pac1a postaje pac1b, pac2a postaje pac2b, i tako dalje kroz sva tri dela. Unutrašnji pomoćni delovi su PdfAIsLevelA i PdfADowngradeToLevelB
Razlog vredi reći otvoreno: fajl koji pošteno prijavljuje nivo koji zaista dostiže korisniji je od onog koji laže o nivou koji nema. Nivo U se obrađuje drugačije. Otkrivanje stvarne pokrivenosti Unicode-om značilo bi naivan test "da li ima /ToUnicode" koji bi previše spuštao legitimne dokumente (WinAnsi i slična kodiranja su izuzeta), pa save strana emituje U tvrdnju onako kako ju je pozivalac zadao i odstupanje prepušta da bude označeno na strani validacije. Ako vam treba garantovana Level A arhiva, označite dokument pre konverzije; konverter neće izmisliti strukturu koje nema
Zamka sa ICC profilom koju hvata samo pravi validator
Ovo je bio neuspeh koji je naučio najtežu lekciju, jer je sopstvena provera biblioteke prošla, a veraPDF, referentni validator za ISO 19005, nije. PDF/A zahteva da odredišni profil OutputIntent-a bude važeći ICCBased tok, a §6.2.3.2 nalaže da verifier taj tok proveri kao prostor boje. ICCBased tok mora da prijavi /N, broj komponenti boje. Rana verzija injektora je zapisala rečnik ICC toka sa samo /Length i bez /N, a veraPDF je odbio rezultat sa "The N entry (value null)... is missing"
Zamka je bila u tome što se odbijanje okidalo samo za PDF/A-1b i -1a. Modeli usklađenosti za deo 2 i deo 3 nisu pokretali tu konkretnu proveru nad profilom odredišta, pa je identična ubrizgana struktura prolazila pod pac2b, pac3b, i pac2u ali nije prolazila pod pac1b samo zbog pdfaid:part vrednosti. Jedan unit test to nikada ne bi video, jer je sopstveni ValidatePdfACompliance proveravao je samo da li je /DestOutputProfile ključ postojao, a ne šta je bilo unutar rečnika toka. Interni testovi su ostali zeleni; stvarna arhivska validacija je pala
Popravka je IccComponentCount pouzdanija rutina koja čita potpis prostora boje podataka na offsetu 16 ICC zaglavlja i preslikava ga u broj komponenti: GRAY je 1, RGB , Lab , and XYZ su 3, CMYK je 4, a nepoznat profil podrazumevano daje 3. Taj broj ulazi u rečnik toka kao /N. It is computed, not hard-coded to 3, so that a caller who supplies a CMYK or grayscale profile through IccProfileData je izračunato, a ne tvrdo kodirano na 3, tako da pozivalac koji preko validacija komprimovanih objekata i xref tokova, što je važno jer su moderni PDF-ovi koje injektor prihvata često zasnovani na cross-reference tokovima
Šifrovanje, xref tokovi i druge ivice
Pošto ISO 19005 zabranjuje šifrovanje, putanja za čuvanje ga uklanja pre upisa. SaveAsPdfA primenjuje FPDF_REMOVE_SECURITY prilikom serijalizacije, pa se šifrovan izvor (učitan sa svojom lozinkom) dešifruje na putu u arhivu. Na nešifrovanom dokumentu ovo je no-op i ne menja ništa. Posledica je ista ona restrikcija koju HotPDF nameće iz suprotnog smera: jedan fajl ne može istovremeno biti šifrovan i PDF/A. Kada radnom toku trebaju oba, odgovor su dva artefakta, šifrovana kopija za distribuciju i posebna čista kopija za arhivu
Još jedna ivica postaje vidljiva tek kad zaboli: PDF 1.5+ dokumenti koji koriste čist cross-reference stream i ne nose trailer ključ. Injektor čita trailer da pronađe izvorni /Info i da nadoveže svoje inkrementalno ažuriranje, i mora da prihvati xref-stream oblik, inače bi takav dokument bio kopiran dalje sa tiho izgubljenim markerima. ISO 32000-1 §7.5.6 izričito dopušta da klasično trailer inkrementalno ažuriranje sledi dokumentu sa xref-stream-om, uz /Prev koji pokazuje na xref-stream offset, što je upravo struktura koju injektor emituje. Sopstveni FPDF_SaveAsCopy PDFium-a uvek piše klasični trailer, pa u normalnom pipeline-u injektor nikada ne susreće čist xref-stream izvor, ali putanja čitanja to podržava za dokumente koji stižu od drugde
Verifikacija pre nego što poverujete tvrdnji
Biblioteka isporučuje proveru na nivou bajta, TPdf.ValidatePdfA, koja vraća jedan TPdfAValidationResult. Njeno Conformance polje prijavljuje otkriveni nivo i Issues je skup TPdfAValidationIssue vrednosti; pogodna metoda IsCompliant je tačna samo kada je stvarni nivo otkriven i skup problema je prazan. Pokrenite je kao brzu prvu prepreku u serijskoj obradi
var
Pdf: TPdf;
Res: TPdfAValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.LoadFromFile('invoice_archive.pdf');
Res := Pdf.ValidatePdfA;
if Res.IsCompliant then
Writeln('Conformant: detected level ', Ord(Res.Conformance))
else
Writeln('Issues found: ', SizeOf(Res.Issues), ' flags set');
finally
Pdf.Free;
end;
end;
Budite pošteni prema onome što vam ovo daje. Provera na nivou bajta hvata strukturne probleme (nedostajući OutputIntent, zabranjenu akciju, prisutnu /Encrypt, transparentnost tamo gde deo 1 to zabranjuje) s velikom pouzdanošću, a otkrivanje ugradnje fonta koristi heuristiku brojanja koja namerno prijavljuje samo signal visoke pouzdanosti umesto da juri pokrivenost po glifu. Ono što ne radi jeste analiza operatora u toku sadržaja, za koju bi bio potreban pun parser sadržaja i koja je izvan namene. Za release gate, uparite proveru unutar biblioteke sa veraPDF-om: provera je trenutna i radi svuda bez DLL-a, veraPDF je autoritativan. Uvezivanje tog para u batch run tema je CLI-ja za batch preflight izveštaj, i tu ova validacija pripada u stvarnom arhivskom toku
API-je prikazane ovde isporučuju se uz SaveAsPdfA, InjectPdfAMarkers za Delphi, C++Builder i Lazarus/FPC. Stranica proizvoda vodi do pune API reference, uključujući kompletnu enumeraciju usklađenosti i zapis opcija iza ovih primera.ValidatePdfA APIs shown here ship with PDFium Component for Delphi, C++Builder, and Lazarus/FPC. The product page links the full API reference, including the complete conformance enumeration and the options record behind these examples