Teknisk artikkel

Taggete PDF-figurer fra Excel-bilder med HotXLS

Når HotXLS eksporterer et regneark til PDF med automatisk tagging aktivert, sender regnearkbilder som bærer alternativ tekst nå ut som uavhengige /Figure-strukturelementer med en Unicode /Alt-oppføring, tette sidelokale marked-content-identifikatorer og nøyaktige foreldretre-oppføringer. Bilder uten alternativ tekst forblir dekorative artefakter, og diagrammer forblir også artefakter. Det presise omfanget betyr noe: det gjør informative bilder nåbare for en skjermleser, og det er ikke det samme som full PDF/UA-konformitet

Mekanikken bak er mer interessant enn funksjonsbeskrivelsen, fordi to av dem er den typen detalj som lydløst produserer en strukturelt gyldig PDF hvis struktur peker på feil innhold

Hva teller som et informativt bilde?

Bare en ikke-tom AltText. TXLSXImage.AltText-egenskapen rundturser OOXML descr-attributten til bildets ikke-visuelle egenskaper, noe som er der Excel lagrer teksten en bruker taster inn i alt-tekstpanelet. Det er det eneste signalet i filen om at forfatteren betraktet bildet som å bære informasjon snarere enn dekorasjon, så det er det eneste signalet eksportøren stoler på

To nesten-treff aksepteres bevisst ikke. Tittelfeltet, lagret separat fra beskrivelsen, er ikke en erstatning: en tittel er et navn for objektet, ikke en tekstlig ekvivalent av det, og å forfremme den inn i /Alt ville produsere et dokument som passerer en automatisert sjekk mens det annonserer «Bilde 3» til en skjermleser. En tom beskrivelse er også ikke et gap å fylle med en plassholder; det betyr at bildet forblir en artefakt, noe som er det korrekte utfallet for en logo eller en skillerlinje. Diagrammer forblir også artefakter foreløpig, fordi et diagrams tekstlige ekvivalent er dets data, og å syntetisere én fra seriene ville være oppfinnelse snarere enn ekstraksjon

Bilder med ikke-tom AltText eksporterer som PDF Figure-strukturelementer med sin egen MCID; tomme beskrivelser og diagrammer forblir artefakter
Bare forfatterbeskrivelsen i AltText signaliserer et informativt bilde; en tittel alene blir aldri 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];

    // Revider før eksport: et bilde uten en beskrivelse
    // eksporteres som en dekorativ artefakt
    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 trenger siden én enkelt MCID-allokator?

Fordi foreldretreet er en array indeksert etter marked-content-identifikator, og to allokatorer produserer to oppføringer som krever samme plass. Tagget PDF kobler innhold til struktur i begge retninger. På innholdssiden er et spenn av sideinnholdsstrømmen pakket inn i BDC- og EMC-operatorer som bærer et /MCID-nummer som er unikt innenfor den siden. På struktursiden bærer sideordboken en /StructParents-nøkkel som navngir en rad av dokumentets /ParentTree, og den raden er en array hvis element ved indeks n er strukturelementet som eier MCID n

En regnearkside inneholder tabellceller og, nå, figurer. Hvis celletaggeren teller sine identifikatorer fra null og figurtaggeren også teller fra null, krever den første figuren plassen den første cellen allerede eier. Ingenting ved den resulterende filen er feilformet nok til at en parser avviser den: strukturetret er intakt, det markerte innholdet er balansert, og en validator ser et dokument med et foreldretre. Det en skjermleser får, er en tabellcelle annonsert som et bilde, eller et bilde annonsert med teksten til en celle. Eksportøren allokerer derfor fra én sidenivåteller delt av begge taggerne, og fryser siderecorden først når sideobjektnummeret er kjent, siden foreldretræraden ikke kan skrives før siden den refererer til, har en identitet

