Tehnični članak

Samodejno strukturno označevanje za dostopen PDF v Delphiju

PDFlibPas zna dokument označiti, medtem ko ga rišete. Vklopite SetAutoTagMode in običajni klici DrawText postanejo odstavki, besedilo, narisano takoj za RegisterHeading, postane naslov te ravni, tekoče glave in noge postanejo pripomočki, ki jih bralnik preskoči, slike postanejo figure, DrawTableRows pa prenese tabelo, njene vrstice in celice v drevo strukture

Nadomestilo — in do pred kratkim edina možnost — je bilo ročno ovijati vsak klic risanja v BeginTag in EndTag. To deluje in za dokumente z neobičajno strukturo je še vedno pravo orodje. Za običajno poročilo, račun ali izpisek to pomeni, da dostopnost izhoda temelji na tem, da nikoli nihče ne pozabi para, in sicer pri vsaki poti kode, ki karkoli nariše

Česar se nanašajo biti načina

SetAutoTagMode sprejme bitno masko in vrne način, ki je bil prej v veljavi. AUTOTAG_TEXT (1) označi besedilo kot odstavek ali kot naslov, ko je ta na vrsti. AUTOTAG_FURNITURE (2) označi tekoče glave, noge in številke strani kot pripomočke. AUTOTAG_FIGURE (4) spremeni narisano sliko v figuro ali v pripomoček, kadar je bila razglašena za okrasno. AUTOTAG_TABLE (8) prenese narisane tabele v drevo strukture. AUTOTAG_DEFAULT je 15, kar je vse štiri

Vklop načina dokument označi tudi kot označen, ta korak pa je manj kozmetičen, kot zveni. Bralnik dokument obravnava kot neoznačen, razen če katalog pravi drugače (ISO 32000-1 §14.7.1), zato assistivna tehnologija datoteko, ki nosi popolno drevo strukture brez izjave /MarkInfo, objavi, kot da sploh nima strukture. Drevo je tam; nihče ga ne bere

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;

Kako ve naslov, kateremu besedilu pripada?

RegisterHeading poimenuje raven za naslednje narisano besedilo in čaka na besedilo. Če je vmes narisana slika, slika postane figura, naslov pa ostane v čakanju za besedilo, ki sledi. To obnašanje je namerno: nadomestilo, kjer bi slika prevzela raven naslova, je dajalo dokumente, v katerih je bil okrasni ločilni črtni pod naslovom objavljen kot naslov

Isto pravilo porabljenosti za en element velja za figure. RegisterFigure zagotovi opis, ki ga nosi naslednja slika, RegisterDecoration pa razglasi naslednjo sliko za črto, obrobo ali ozadje, ki ne nosi pomena. Oba porabi ena slika, zato poznejša slika nikoli ne podeduje opisa, mišljenega za zgodnejšo — to pa je način, kako alternativno besedilo v ročno označeni kodi pristane ob napačni sliki

Opis je pomembnejši kot katerikoli drug posamezni niz v dostopnem dokumentu. Bralec, ki ne vidi, dobi namesto slike opis in to je vse, kar dobi. "Graf" ni opis; "Četrtletni prihodek po regijah, pri čemer je bila vzhodna regija najvišja v tretjem četrtletju", je

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

Tabele, glave in kje živi odločitev o ponovitvi

Z vklopljenim bitom za tabele DrawTableRows prenese tabelo, njene vrstice in celice v drevo strukture, tako lahko bralec pove, v katerem stolpcu leži vrednost, namesto da prebere celotno tabelo kot zaporedje nepovezanega besedila. SetTableHeaderRowCount poimenuje, koliko vodilnih vrstic so glave; te vrstice so zapisane kot celice glave s področjem stolpca, kar bralcu omogoča, da objavi naslov vrednosti, na kateri je uporabnik

Vrstice glave, poimenovane na ta način, ostanejo tam, kjer so. Njihova ponovitev na vrhu vsake strani je odločitev postavitve in takšna tudi ostaja: DrawTaggedTableRows za natanko ta namen sprejme argument RepeatHeaderRows. Ločevanje obeh preprečuje, da bi drevo strukture dobilo drugo kopijo glave za vsak prelom strani, kar bi samodejna ponovitev proizvedla

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;

Mešanje samodejnega in ročnega označevanja

Samodejno označevanje stopi ob stran znotraj oznake, odprte ročno. Del dokumenta je lahko opisan z vašo kodo, preostanek pa prepuščen knjižnici, brez da bi se drug v drugo vgnezdila — kar je ureditev, ki jo želi večina resničnih dokumentov. Naslovnica in blok podpisa imata strukturo, ki jo razumete samo vi; dvesto strani telesa besedila vmes pa ne

Dve varnostni pravili ohranjata izhod čist. Znotraj pripomočka nič ni označeno, ker vsebina, označena kot pripomoček, ne sme nositi nobenega elementa strukture. Prazno besedilo ne odpre nobenega elementa, zato zasut DrawText s praznim nizom ne more ustvariti strukturnega elementa, ki bi ga bralnik objavil kot praznega. Oboje sta napaki, ki jih ročno označeni dokumenti tiho nabirajo in jih validator poroča v masi mesece kasneje

Česar samodejno označevanje še vedno ne odloči namesto vas

Vrstni red branja onkraj vrstnega reda risanja, semantične vloge, ki niso odstavek, naslov, figura ali tabela, in izjave jezika. Samodejno označevanje dodeli strukturo v vrstnem redu, v kakršnem se vsebina riše — če vaša koda postavitve riše stransko vrstico pred telesom, je to vrstni red, ki ga drevo zabeleži. Za dokumente, kjer se vizualni vrstni red in vrstni red branja resnično razlikujeta, je ročni API za označevanje še vedno pravo orodje, sprehod skozi označeni PDF in strukturo dostopnosti pa podrobno obravnava vloge, področja in vezave glave

Ko je dokument končan, preverite namesto da privzamete: zapiski o predletu PDF/A in PDF/UA pokažejo, kako dobiti verdikt o strukturi, ki ste jo proizvedli, sprehod skozi izvoz poročil, ki ga poganja nabor podatkov, pa obravnava, kam sodijo ti klici v pogonu poročil, ki svojo postavitev ustvarja iz podatkov

PDFlibPas je izvorna Pascalova knjižnica PDF za Delphi, C++Builder in Lazarus brez zunanjega izvajalnega okolja PDF, tako da dostopen izhod proizvaja ista koda, ki riše dokument — glejte stran izdelka PDFlibPas za popoln seznam API-jev in platform