Tehnički članak

Automatsko označavanje strukture za pristupačni PDF u Delphiju

PDFlibPas može označavati dokument dok se crta. Uključite SetAutoTagMode i obični pozivi DrawText postaju odlomci, tekst nacrtan neposredno nakon RegisterHeading postaje naslov te razine, tekuća zaglavlja i podnožja postaju artefakti koje čitač preskače, slike postaju figure, a DrawTableRows unosi tablicu, njene redove i ćelije u stablo strukture

Alternativa, a do nedavno jedina opcija, bila je ručno umotati svaki poziv za crtanje u BeginTag i EndTag. To radi, i za dokumente neobične strukture i dalje je pravi alat. Za obično izvješće, fakturu ili izvod znači da pristupačnost izlaza ovisi o tome da nitko nikada ne zaboravi par, u svakoj putanji koda koja išta crta

Što pokrivaju bitovi načina

SetAutoTagMode prima bitovsku masku i vraća način koji je prethodno bio na snazi. AUTOTAG_TEXT (1) označava tekst kao odlomak, ili kao naslov kad je on na redu. AUTOTAG_FURNITURE (2) označava tekuća zaglavlja, podnožja i brojeve stranica kao artefakte. AUTOTAG_FIGURE (4) pretvara nacrtanu sliku u figuru, ili u artefakt kad je proglašena ukrasnom. AUTOTAG_TABLE (8) unosi nacrtane tablice u stablo strukture. AUTOTAG_DEFAULT je 15, što je sve četiri

Uključivanje načina također označava dokument kao označeni, i taj korak manje je kozmetički nego što zvuči. Čitač smatra dokument neoznačenim osim ako katalog ne kaže drukčije (ISO 32000-1 §14.7.1), pa se datoteka koja nosi potpuno stablo strukture bez deklaracije /MarkInfo najavljuje pomoćnoj tehnologiji kao da uopće nema strukturu. Stablo je tu, ali ga ništa ne čita

var
  Lib: TPDFlib;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.SetAutoTagMode(AUTOTAG_DEFAULT);   // text + furniture + figures + tables
    Lib.AddStandardFont(4);
    Lib.SetTextSize(18);
    Lib.RegisterHeading(1, 'Annual service report');
    Lib.DrawText(72, 96, 'Annual service report');   // becomes H1
    Lib.SetTextSize(11);
    Lib.DrawText(72, 130, 'Every unit installed before 2024 was inspected.');
    Lib.SaveToFile('report.pdf');
  finally
    Lib.Free;
  end;
end;

Otkud naslov zna kojem tekstu pripada?

RegisterHeading imenuje razinu za sljedeći nacrtani tekst i čeka na tekst. Ako se između nacrta slika, slika postaje figura, a naslov ostaje na čekanju za tekst koji slijedi. To ponašanje je namjerno: alternativa, u kojoj slika preuzima razinu naslova, proizvodila je dokumente u kojima je ukrasna crta pod naslovom bila najavljivana kao naslov

Isto pravilo utrošeno na jednu stavku vrijedi za figure. RegisterFigure dostavlja opis koji sljedeća slika nosi, a RegisterDecoration proglašava sljedeću sliku crtom, okvirom ili pozadinom koja ne nosi značenje. Oboje se troši na jednu sliku, tako da kasnija slika nikada ne nasljeđuje opis namijenjen ranijoj, što je način na koji alt tekst završi pridružen pogrešnoj slici u ručno označenom kodu

Opis je važniji od ijednog drugog pojedinog niza znakova u pristupačnom dokumentu. Čitatelj koji ne vidi dobiva opis umjesto slike, i to je sve što dobiva. Grafikon nije opis; Tromjesečni prihod po regijama, s istočnom regijom najvišom u Q3, jest

Lib.RegisterFigure('Exploded view of the gearbox assembly');
Lib.AddImageFromFile('gearbox.png', 0);      // becomes a tagged Figure

Lib.RegisterDecoration;                       // meaningless rule
Lib.AddImageFromFile('divider.png', 0);       // drawn inside a layout artifact