Uavhengige celle- og figurtaggere kolliderer på foreldretreplass null; én sidenivå-MCID-teller holder hvert merke mappt til én eier
Den kolliderende filen passerer fortsatt en strukturell validator; bare skjermleserannonseringen er feil

Figuren må pakke inn hele den synlige instansen

Den naive plasseringen er å pakke inn Do-operatoren som påkaller bilde-XObject-en, siden det er operatoren som tegner bildet. Det er ikke nok. Et regnearkbilde tegnes ofte med en skygge bak seg og en klippevei rundt seg, og de merkene er en del av det synlige objektet. Igjen utenfor /Figure-skopen blir de umarkert innhold, noe som er nøyaktig tilstanden en strukturrevisjon flagger

Så marked-content-skopen åpnes før skyggen og lukkes etter bildetegningen, og dekker også klippet. Deling bevares der deling er korrekt: to celler som viser det samme bildepayloadet refererer fortsatt én bilde-XObject, fordi det er en ressursnivåoptimalisering og ikke har noe med semantikk å gjøre. Det hver synlig instans får, er sin egen MCID og sitt eget strukturelement, fordi to forekomster av den samme logoen på forskjellige steder er to ting en leser støter på. Bildeplassering og EMU-geometrien som posisjonerer disse objektene, er dekket i artikkelen om bildegeometri

BDC-merket åpner Figure-skopen før skygge og klipp, og EMC lukker etter Do-bildetegningen, og dekker hele den synlige instansen
Å pakke inn bare bildeoperatoren ville etterlate skygge og klipp som umarkert innhold; ressursdeling mellom celler bevares

Leserrekkefølge på en regnearkside

Leserrekkefølge er en avgjørelse eksportøren må ta, fordi et regneark ikke har noen forfattet flyt slik et dokument har. Regelen som er vedtatt, er stabil og lett å forklare: for hver side kommer tabellen først, deretter figurer i tegnerekkefølge. En leser hører derfor det tabellære innholdet på siden og deretter bildene dens, snarere enn å ha bilder flettet inn på den posisjonen tegneobjektene tilfeldigvis okkuperte i filen

Den rekkefølgen er per side snarere enn per dokument, noe som betyr noe på en arbeidsbok som paginerer inn i dusinvis av sider: hver sides strukturgren er selvstendig, så en leser som beveger seg mellom sider, hopper ikke tilbake inn i en tidligere tabell. Hvis du trenger kontroll over hvordan arket paginerer i utgangspunktet, er sideoppsett- og utskriftsområdesamspillet beskrevet i artikkelen om beskyttelse og sideoppsett

Hva dette sertifiserer, og hva det ikke gjør

Det sertifiserer at informative bilder når assisterende teknologi med sin forfatterleverte beskrivelse, og at innhold-til-struktur-mappingen er korrekt snarere enn bare til stede. Det gjør ikke output-PDF-en PDF/UA-konform, og å beskrive det slik ville være et krav implementeringen ikke kan støtte: diagrammer er fortsatt artefakter, og en full konformitetserklæring krever en revisjon av hver strukturtype, hver font og dokumentmetadataene som helhet

Hvis kravet ditt er en arkiv- eller konformitetsprofil snarere enn tilgjengelighetsforbedring, er det en annen eksportkonfigurasjon og et annet sett med sjekker, beskrevet i artikkelen om PDF/A-arkiveksport. De to kombineres, men de svarer ulike revisorer

Ét praktisk forslag til en rapporteringspipeline: revider alternativ tekst på det punktet arbeidsboken genereres, ikke ved eksporttid. Generatoren vet hva hvert diagrambilde eller innebygd diagram representerer, og kan skrive en ekte beskrivelse inn i AltText; et eksporttidspass kan bare fortelle deg at en beskrivelse mangler. HotXLS leser og skriver XLS, XLSX, ODS og CSV nativt fra Delphi og C++Builder uten Excel-avhengighet, og dets eksportkonfigurasjonsvalg er oppført på produktsiden for HotXLS Delphi spreadsheet component