Teknisk artikel

Taggede PDF-Figures fra Excel-billeder med HotXLS

Når HotXLS eksporterer et regneark til PDF med automatisk tagning slået til, udsendes regnearksbilleder, der bærer alternativ tekst, nu som selvstændige /Figure-strukturelementer med en Unicode /Alt-post, tætte sidelokale marked-content-identifikatorer og eksakte parent-tree-poster. Billeder uden alternativ tekst forbliver dekorative artifacts, og diagrammer forbliver også artifacts. Det præcise omfang tæller: det gør informative billeder tilgængelige for en skærmlæser, og det er ikke det samme som fuld PDF/UA-overensstemmelse

Mekanikken bag er mere interessant end funktionsbeskrivelsen, for to af dem er den slags detaljer, der i stilhed producerer en strukturelt gyldig PDF, hvis struktur peger på det forkerte indhold

Hvad tæller som et informativt billede?

Kun en ikke-tom AltText. Egenskaben TXLSXImage.AltText round-tripper OOXML descr-attributten i billedets non-visual properties, hvilket er dér, Excel gemmer den tekst, en bruger taster ind i alt-text-panelet. Det er det eneste signal i filen om, at forfatteren betragtede billedet som informationsbærende frem for dekorativt, så det er det eneste signal, eksportøren stoler på

To næsten-rigtige udelades bevidst. Titelfeltet, gemt separat fra beskrivelsen, er ikke en erstatning: en titel er et navn for objektet, ikke en tekstlig ækvivalent til det, og at forfremme den til /Alt ville give et dokument, der består et automatiseret tjek, mens det annoncerer "Picture 3" til en skærmlæser. En tom beskrivelse er heller ikke et hul, der skal fyldes med en placeholder; det betyder, at billedet forbliver et artifact, hvilket er det korrekte udfald for et logo eller en adskillelseslinje. Diagrammer forbliver også artifacts foreløbigt, for et diagrams tekstlige ækvivalent er dets data, og at syntetisere en ud fra serierne ville være opfindelse frem for udtrækning

