PDFlibPas може да маркира документ докато се чертае. Включете SetAutoTagMode и обикновените извиквания на DrawText стават абзаци, текстът начертан веднага след RegisterHeading става заглавие от съответното ниво, колонтитулите стават артефакти, които четецът прескача, изображенията стават фигури, а DrawTableRows пренася таблицата, нейните редове и клетки в дървото на структурата
Алтернативата — и до скоро единствената възможност — беше ръчно да обвиете всяко извикване за чертане в BeginTag и EndTag. Това работи и за документи с необичайна структура все още е правилният инструмент. За обикновен отчет, фактура или извлечение означава, че достъпността на изхода зависи от това никой никога да не забрави двойка, по всички кодови пътища, които чертаят каквото и да е
Какво покриват битовете на режима
SetAutoTagMode приема битовa маска и връща режима, който е бил в сила преди това. AUTOTAG_TEXT (1) маркира текст като абзац или като заглавие, когато е настъпило време за такова. AUTOTAG_FURNITURE (2) маркира колонтитулите и номерата на страници като артефакти. AUTOTAG_FIGURE (4) превръща начертано изображение във фигура или в артефакт, когато е обявено като декоративно. AUTOTAG_TABLE (8) пренася начертани таблици в дървото на структурата. AUTOTAG_DEFAULT е 15, което е и четирите
Включването на режима също маркира документа като маркиран, и тази стъпка е по-малко козметична, отколкото звучи. Четецът приема документ за немаркиран, освен ако каталогът не каже друго (ISO 32000-1 §14.7.1), така че файл, носещ пълно дърво на структурата без декларация /MarkInfo, бива обявен от асистивната технология като изобщо лишен от структура. Дървото е там; нищо не го чете
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;
Откъде заглавието знае към кой текст принадлежи?
RegisterHeading задава нивото за следващия текст, който се чертае, и то чака за текст. Ако междувременно се начертае изображение, то става фигура, а заглавието остава в очакване за текста, който следва. Това поведение е умишлено: алтернативата, при която изображението поеме нивото на заглавието, пораждаше документи, в които декоративна линия под заглавието беше обявявана като самото заглавие
Същото правило «изразходва се за един елемент» управлява фигурите. RegisterFigure доставя описанието, което следващото изображение носи, а RegisterDecoration обявява следващото изображение като линия, рамка или фон, който не носи смисъл. И двете се изразходват от едно изображение, така че по-късно изображение никога не наследява описание, предназначено за по-ранно — точно така алтернатив текст се озовава прикачен към грешна картина в ръчно маркиран код
Описанието има значение повече от всеки друг низ в достъпен документ. Четец със зрително увреждане получава описанието вместо картината, и това е всичко, което получава. «Графика» не е описание; «Тримесечна приходи по региони, с източния регион най-висок през Q3» е
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
Таблици, заглавни редове и къде живее решението за повторение
С включен бит за таблици DrawTableRows пренася таблицата, нейните редове и клетки в дървото на структурата, така че четецът може да каже в коя колона седи стойност, вместо да чете цялата таблица като поредица от несвързан текст. SetTableHeaderRowCount задава колко от водещите редове са заглавни; тези редове се записват като заглавни клетки, носещи обхват на колона, което е точно това, което позволява на четеца да обяви заглавието на стойността, върху която потребителят се намира
Заглавните редове, зададени по този начин, остават там, където са. Повторението им в горната част на всяка страница е решение за оформление, и то си остава такова: DrawTaggedTableRows приема аргумент RepeatHeaderRows точно за тази цел. Поддържането на двете отделни избягва дървото на структурата да придобие втора копие на заглавието при всеки прекъсване на страница, което е точно това, което би произвело автоматично повторение
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;
Смесване на автоматично и ръчно маркиране
Автоматичното маркиране отстъпва вътре в маркер, отворен ръчно. Част от документ може да бъде описана от вашия код, а останалото оставено на библиотеката, без двете да се влагат едно в друго — което е подредбата, която повечето реални документи искат. Корица и блокът за подпис имат структура, която само вие разбирате; двете стотици страници основен текст между тях не я имат
Две правила за безопасност пазят изхода чист. Нищо не се маркира вътре в артефакт, защото съдържание, маркирано като артефакт, не трябва да носи елемент на структура. И празен текст не отваря елемент, така че случайно DrawText с празен низ не може да произведе елемент на структура, който четецът би обявил като празен. И двете са вид дефекти, които ръчно маркираните документи тихо натрупват и които валидатор докладва в маса месеци по-късно
Какво автоматичното маркиране все още не решава вместо вас
Ред на четене извън реда на чертане, семантични роли, които не са абзац, заглавие, фигура или таблица, и декларации на език. Автоматичното маркиране присвоява структура в реда, в който съдържанието се чертае — ако кодът за оформление чертае страничната лента преди основния текст, това е редът, който дървото записва. За документи, при които визуалният ред и редът на четене наистина се различават, ръчното API за маркиране остава правилният инструмент, а ръководството за маркиран PDF и структура на достъпност разглежда роли, обхвати и заглавни обвързвания в детайл
Когато документът е завършен, валидирайте вместо да предполагате: записките за PDF/A и PDF/UA предполетна проверка показват как да получите присъда за структурата, която сте произвели, а ръководството за експорт на отчети на базата данни разглежда къде тези извиквания се вписват в двигател за отчети, който генерира оформлението си от данни
PDFlibPas е нативна Pascal PDF библиотека за Delphi, C++Builder и Lazarus без външен PDF runtime, така че достъпен изход се произвежда от същия код, който чертае документа — вижте страницата на продукта PDFlibPas за пълния списък с API и платформи