PDFlibPas osaa tunnistaa asiakirjan rakenteen samalla kun sitä piirretään. Kun SetAutoTagMode on käytössä, tavallisista DrawText-kutsuista tulee kappaleita, RegisterHeading:iä heti seuraavasta tekstistä tulee otsikko kyseisellä tasolla, juoksevista ylä- ja alatunnisteista tulee elementtejä joita lukija ohittaa, kuvista tulee kuva-elementtejä ja DrawTableRows vie taulukon, sen rivit ja solut rakennepuuhun
Vaihtoehto — ja aina hiljattain asti ainoa vaihtoehto — oli kääriä jokainen piirtokutsu käsin BeginTag:iin ja EndTag:iin. Tämä toimii, ja asiakirjoissa joissa on epätavallinen rakenne se on edelleen oikea työkalu. Tavallisen raportin, laskun tai tiliotteen kohdalla se tarkoittaa, että tulosteen saavutettavuus riippuu siitä, ettei kukaan koskaan unohda yhtä paria, kaikissa koodipoluissa jotka piirtävät mitään
Mitä tilabitit kattavat
SetAutoTagMode ottaa bittimaskin ja palauttaa aiemmin voimassa olleen tilan. AUTOTAG_TEXT (1) tunnistaa tekstin kappaleeksi, tai otsikoksi kun yksi on vuorossa. AUTOTAG_FURNITURE (2) merkitsee juoksevat ylä- ja alatunnisteet sekä sivunumerot taustaelementeiksi. AUTOTAG_FIGURE (4) muuttaa piirretyn kuvan kuva-elementiksi, tai taustaelementiksi kun se oli ilmoitettu koristeelliseksi. AUTOTAG_TABLE (8) vie piirretyt taulukot rakennepuuhun. AUTOTAG_DEFAULT on 15, eli kaikki neljä
Tilan kytkeminen päälle merkitsee myös asiakirjan tunnistetuksi, ja tämä vaihe on vähemmän kosmeettinen kuin miltä kuulostaa. Lukija pitää asiakirjaa tunnistamattomana ellei katalogi sano muuta (ISO 32000-1 §14.7.1), joten tiedosto joka kantaa täydellisen rakennepuun ilman /MarkInfo-ilmoitusta julkistetaan avustavan teknologian toimesta rakenteettomaksi. Puu on olemassa, mikään ei sitä lue
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;
Mistä otsikko tietää, mihin tekstiin se kuuluu?
RegisterHeading nimeää tason seuraavalle piirretylle tekstille, ja se odottaa tekstiä. Jos väliin piirretään kuva, kuvaajasta tulee kuva-elementti ja otsikko pysyy odottamassa seuraavaa tekstiä. Tämä käytös on tahallaan valittu: vaihtoehto, jossa kuva ottaisi otsikkotason, tuotti asiakirjoja joissa otsikon alla oleva koristeviiva julkistettiin otsikkona
Sama "kulutetaan yhteen elementtiin" -sääntö koskee kuvia. RegisterFigure toimittaa kuvauksen jonka seuraava kuva kantaa, ja RegisterDecoration julistaa seuraavan kuvan säännöksi, reunukseksi tai taustaksi joka ei kanna merkitystä. molemmat kulutetaan yhteen kuvaan, joten myöhempi kuva ei koskaan peri aiemmin tarkoitettua kuvausta — mikä on juuri se tapa jolla alt-teksti päätyy kiinni väärään kuvaan käsin tunnistetuissa koodissa
Kuvaus merkitsee enemmän kuin yksikään muu yksittäinen merkkijono saavutettavassa asiakirjassa. Näkövammainen lukija saa kuvauksen kuvan sijaan, ja se on koko se mitä hän saa. "Kaavio" ei ole kuvaus; "Vuosineljänneksen liikevaihto alueittain, itäinen alue korkeimmillaan Q3:ssa" on
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
Taulukot, otsikkorivit ja missä toistopäätös asuu
Taulukkobitin ollessa päällä DrawTableRows vie taulukon, sen rivit ja solut rakennepuuhun, jolloin lukija voi sanoa missä sarakkeessa arvo sijaitsee sen sijaan että lukisi koko taulukon yksittäisenä tekstinä. SetTableHeaderRowCount nimeää kuinka monta alkuriviä on otsikoita; kyseiset rivit kirjoitetaan otsikkosoluiksi jotka kantavat sarakelaajuutta, mikä on juuri se mikä antaa lukijalle mahdollisuuden julistaa sen arvon otsikko jolla käyttäjä on
Tällä tavalla nimetyt otsikkorivit pysyvät siellä missä ne ovat. Niiden toistaminen jokaisen sivun yläosassa on asettelupäätös, ja se pysyy sellaisena: DrawTaggedTableRows ottaa RepeatHeaderRows-argumentin juuri tätä tarkoitusta varten. Kahden erillään pitäminen estää rakennepuuta hankkimasta toista kopiota otsikosta joka sivunvaihdossa, mikä olisi seurausta automaattisesta toistosta
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;
Automaattisen ja käsin tehtyjen tunnistusten yhdistäminen
Automaattinen tunnistus vetäytyy käsin avatun tunnisteen sisällä. Yksi osa asiakirjaa voidaan kuvata koodillasi ja loput jättää kirjaston hoidettavaksi ilman että nämä kaksi pesiytyvät toisiinsa — mikä on juuri se järjestely jota useimmat todelliset asiakirjat haluavat. Kansisivulla ja allekirjoituslohkolla on rakennetta jonka vain sinä ymmärrät; niiden välissä olevilla kahdellasivulla leipätekstiä ei
Kaksi turvasääntöä pitää tulosteen puhtaana. Mikään taustaelementin sisällä ei tunnisteta, koska taustaelementiksi merkityn sisällön ei tule kantaa rakennetta. Ja tyhjä teksti ei avaa elementtiä, joten harhaanlinessunut DrawText tyhjällä merkkijonolla ei voi tuottaa rakennetta jonka lukija julkistaisi tyhjänä. molemmat ovat sellaisia virheitä joita käsin tunnistetut asiakirjat keräävät hiljaa ja jotka validaattori raportoi massana kuukausia myöhemmin
Mitä automaattinen tunnistus ei vieläkään päätä puolestasi
Lukujärjestystä piirtojärjestystä pidemmälle, semanttisia rooleja jotka eivät ole kappale, otsikko, kuva tai taulukko, ja kielimäärittelyjä. Automaattinen tunnistus sijoittaa rakenteen siinä järjestyksessä missä sisältö piirretään — jos asettelukoodisi piirtää sivupalkin ennen leipätekstiä, tuo on järjestys jonka puu tallentaa. Asiakirjoissa joissa visuaalinen järjestys ja lukujärjestys aidosti eroavat toisistaan, käsin tehty tunnistus-API pysyy oikeana työkaluna, ja artikkeli tunnistettu PDF ja saavutettavuusrakenne käsittelee roolit, laajuudet ja otsikkosidokset yksityiskohtaisesti
Kun asiakirja on valmis, varmenna sen sijaan että oletat: artikkeli PDF/A- ja PDF/UA-eskelennus näyttää kuinka saat tuomion tuottamastasi rakenteesta, ja artikkeli aineistojen ohjaama raporttivienti käsittelee mihin nämä kutsut sopivat raporttimoottorissa joka tuottaa asettelunsa datasta
PDFlibPas on natiivi Pascal-PDF-kirjasto Delphille, C++Builderille ja Lazarukselle ilman ulkoista PDF-ajonaikaa, joten saavutettava tuloste tuotetaan samalla koodilla joka piirtää asiakirjan — katso PDFlibPas-tuotesivulta koko API ja alustaluettelo