En tilgjengelig PDF hviler på én struktur den synlige siden aldri viser: strukturtreet definert i ISO 32000-1 §14.7. Det er et logisk hierarki av overskrifter, avsnitt, tabeller og figurer, lagt over det opptegnede innholdet og avbildet på standardroller gjennom et rollekart. En skjermleser leser det treet, ikke merkene på siden. Uten det er en generert faktura som ser plettfri ut, semantisk tom, for innholdsstrømmen noterer tegnerekkefølge og ingenting annet. Totalsummen kan bli lest opp før linjepostene, bunnteksten kan skjære inn i et avsnitt, posttabellen kan kollapse til én udifferensiert ordrekke. Kostnaden ved å hindre det er skjevt fordelt i din favør. Å sende ut struktur mens du tegner, er minutter med kode; å ettermontere den i ferdige dokumenter er et utbedringsprosjekt. losLab PDF Library (PDF Library for Delphi) eksponerer treet for Delphi og C++Builder gjennom et lite sett kall som pakker hver tegneoperasjon inn i sin logiske rolle
Hvordan merket innhold bindes til strukturtreet
To lag samarbeider. I innholdsstrømmen klammes tegneoperasjoner inn i sekvenser med merket innhold, hver med en heltalls-MCID. I dokumentkatalogen avbilder strukturtreet de MCID-ene på et hierarki av typede elementer (H1, P, Table, Figure) med attributter som alternativ tekst og språk. Egendefinerte elementtyper er lovlige, men hver av dem må løses opp i en standardrolle gjennom rollekartet (ISO 32000-1 §14.8.4). Innhold som ikke bærer mening i det hele tatt, som linjer, bakgrunner og gjentatt sidemøblement, merkes som artefakt slik at hjelpeteknologi hopper over det i stedet for å lese det midt i en setning
PDF Library for Delphi holder styr på begge lagene bak ett klammepar. BeginTag åpner et strukturelement og starter sekvensen med merket innhold, tegnekallene lander inni den, og EndTag lukker begge. Bokføringen som feller håndlaget tagging, MCID-ene og foreldretreet og sidereferansene, skjer internt der du ikke får gjort det galt
To brytere på dokumentnivå rammer inn arbeidet før noen tagg åpnes. SetMarkInfo skriver katalogflagget som erklærer dokumentet tagget, og IsTaggedPDF leser det tilbake, som er den billige første sonderingen når du skal avgjøre om en innkommende fil har noen struktur verdt å bevare. Språk har to inngangspunkter. SetDocumentLanguage setter dokumentstandarden alene, mens SetPDFUAMode setter den som del av å slå på full PDF/UA-utdata. En fil kan være nyttig tagget uten å hevde PDF/UA-samsvar, og en trinnvis innføring starter ofte nettopp der
Tagging mens du tegner, ikke etterpå
Genereringsmønsteret som virker, er å behandle taggklammen som en del av signaturen til hvert tegnekall, aldri som en senere runde:
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1); // origo øverst til venstre
Lib.SetPDFUAMode('en-US'); // hever lagringsversjonen til PDF 1.7
Lib.SetInformation(1, 'Service Manual'); // /Title er obligatorisk for PDF/UA
Lib.AddRoleMap('ManualTitle', 'H1'); // egendefinert type -> standardrolle
Lib.AddStandardFont(4);
Lib.SetTextSize(18);
Lib.BeginTagEx2('ManualTitle', '', '', 'en-US', '', 'h1-cover', '');
Lib.DrawText(72, 96, 'Service Manual');
Lib.EndTag;
Lib.BeginTag('Figure', 'Exploded view of the gearbox assembly', '');
Lib.AddImageFromFile('gearbox.png', 0);
Lib.EndTag;
Lib.BeginArtifact('Layout'); // sidedekor: utelatt fra lesingen
// ... tegn linjer og bakgrunnstone ...
Lib.EndArtifact;
Lib.SaveToFile('manual.pdf');
finally
Lib.Free;
end;
end;
Tre kall i den sekvensen veier tungt for samsvar. SetPDFUAMode slår på PDF/UA-utdata og hever stilltiende dokumentversjonen til PDF 1.7, noe som kolliderer med versjonslåsing. Et dokument låst til PDF 1.4 med LockSaveVersion nekter å lagre og returnerer feilkode 602 så snart UA-modus er aktiv, en kollisjon som gjerne dukker opp når arkivprofiler og tilgjengelighetskrav konfigureres av ulike team. SetInformation(1, ...) skriver dokumenttittelen, som ISO 14289 forventer at lesere viser i stedet for filnavnet; fraværet av den er ett av de vanligste PDF/UA-funnene i praksis. AddRoleMap registrerer den egendefinerte typen ManualTitle som en H1, og hopper du over det, flagger diagnostikken beskrevet nedenfor en uavbildet rolle
Overskriftsnivåer fortjener en bevisst policy, ikke tilfeldige valg tatt for utseendets skyld på en side. Skjermleserbrukere hopper mellom seksjoner med overskriftssnarveier, så en mal som går fra H1 til H3 fordi mellomnivået så for stort ut i det visuelle designet, ødelegger stilltiende den navigasjonen, og ingen visuell gjennomgang vil noen gang fange det. Det er nøyaktig den defekten diagnosen HEADING-LEVEL-SKIP finnes for å navngi. Avbild hver mals visuelle stiler på en fast overskriftsstige én gang, på ett sted, så starter driften aldri
Tabeller en skjermleser faktisk kan navigere
Opptegnede rutelinjer betyr ingenting utenfor skjermen. Det skjermlesere navigerer i, er strukturelle relasjoner: hvilke celler som er hoder, hva hvert hode styrer, og hvordan dataceller binder seg til hoder i uregelmessige oppsett. Attributtkallene på strukturelementer håndterer alle tre:
Lib.BeginTag('Table', '', '');
Lib.BeginTag('TR', '', '');
Lib.BeginTagEx2('TH', '', '', '', '', 'col-part', '');
Lib.SetStructElemScope('Column'); // gyldig bare mens denne TH-en er åpen
Lib.DrawText(72, 120, 'Part');
Lib.EndTag;
Lib.BeginTagEx2('TH', '', '', '', '', 'col-torque', '');
Lib.SetStructElemScope('Column');
Lib.SetStructElemColSpan(2); // hodet spenner over verdi- og enhetskolonnen
Lib.DrawText(200, 120, 'Tightening torque');
Lib.EndTag;
Lib.EndTag;
Lib.BeginTag('TR', '', '');
Lib.BeginTag('TD', '', '');
Lib.SetStructElemHeaders('col-part'); // eksplisitt binding for uregelmessige tabeller
Lib.DrawText(72, 140, 'M8 flange bolt');
Lib.EndTag;
Lib.EndTag;
Lib.EndTag; // Table
Rekkefølgeregelen er streng og håndheves i stillhet. Hvert SetStructElem*-kall gjelder den taggen som er åpen i det øyeblikket, mellom dens BeginTag og dens EndTag, og det returnerer 0 uten å utløse noe når ingen tagg er åpen eller attributtet ikke gjelder den gjeldende. Et feilplassert kall forsvinner rett og slett. Å pakke returverdiene inn i assertions under utvikling fanger driften mens du fortsatt kan se den; lar du det være, viser et manglende omfang seg først når en tilgjengelighetsrevisjon kjører en ekte skjermleser over tabellen. Element-ID-ene som sendes gjennom BeginTagEx2, mater ID-treet (ISO 32000-1 §14.7.4), og det er det som gjør SetStructElemHeaders-bindingen mulig å løse opp i det hele tatt
Den samme attributtfamilien dekker resten av det hjelpeteknologi støtter seg på. SetStructElemListNumbering erklærer hvordan listeelementer merkes, slik at en skjermleser melder posisjon i listen i stedet for å ramse opp kulepunkttegn. SetStructElemBBox noterer omsluttende ramme for figurer og tabeller, som visninger med omflyt bruker til å plassere innhold. SetStructElemActualText gir erstatningstekst for tekstrekker hvis glyffer ikke lar seg avbilde på lesbare tegn, slik som en anfang satt sammen av vektorgrafikk. Hver av dem følger samme regel: den binder seg til den åpne taggen, eller den forsvinner
Artefakter, språk og diagnostikkporten før lagring
Gjentatt sidemøblement, altså løpende topptekster, brettemerker, vannmerker og bakgrunnstoner, hører hjemme inne i klammene BeginArtifact og EndArtifact, så det aldri kommer inn i lesestrømmen. Språk er arvbart. Dokumentstandarden kommer fra argumentet til SetPDFUAMode, og en tekstrekke på et annet språk overstyrer den per element gjennom BeginTagEx eller SetStructElemLang. Det er det som holder et fransk sitat inne i en engelsk håndbok uttalbart
Før lagring kjører GetPDFUADiagnostics bibliotekets strukturkontroller over dokumentet i minnet og returnerer funn som tekst, der en tom streng betyr at ingenting ble funnet. Kodene navngir de klassiske forfattertabbene direkte: FIGURE-NO-ALT for et bilde uten alternativ tekst, HEADING-LEVEL-SKIP for en H3 som følger en H1, ROLEMAP-UNMAPPED for en egendefinert type som aldri ble registrert. Koble dette inn i bygget (generer dokumentsettet, la trinnet feile på ikke-tom diagnostikk), så blir tilgjengelighetsregresjoner feil av kompileringstypen i stedet for revisjonsfunn måneder senere. Den fullstendige samsvarsdommen hører fortsatt til preflight på den lagrede filen, dekket i PDF/A- og PDF/UA-preflight i Delphi, fordi noen normaliseringer først anvendes under serialiseringen
Navigasjon i annotasjoner har sin egen bryter. PDF/UA forventer at tastaturgjennomgang av skjemafelter og lenker følger strukturrekkefølgen, og SetTabOrderMode skriver oppføringen for tabulatorrekkefølge på sidenivå som lesere respekterer, med GetTabOrderMode tilgjengelig for gransking av innkommende filer. Det er den typen krav ingen legger merke til før en bruker som bare bruker tastatur, melder feilen, og det koster ett kall per dokument å få riktig
Strukturtrær overlever ikke enhver sammenslåing
Taggede dokumenter forblir tagget bare når hvert senere behandlingstrinn bevarer treet, og den skarpe kanten inne i PDF Library for Delphi er familien av sammenslåingslister. MergeFileListFast bytter bort bevaring av strukturtreet mot fart. Det er den rette avveiningen for batcher med skannede bilder og den gale for taggede rapporter, for utdataene åpner seg fint, gjengis identisk og har stilltiende mistet tilgjengelighetslaget sitt. Bruk standardvalget MergeFileList eller den strenge varianten når noen av inndatafilene er tagget, og gjør IsTaggedPDF til en del av kontrollene etter sammenstilling, så en flatet batch ikke kan sendes ut uten at noen merker det. Sammenstillingspipeliner for store dokumentsett bærer flere avveininger av dette slaget, utforsket i sammenslåing, oppdeling og direkte tilgang for store PDF-er
Verifiseringssløyfen lukkes utenfor biblioteket: åpne utdataene i Acrobat, inspiser taggpanelet, og les minst ett dokument per malfamilie med en ekte skjermleser. Diagnostikken fanger strukturelle tabber; bare et menneskelig øre fanger en leserekkefølge som er teknisk gyldig og praktisk forvirrende. Evalueringsbygg og den fullstendige API-referansen for tagging finnes på produktsiden for losLab PDF Library for Delphi