Merket innhold er den mekanismen ISO 32000-1 §14.6 definerer for å merke sideinnhold, og både merket PDF og PDF/UA er bygget på den. PDFium Component eksponerer den direkte: PageObjectMarks leser hver BDC-tag og dens egenskapsliste fra et sideobjekt, AddPageObjectMark skriver en, RemovePageObjectMark sletter en, og PageObjectMarkedContentID rapporterer MCID-en som kobler innhold til strukturtreet
Før strukturtreet kan kobles tilbake til innholdet det beskriver, er tilgjengelighetsverktøy gjetting. Strukturtreet sier «dette er en overskrift»; MCID-en sier hvilke merker på hvilken side den overskriften faktisk er. Begge halvdeler må være lesbare før en applikasjon kan sjekke, reparere eller rapportere på merking
Hva er et merke, i bytes?
En BDC-operator med et merkenavn og en valgfri egenskapsliste, lukket av EMC. I innholdsstrømmen ser det ut som /P <</MCID 3>> BDC ... EMC: merket /P navngir rollen, ordboken bærer egenskaper, og alt mellom operatorene er det merkede innholdet. Et sideobjekt inne det spennet bærer merket, noe som er det PDFium leverer tilbake og det PDFium Component gjør om til en post
TPdfContentMark holder et håndtak, merket Name, og en array av TPdfContentMarkParam. Hver parameter har en Key, en Kind og ett meningsfullt verdi-felt valgt av den typen: pmpInt, pmpFloat, pmpString eller pmpBlob. Typen kommer fra PDFiums egen type-rapport snarere enn fra hvilken getter som tilfeldigvis lyktes, noe som er forskjellen mellom å lese en egenskapsliste og å gjette på en
var
Marks: TPdfContentMarks;
M: TPdfContentMark;
P: TPdfContentMarkParam;
I: Integer;
begin
Pdf.PageNumber := 1; // PageNumber is 1-based
for I := 0 to Pdf.ObjectCount - 1 do // page object indexes are 0-based
begin
Marks := Pdf.PageObjectMarks(I);
for M in Marks do
begin
Memo1.Lines.Add('mark ' + M.Name +
' (MCID ' + IntToStr(Pdf.PageObjectMarkedContentID(I)) + ')');
for P in M.Params do
case P.Kind of
pmpInt: Memo1.Lines.Add(' ' + P.Key + ' = ' + IntToStr(P.IntValue));
pmpString: Memo1.Lines.Add(' ' + P.Key + ' = ' + P.StringValue);
pmpFloat: Memo1.Lines.Add(' ' + P.Key + ' = ' + FloatToStr(P.FloatValue));
pmpBlob: Memo1.Lines.Add(' ' + P.Key + ' = ' +
IntToStr(Length(P.BlobValue)) + ' bytes');
end;
end;
end;
end;
Hvorfor betyr pmpUnknown to forskjellige ting
pmpUnknown returneres når PDFium rapporterer FPDF_OBJECT_UNKNOWN, og PDFium returnerer det også for en nøkkel som ikke finnes. De to tilfellene kan ikke skilles på dette laget, og å late som om det var mulig ville være verre enn å si det
Den praktiske konsekvensen for koden din: behandle pmpUnknown som «ingen brukbar verdi her» snarere enn som en type du kanskje likevel kunne dekodet. Hvis en egenskap betyr noe for din arbeidsflyt, verifiser at den er til stede med en type du gjenkjenner, og ikke utled fravær fra en ukjent — et merke hvis egenskapsliste du ikke kan lese er et merke du bør rapportere på, ikke ett du bør godta i stillhet
En merke-post er et øyeblikksbilde, ikke et håndtak du eier
Handle-feltet tilhører biblioteket. Det blir stamsting i det øyeblikket merket fjernes, sideobjektet ødelegges eller siden lastes ut, slik at posten er et skrivebeskyttet øyeblikksbilde med kort levetid. Mellomlagre det på tvers av et sidebytte og du holder en peker inn i minne motoren har tilbakekalt
Dette er den samme disiplinen som gjelder for sideobjekt-håndtak generelt i PDFium, og den fanger folk på det samme stedet: en liste-kontroll befolket med merke-poster, en bruker som navigerer til en annen side, og et krasj som ser urelatert til navigasjonen ut. Kopier ut verdiene du trenger — navnet, nøklene, tallene — og lat håndtaket gå. Notatene om sideobjekt-håndtak som blir stamstige etter en transform dekker den generelle regelen og hvordan den biter andre steder
Å legge til et merke, og lagringstrinnet som er lett å gå glipp av
AddPageObjectMark tar sideobjekt-indeksen, et merkenavn og et komplett parametersett. Parametre skrives som et sett snarere enn lappet én nøkkel av gangen, noe som er grunnen til at TPdfContentMarkParam ikke har noen Has*-voktere — tilfelle «oppdater ett felt av en eksisterende post» de ville beskytte oppstår ikke
Den delen det lønner seg å slå fast eksplisitt: å legge til et merke bygger om sideinnholdsstrømmen slik at merket overlever en lagring. Dette måtte være eksplisitt fordi SaveAs ikke regenererer innhold på egen hånd — en endring som bare levde i objektmodellen ville forkastes, og den lagrede filen ville se nøyaktig ut som den du startet med. Hvis du noensinne har lagt noe til en PDFium-side og funnet det manglende fra utdataen, er dette vanligvis grunnen
var
Params: TPdfContentMarkParams;
begin
SetLength(Params, 1);
Params[0].Key := 'MCID';
Params[0].Kind := pmpInt;
Params[0].IntValue := NextMcid;
Pdf.AddPageObjectMark(ObjectIndex, 'P', Params); // rebuilds the content stream
Pdf.UpdatePage;
Pdf.SaveAs('tagged-out.pdf');
end;
Hva dette gjør og ikke gjør et dokument til
Merkker alene gjør ikke en merket PDF. Et konformt merket dokument trenger et struktur-tre hvis elementer refererer disse MCID-ene, en /MarkInfo-oppføring som erklærer dokumentet merket, og rollenavn som betyr det standarden sier de betyr. Å skrive et /P-merke med en MCID ingen struktur-element peker på gir deg innhold som krever å være merket og et struktur-tre som aldri nevner det
Der merket innhold genuint tjener inn sin rett på dette nivået er inspeksjon og reparasjon: revidere hvilke sideobjekter som er merket, finne artefakter som burde ha vært merket som slike, eller matche MCID-er mot et struktur-tre for å finne de foreldreløse. For struktur-tre-halvdelen av det arbeidet, se gjennomgangen av PDF/UA-struktur-tre-validering, og for leseopplevelsen merkene til syvende og sist er for, notatene om å bygge en tilgjengelig PDF-leser i Delphi
PDFium Component gir Delphi-, C++Builder- og Lazarus-applikasjoner et høynivå VCL-API over PDFium-motoren, med merket innhold, struktur-trær og tilgjengelighetsvalidering nåbart fra vanlig Pascal-kode — se PDFium Component-produktsiden for den fullstendige API-flaten