Billeder med ikke-tom AltText eksporteres som PDF Figure-strukturelementer med deres egen MCID; tomme beskrivelser og diagrammer forbliver artifacts
Kun forfatterbeskrivelsen i AltText signalerer et informativt billede; en titel alene bliver aldrig alt-teksten
uses
  lxHandleX, lxPDF;

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Exporter: TXLSPDFExport;
  I: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('regional-review.xlsx');
    Sheet := Book.Sheets.ByPos[0];

    // Revidér før eksport: et billede uden en beskrivelse
    // eksporteres som et dekorativt artifact
    for I := 0 to Sheet.Images.Count - 1 do
      if Sheet.Images[I].AltText = '' then
        Sheet.Images[I].AltText := DescribeImage(Sheet.Images[I].Name);

    Exporter := TXLSPDFExport.Create;
    try
      Exporter.TagMode := xlsPdfTagsAutomatic;
      Exporter.DocumentLanguage := 'en-US';
      Exporter.SaveAsPDF(Sheet, 'regional-review.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

Hvorfor behøver siden én enkelt MCID-allokator?

Fordi parent tree er et array indekseret efter marked-content-identifikator, og to allokatorer producerer to poster, der gør krav på samme plads. Tagged PDF forbinder indhold til struktur i begge retninger. På indholdssiden pakkes et stykke af sidens content stream ind i BDC- og EMC-operatorer, der bærer et /MCID-nummer, som er unikt inden for den side. På structuresiden bærer sideordbogen en /StructParents-nøgle, der navngiver en række i dokumentets /ParentTree, og den række er et array, hvis element ved indeks n er det strukturelement, der ejer MCID n

En regnearksside indeholder tabelceller og nu også figures. Hvis celle-taggeren tæller sine identifikatorer fra nul, og figure-taggeren også tæller fra nul, gør den første figure krav på pladsen, som den første celle allerede ejer. Intet ved den resulterende fil er misdannet nok til, at en parser afviser den: strukturtræet er intakt, det markerede indhold er balanceret, og en validator ser et dokument med et parent tree. Det, en skærmlæser får, er en tabelcelle annonceret som et billede, eller et billede annonceret med en celles tekst. Eksportøren allokerer derfor fra én tæller på sideniveau, der deles af begge taggere, og fryser siderecorden først, når sideobjektnummeret er kendt, da parent-tree-rækken ikke kan skrives, før den side, den refererer til, har en identitet

Selvstændige celle- og figure-taggere kolliderer om parent tree-plads nul; én sideniveau-MCID-tæller holder hvert mærke knyttet til én ejer
Den kolliderende fil består stadig en strukturel validator; kun skærmlæserens annoncering er forkert

Figuren skal pakke hele den synlige instans

Den naive placering er at pakke Do-operatoren, der kalder image XObject, da det er operatoren, der tegner billedet. Det er ikke nok. Et regnearksbillede tegnes ofte med en skygge bag sig og en klippesti omkring sig, og de mærker er en del af det synlige objekt. Efterladt uden for /Figure-scopet bliver de umarkeret indhold, hvilket præcis er den tilstand, en strukturrevision flagger

Så det markerede indholds scope åbner før skyggen og lukker efter billedtegningen og dækker også klippet. Deling bevares, hvor deling er korrekt: to celler, der viser samme billedpayload, refererer stadig til ét image XObject, for det er en optimering på ressourceniveau og intet har med semantik at gøre. Det, hver synlig instans får, er sin egen MCID og sit eget strukturelement, for to forekomster af samme logo forskellige steder er to ting, en læser støder på. Billedplacering og den EMU-geometri, der positionerer disse objekter, er dækket i artiklen om billedgeometri

BDC-mærket åbner Figure-scopet før skygge og klip, og EMC lukker efter Do-billedtegningen og dækker hele den synlige instans
At pakke kun billedoperatoren ville efterlade skygge og klip som umarkeret indhold; ressourcedeling mellem celler bevares

Læserækkefølge på en regnearksside

Læserækkefølge er en beslutning, eksportøren må træffe, for et regneark har ingen forfattet strøm, som et dokument har. Den vedtagne regel er stabil og let at forklare: for hver side kommer tabellen først, derefter figures i tegnerækkefølge. En læser hører derfor sidens tabulære indhold og derefter dens billeder i stedet for at have billeder flettet ind på den position, tegneobjekterne tilfældigvis optog i filen

Den orden er pr. side snarere end pr. dokument, hvilket tæller på en projektmappe, der paginerer ud i snesevis af sider: hver sides strukturgren er selvstændig, så en læser, der bevæger sig mellem sider, hopper ikke tilbage i en tidligere tabel. Hvis du behøver styring med, hvordan arket overhovedet paginerer, er sideopsætnings- og udskriftsområde-interaktionen beskrevet i artiklen om beskyttelse og sideopsætning

Hvad dette certifierer, og hvad det ikke gør

Det certifierer, at informative billeder når hjælpeteknologien med deres af forfatteren leverede beskrivelse, og at indhold-til-struktur-mappingen er korrekt snarere end blot til stede. Det gør ikke outputtet PDF/UA-konformt, og at beskrive det sådan ville være en påstand, implementationen ikke kan understøtte: diagrammer er stadig artifacts, og en fuld overensstemmelseserklæring kræver en revision af hver strukturtype, hver font og dokumentmetadata som helhed

Hvis dit krav er en arkiverings- eller overensstemmelsesprofil frem for en tilgængelighedsforbedring, er det en anden eksportkonfiguration og et andet sæt tjek, beskrevet i artiklen om PDF/A-arkiveringseksport. De to kombineres, men de svarer forskellige revisorer

Ét praktisk forslag til en rapporteringspipeline: revidér alternativ tekst der, hvor projektmappen genereres, ikke på eksporttidspunktet. Generatoren ved, hvad hvert diagrambillede eller indlejret skema repræsenterer, og kan skrive en rigtig beskrivelse ind i AltText; et gennemløb på eksporttidspunktet kan kun fortælle dig, at en beskrivelse mangler. HotXLS læser og skriver XLS, XLSX, ODS og CSV nativt fra Delphi og C++Builder uden Excel-afhængighed, og dets eksportkonfigurationsindstillinger er opført på produktsiden HotXLS Delphi spreadsheet component