Merkitty sisältö on mekanismi jonka ISO 32000-1 §14.6 määrittelee sivun sisällön tunnistamiseen, ja tunnistettu PDF ja PDF/UA on molemmat rakennettu sen varaan. PDFium Component paljastaa sen suoraan: PageObjectMarks lukee jokaisen BDC-tunnisteen ja sen ominaisuusluettelon sivuoliolta, AddPageObjectMark kirjoittaa yhden, RemovePageObjectMark poistaa yhden, ja PageObjectMarkedContentID raportoi MCID:n joka linkittää sisällön rakennepuuhun
Kunnes rakennepuu voidaan liittää takaisin sisältöön jota se kuvaa, saavutettavuustyökalut ovat arvailua. Rakennepuu sanoo "tämä on otsikko"; MCID sanoo mitkä merkinnät millä sivulla tuo otsikko todellisuudessa on. molemmat puoliskot pitää olla luettavissa ennen kuin sovellus voi tarkistaa, korjata tai raportoida tunnistuksesta
Mikä on merkki, tavuina?
BDC-operaattori jolla on tunnisteen nimi ja valinnainen ominaisuusluettelo, jonka EMC sulkee. Sisältövirrassa se näyttää tältä /P <</MCID 3>> BDC ... EMC: tunniste /P nimeää roolin, sanakirja kantaa ominaisuuksia, ja kaiken operaattoreiden välissä on merkitty sisältö. Sivuolio tuon välivälin sisällä kantaa merkin, mikä on se minkä PDFium palauttaa ja minkä PDFium Component muuttaa tietueeksi
TPdfContentMark pitää kahvan, tunnisteen Name:n ja taulukon TPdfContentMarkParam-arvoja. Jokaisella parametrilla on Key, Kind ja yksi merkityksellinen arvokenttä jonka se laji valitsee: pmpInt, pmpFloat, pmpString tai pmpBlob. Laji tulee PDFiumin omasta tyyppiraportista eikä siitä getteristä joka sattui onnistumaan, mikä on ero ominaisuusluettelon lukemisen ja sen arvailemisen välillä
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;
Miksi pmpUnknown tarkoittaa kahta eri asiaa
pmpUnknown palautetaan kun PDFium raportoi FPDF_OBJECT_UNKNOWN:n, ja PDFium palauttaa sen myös avaimelle jota ei ole olemassa. Kahta tapausta ei voida erottaa tällä tasolla, ja muun olettaminen olisi pahempaa kuin asian sanoaminen
Käytännön seuraus koodillesi: käsittele pmpUnknown:ta "ei käyttökelpoista arvoa tässä" sen sijaan että lajina jonka saatat siltiin selvittää. Jos ominaisuus merkitsee työnkulullesi, varmista että se on läsnä tunnistamallasi lajilla, äläkä päätä puuttumista tuntemattomasta — merkki jonka ominaisuusluetteloa et voi lukea on merkki josta sinun pitäisi raportoida, ei sellainen jonka hiljaa hyväksyt
Merkkitietue on tilannevedos, ei kahva jonka omistat
Handle-kenttä kuuluu kirjastolle. Se vanhenee heti kun merkki poistetaan, sivuolio tuhotaan tai sivu purkaa, joten tietue on vain luku -tilannevedos jolla on lyhyt elämä. Välimuistita se sivunvaihdon yli ja pidät osoitinta muistiin jonka moottori on vaatinut takaisin
Tämä on sama kurinalaisuus joka koskee sivuoliokahvoja yleensä PDFiumissa, ja se nappaa ihmiset samassa paikassa: luettelokontrolli joka on täytetty merkkitietueilla, käyttäjä joka siirtyy toiselle sivulle, ja kaatumis joka näyttää irralliselta siirtymiseltä. Kopioi ulos arvot joita tarvitset — nimi, avaimet, numerot — ja anna kahvan mennä. Muistiinpanot sivuoliokahvojen vanhenemisesta muunnoksen jälkeen käsittelevät yleisen säännön ja miten se puree muualla
Merkin lisääminen ja tallennusaskel joka on helppo ohittaa
AddPageObjectMark ottaa sivuolioindeksin, tunnistenimen ja täydellisen parametrijoukon. Parametrit kirjoitetaan joukkona eikä paikataan yksi avain kerrallaan, mikä on syy miksi TPdfContentMarkParam:lla ei ole Has*-vartioita — "päivitä yksi kenttä olemassa olevasta tietueesta" -tapaus jonka nuo varaisivat ei nouse
Osa joka kannattaa sanoa nimenomaisesti: merkin lisääminen rakentaa sivun sisältövirran uudelleen niin että tunniste säilyy tallennuksen. Tämän piti olla nimenomainen koska SaveAs ei tuota sisältöä uudelleen itsestään — muutos joka eli vain oliomallissa hylättiin, ja tallennettu tiedosto näyttäisi tismalleen samalta kuin mistä aloitit. Jos olet koskaan lisännyt jotain PDFium-sivulle ja löytänyt sen puuttuvan tulosteesta, tämä on yleensä syy
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;
Mitä tämä tekee ja ei tee asiakirjasta
Merkit yksinään eivät tee tunnistetusta PDF:stä. Vaatimustenvastainen tunnistettu asiakirja tarvitsee rakennepuun jonka elementit viittaavat näihin MCID:ihin, /MarkInfo-merkinnän joka julistaa asiakirjan tunnistetuksi, ja roolinimet jotka tarkoittavat mitä standardi sanoo niiden tarkoittavan. /P-merkin kirjoittaminen MCID:n kanssa johon mikään rakenneryhmä ei osoita antaa sinulle sisältöä joka väittää olevansa tunnistettua ja rakennepuun joka ei koskaan mainitse sitä
Missä merkitty sisältö aidosti ansaitsee paikkansa tällä tasolla on tarkastus ja korjaus: sen auditoiminen mitkä sivuoliot on tunnistettu, sellaisten taustaelementtien löytäminen jotka olisi pitänyt merkitä sellaisiksi, tai MCID:ien täsmääminen rakennepuuhun löytääkseen orvot. Tuon työn rakennepuupuolta varten katso artikkeli PDF/UA-rakennepuun validointi, ja lukukokemusta varten jota tunnisteet lopulta ovat, muistiinpanot saavutettavan PDF-lukijan rakentaminen Delphissä
PDFium Component antaa Delphi-, C++Builder- ja Lazarus-sovelluksille korkean tason VCL-API:n PDFium-moottorin yli, jolloin merkitty sisältö, rakennepuut ja saavutettavuusvalidointi on tavoitettavissa tavallisesta Pascal-koodista — katso PDFium Component -tuotesivulta koko API-pinta