Tablice, zaglavlja i gdje živi odluka o ponavljanju

S uključenim bitom tablice, DrawTableRows unosi tablicu, njene redove i ćelije u stablo strukture, tako da čitač može reći u kojem se stupcu nalazi vrijednost umjesto da pročita cijelu tablicu kao niz nepovezanog teksta. SetTableHeaderRowCount imenuje koliko vodećih redova su zaglavlja; ti se redovi zapisuju kao ćelije zaglavlja koje nose opseg stupca, što je što čitatelju omogućuje da najavi naslov vrijednosti na kojoj se korisnik nalazi

Redovi zaglavlja imenovani na ovaj način ostaju gdje jesu. Njihovo ponavljanje na vrhu svake stranice je odluka rasporeda, i takvom ostaje: DrawTaggedTableRows prima argument RepeatHeaderRows upravo u tu svrhu. Držanje ovih dviju stvari odvojenima izbjegava da stablo strukture dobije drugi primjerak zaglavlja pri svakom prijelomu stranice, što bi automatsko ponavljanje proizvelo

var
  TableID: Integer;
begin
  TableID := Lib.CreateTable(40, 3);
  Lib.SetTableHeaderRowCount(TableID, 1);       // row 1 is the header band
  Lib.SetTableCellContent(TableID, 1, 1, 'Part');
  Lib.SetTableCellContent(TableID, 1, 2, 'Torque');
  Lib.SetTableCellContent(TableID, 1, 3, 'Unit');
  // ... fill the data rows ...
  // Draw rows 1..40 into a 600pt band, repeating one header row per page
  Lib.DrawTaggedTableRows(TableID, 72, 150, 600, 1, 40, 1);
end;

Miješanje automatskog i ručnog označavanja

Automatsko označavanje se povlači unutar oznake otvorene ručno. Dio dokumenta može opisati vaš kod, a ostatak prepustiti knjižnici, bez da se dvije ugniježđuju jedna u drugu, što je raspored koji većina stvarnih dokumenata želi. Naslovnica i blok potpisa imaju strukturu koju razumijete samo vi; dvjesto stranica temeljnog teksta između nemaju

Dva sigurnosna pravila drže izlaz čistim. Ništa se ne označava unutar artefakta, jer sadržaj označen kao artefakt ne smije nositi nijedan element strukture. A prazan tekst ne otvara nijedan element, pa slučajni DrawText s praznim nizom znakova ne može proizvesti element strukture koji bi čitač najavio kao prazan. Oboje su vrsta defekata koje ručno označeni dokumenti tiho nakupljaju, a validator prijavljuje u masi mjesecima kasnije

Što automatsko označavanje još uvijek ne odlučuje za vas

Redoslijed čitanja izvan redoslijeda crtanja, semantičke uloge koje nisu odlomak, naslov, figura ili tablica te jezične deklaracije. Automatsko označavanje dodjeljuje strukturu redoslijedom kojim se sadržaj crta. Ako vaš kod rasporeda crta bočnu traku prije tijela, taj je redoslijed onaj koji stablo zapisuje. Za dokumente u kojima se vizualni redoslijed i redoslijed čitanja stvarno razlikuju, API za ručno označavanje ostaje pravi alat, a prikaz označenog PDF-a i strukture pristupačnosti detaljno pokriva uloge, opsege i veze zaglavlja

Kad je dokument završen, provjerite umjesto da pretpostavljate: bilješke o PDF/A i PDF/UA preletu pokazuju kako doći do presude o strukturi koju ste proizveli, a prikaz izvoza izvješća vođenog skupom podataka pokriva gdje se ti pozivi uklapaju u mehanizam izvješća koji generira raspored iz podataka

PDFlibPas je izvorna Pascal PDF knjižnica za Delphi, C++Builder i Lazarus bez vanjskog PDF izvršnog okruženja, pa pristupačni izlaz proizvodi isti kod koji crta dokument. Pogledajte stranicu proizvoda PDFlibPas za cijeli popis API-ja i platformi