PDFlibPas dokáže dokument značiť už počas jeho kreslenia. Zapnite SetAutoTagMode a bežné volania DrawText sa stanú odsekom, text nakreslený hneď po RegisterHeading sa stane nadpisom príslušnej úrovne, hlavičky a päty behom strany sa stanú artefaktmi, ktoré čítačka preskočí, obrázky sa stanú figúrami a DrawTableRows prenese tabuľku, jej riadky a bunky do stromu štruktúry
Alternatívou — a donedávna jedinou možnosťou — bolo ručné obaľovanie každého volania kreslenia do BeginTag a EndTag. To funguje a pre dokumenty s neobvyklou štruktúrou je to stále ten správny nástroj. Pre obyčajný report, faktúru či výpis to však znamená, že prístupnosť výstupu závisí od toho, že nikto nikdy nezabudne na pár, a to naprieč každou cestou v kóde, ktorá niečo kreslí
Čo pokrývajú bity režimu
SetAutoTagMode prijíma bitovú masku a vracia režim, ktorý bol doposiaľ aktívny. AUTOTAG_TEXT (1) značí text ako odsek alebo ako nadpis, ak je jeden na rade. AUTOTAG_FURNITURE (2) označuje hlavičky, päty a čísla strán ako artefakty. AUTOTAG_FIGURE (4) z nakresleného obrázku urobí figúru, prípadne artefakt, ak bol deklarovaný ako dekoratívny. AUTOTAG_TABLE (8) prenáša nakreslené tabuľky do stromu štruktúry. AUTOTAG_DEFAULT je 15, čo sú všetky štyri
Zapnutie režimu zároveň označí dokument ako značený a tento krok je menej kozmetický, než to znie. Čítačka považuje dokument za neznačený, ak katalóg nehovorí inak (ISO 32000-1 §14.7.1), takže súbor, ktorý nesie kompletný strom štruktúry bez deklarácie /MarkInfo, je asistívnymi technológiami ohlásený ako dokument bez akejkoľvek štruktúry. Strom tam je, no nič ho nečíta
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;
Odkiaľ nadpis vie, ku ktorému textu patrí?
RegisterHeading určuje úroveň pre ďalší nakreslený text a čaká, kým sa text objaví. Ak sa medzitým nakreslí obrázok, stane sa figúrou a nadpis zostáva čakať na text, ktorý príde po ňom. Toto správanie je zámerne: alternatíva, kde by obrázok prevzal úroveň nadpisu, produkovala dokumenty, v ktorých sa dekoratívna čiara pod titulom ohlasovala ako samotný titul
Rovnaké pravidlo „spotrebuje sa na jednu položku" platí pre figúry. RegisterFigure dodáva popis, ktorý bude niesť ďalší obrázok, a RegisterDecoration vyhlasuje ďalší obrázok za čiaru, rámik alebo pozadie, ktoré nenesie žiadny význam. Obe sa spotrebujú na jeden obrázok, takže neskorší obrázok nikdy nezdedí popis určený pre skorší — čo je presne spôsob, akým pri ručnom značení končí alternatívny text pripojený k nesprávnemu obrázku
Popis má väčší výnam než akýkoľvek iný reťazec v prístupnom dokumente. Nevidiaci čitateľ dostane popis namiesto obrázku a nič iné nedostane. „Graf" nie je popis; „Štvrťročné tržby podľa regiónov, pričom východný región je najvyšší v Q3" 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
Tabuľky, hlavičky a kde žije rozhodnutie o opakovaní
S zapnutým bitom tabuľky DrawTableRows prenese tabuľku, jej riadky a bunky do stromu štruktúry, takže čítačka dokáže povedať, v ktorom stĺpci sa hodnota nachádza, namiesto toho, aby celú tabuľku čítala ako sériu nesúvisiaceho textu. SetTableHeaderRowCount určuje, koľko úvodných riadkov sú hlavičky; tieto riadky sa zapíšu ako hlavičkové bunky nesúce rozsah stĺpca, čo umožňuje čítačke oznámiť nadpis hodnoty, na ktorej sa používateľ nachádza
Riadky hlavičiek určené týmto spôsobom ostanú tam, kde sú. Ich opakovanie na vrchu každej strany je rozhodnutie o rozvrhnutí a tým aj ostáva: DrawTaggedTableRows preberá argument RepeatHeaderRows presne na tento účel. Udržanie oboch oddelených zabráni tomu, aby strom štruktúry získal druhú kópiu hlavičky pri každom zalomení strany, čo je presne to, čo by automatické opakovanie vyprodukovalo
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;
Zmiešanie automatického a ručného značenia
Automatické značenie sa stiahne vo vnútri značky otvorenej ručne. Časť dokumentu môže opísať váš kód a zvyšok nechať na knižnici, a to bez toho, aby sa do seba navzájom vnárali — čo je usporiadanie, ktoré si želá väčšina reálnych dokumentov. Obalová strana a blok podpisov majú štruktúru, ktorej rozumie iba váš kód; dvesto strán súvislého textu medzi nimi nie
Dve bezpečnostné pravidlá udržiavajú výstup čistý. Vo vnútri artefaktu sa nič neznačí, pretože obsah označený ako artefakt nesmie niesť žiadny element štruktúry. A prázdny text neotvorí žiadny element, takže odcudzené DrawText s prázdnym reťazcom nemôže vyprodukovať štruktúrny element, ktorý by čítačka ohlásila ako prázdny. Obe sú typom defektu, ktoré ručne značené dokumenty potichu hromadia a ktoré validátor nahlásihne hromadne o mesiace neskôr
Čo automatické značenie stále nerozhoduje za vás
Poradie čítania presahujúce poradie kreslenia, sémantické roly, ktoré nie sú odsek, nadpis, figúra ani tabuľka, a deklarácie jazyka. Automatické značenie priraďuje štruktúru v poradí, v akom je obsah kreslený — ak váš kód rozvrhnutia nakreslí bočný panel pred telom dokumentu, v takom poradí ho strom zaznamená. Pre dokumenty, kde sa vizuálne poradie a poradie čítania skutočne líšia, zostáva ručné API značenia tým správnym nástrojom a návod k značenému PDF a štruktúre prístupnosti podrobne pokrýva role, rozsahy a väzby hlavičiek
Keď je dokument dokončený, validujte namiesto predpokladu: poznámky k PDF/A a PDF/UA preflightu ukazujú, ako získať verdikt nad vyprodukovanou štruktúrou, a návod k exportu reportu riadenému dátami pokrýva, kam tieto volania patria v reportovacom engine, ktorý generuje rozvrhnutie z dát
PDFlibPas je natívna Pascal PDF knižnica pre Delphi, C++Builder a Lazarus bez externého PDF runtime, takže prístupný výstup produkuje ten istý kód, ktorý kreslí dokument — kompletný zoznam API a platforiem nájdete na produktovej stránke PDFlibPas