Műszaki cikk

PDF jelölt tartalom olvasása és írása Delphiben

A jelölt tartalom az a mechanizmus, amelyet az ISO 32000-1 §14.6 határoz meg az oldaltartalom címkézésére, és a tagged PDF és a PDF/UA is erre épül. A PDFium Component közvetlenül elérhetővé teszi: a PageObjectMarks minden BDC-címkét és tulajdonságlistáját kiolvassa egy oldalobjektumról, az AddPageObjectMark egyet ír, a RemovePageObjectMark egyet töröl, és a PageObjectMarkedContentID jelzi azt az MCID-t, amely a tartalmat a szerkezeti fához köti

Amíg a szerkezeti fa nem köthető vissza ahhoz a tartalomhoz, amelyet leír, az akadálymentességi eszközözés találgatás. A szerkezeti fa azt mondja „ez egy címsor”; az MCID mondja meg, hogy az a címsor valójában mely oldalakon mely jelöletek. Mindkét felet olvashatóvá kell tenni, mielőtt egy alkalmazás ellenőrizni, javítani vagy jelenteni tudja a címkézést

Mi egy jelölet, bájtokban?

Egy BDC operátor egy címkénévvel és egy opcionális tulajdonságlistával, amelyet EMC zár. A tartalomfolyamban így néz ki: /P <</MCID 3>> BDC ... EMC: a /P címke nevezi meg a szerepet, a szótár tulajdonságokat hordoz, és a két operátor között minden a jelölt tartalom. Egy oldalobjektum, amely abban a tartományban van, hordozza a jelöletet, amelyet a PDFium visszaküld, és amelyet a PDFium Component rekorddá alakít

A TPdfContentMark egy fogantyút, a címke Name-jét és egy TPdfContentMarkParam tömböt tartalmaz. Minden paraméternek van egy Key-je, egy Kind-ja és egy jelentésnélküli értékmezője, amelyet ez a fajta választ ki: pmpInt, pmpFloat, pmpString vagy pmpBlob. A fajta a PDFium saját típusjelentéséből származik, nem abból, hogy melyik getter sikerült, ami a különbség egy tulajdonságlista olvasása és egyről való találgatás között

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;

Miért jelent a pmpUnknown két különböző dolgot?

A pmpUnknown akkor kerül visszaadásra, amikor a PDFium FPDF_OBJECT_UNKNOWN-ot jelent, és a PDFium azt egy nem létező kulcsra is visszaadja. A két eset ezen a rétegen nem különíthető el, és másnak feltüntetése rosszabb lenne, mint kimondani

A kódunkra vonatkozó gyakori következmény: a pmpUnknown-ot úgy kezeljük, mint „itt nincs használható érték”, nem mint egy típus, amelyet esetleg még dekódolhatnánk. Ha egy tulajdonság számít a workflow-nkban, ellenőrizzük, hogy jelen van-e egy általunk felismert fajtával, és ne következtessünk hiányt egy unknown-ból — egy olyan jelölet, amelynek tulajdonságlistáját nem tudjuk elolvasni, olyan jelölet, amelyről jelentést kell tennünk, nem amelyet csendben el kell fogadnunk

Egy jelölet-rekord pillanatkép, nem birtokolt fogantyú

A Handle mező a könyvtáré. Abban a pillanatban elévül, amikor a jelöletet eltávolítják, az oldalobjektumot megsemmisítik vagy az oldalt kirakják, így a rekord egy csak olvasható pillanatkép, rövid élettel. Gyorsítótárazzuk oldalváltás között, és egy olyan memóriára mutató mutatónk van, amelyet a motor visszavett

Ez ugyanaz a fegyelem, amely az oldalobjektum-fogantyúkra általánosságban vonatkozik a PDFiumnál, és ugyanott kapja el az embereket: egy jelölet-rekordokkal feltöltött lista-kontroll, egy felhasználó, aki másik oldalra navigál, és egy összeomlás, amely látszólag nem kapcsolódik a navigáláshoz. Másoljuk ki a szükséges értékeket — a nevet, a kulcsokat, a számokat —, és engedjük el a fogantyút. Az oldalobjektum-fogantyúk transzformáció utáni elévüléséről szóló jegyzetek tárgyalják az általános szabályt és azt, hogyan harap máshol

Jelölet hozzáadása, és a mentési lépés, amelyet könnyű kihagyni

Az AddPageObjectMark átveszi az oldalobjektum-indexet, egy címkenevet és egy teljes paraméterhalmazt. A paraméterek halmazként íródnak, nem kulcsonkénti foltozással, amiért a TPdfContentMarkParam-nak nincsenek Has* szenitinjei — az az „egy meglévő rekord egy mezőjének frissítése” eset, amelyeket ezek védenének, nem merül fel

Azt a részt érdemes nyíltan kimondani: egy jelölet hozzáadása újraépíti az oldaltartalom-folyamot, hogy a címke túltegye a mentést. Ennek kifejezettnek kellett lennie, mert a SaveAs önállóan nem regenerál tartalmat — egy olyan változás, amely csak az objektummodellben élt, eldobásra kerülne, és a mentett fájl pontosan úgy nézne ki, mint amelyivel kezdtük. Ha már adtunk valami egy PDFium-oldalhoz, és hiányzott a kimenetből, általában ez az oka

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 tesz és mit nem tesz ez a dokumentumból?

A jelöletek önmagukban nem tesznek tagged PDF-et. Egy megfelelő tagged dokumentumhoz szerkezeti fa kell, amelynek elemei ezekre az MCID-kre hivatkoznak, egy /MarkInfo bejegyzés, amely taggedként deklarálja a dokumentumot, és olyan szerepnevek, amelyek azt jelentik, amit a szabvány mond. Egy /P jelölet írása olyan MCID-vel, amelyre egyetlen szerkezeti elem sem mutat, olyan tartalmat ad, amely taggednek állítja be magát, és egy olyan szerkezeti fát, amely sosem említi

Ahol a jelölt tartalom ezen a szinten valóban megéri a helyét, az a vizsgálat és a javítás: annak auditálása, hogy mely oldalobjektumok taggedek, olyan artifactok megtalálása, amelyeket úgy kellett volna megjelölni, vagy MCID-k szerkezeti fához való párosítása az árvák megtalálására. A munka szerkezeti-fa feléért lásd a PDF/UA szerkezeti fa-ellenőrzés átjárását, az olvasási élményért, amelyre a címkék végső soron szolgálnak, pedig az akadálymentes PDF-olvasó Delphiben építéséről szóló jegyzeteket

A PDFium Component magas szintű VCL API-t ad Delphi, C++Builder és Lazarus alkalmazásoknak a PDFium motor fölé, a jelölt tartalommal, a szerkezeti fákkal és az akadálymentesség-ellenőrzéssel mindennapi Pascal-kódból elérhetően — a teljes API-felülethez lásd a PDFium Component termékoldal-át