Odborný článok

Tagované PDF figúry z obrázkov Excelu s HotXLS

Keď HotXLS exportuje pracovný hárok do PDF so zapnutým automatickým tagovaním, obrázky hárka nesúce alternatívny text sa teraz emitujú ako nezávislé štrukturálne prvky /Figure s položkou Unicode /Alt, hustými marked-content identifikátormi lokálnymi pre stranu a presnými záznamami parent-tree. Obrázky bez alternatívneho textu zostávajú ozdobnými artifactmi a grafy zostávajú artifactmi tiež. Ten presný rozsah má význam: sprístupňuje informatívne obrázky čítačke obrazovky a nie je to to isté ako plná konformita PDF/UA

Mechanika za tým je zaujímavejšia než popis funkcie, pretože dva z jej detailov sú toho druhu, ktorý potichu produkuje štrukturálne platné PDF, ktorého štruktúra ukazuje na zlý obsah

Čo sa počíta ako informatívny obraz?

Len neprázdny AltText. Vlastnosť TXLSXImage.AltText prenáša obojsmerne atribút OOXML descr nevizuálnych vlastností obrázka, kde Excel uchováva text, ktorý používateľ vpíše do panela alt textu. To je jediný signál v súbore, že autor považoval obrázok za nositeľa informácie, nie dekorácie, takže je to jediný signál, ktorému exportér verí

Dva takmer zásahy sa zámerne neprijímajú. Pole title, uchovávané oddelene od popisu, nie je náhrada: title je meno objektu, nie jeho textový ekvivalent a jeho povýšenie do /Alt by produkovalo dokument, ktorý prejde automatizovanou kontrolou, pričom čítačke obrazovky oznamuje „Obrázok 3“. Prázdny popis tiež nie je medzera na vyplnenie placeholderom; znamená, že obraz zostáva artifactom, čo je správny výsledok pre logo či oddeľovaciu linku. Grafy tiež zostávajú artifactmi zatiaľ, pretože textovým ekvivalentom grafu sú jeho dáta a syntetizovať jeden zo sérií by bol výmysel, nie extrakcia

Obrázky s neprázdnym AltText sa exportujú ako štrukturálne prvky PDF Figure s vlastným MCID; prázdne popisy a grafy zostávajú artifactmi
Len autorov popis v AltText signalizuje informatívny obraz; samotný title sa nikdy nestane alt textom
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];

    // Audit pred exportom: obraz bez popisu bude exportovaný
    // ako ozdobný 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;

Prečo potrebuje strana jediný alokátor MCID?

Pretože parent tree je pole indexované marked-content identifikátorom a dva alokátory produkujú dva záznamy nárokujúce si ten istý slot. Tagované PDF viaže obsah so štruktúrou obojsmerne. Na strane obsahu je úsek content streamu strany zabalený do operátorov BDC a EMC nesúcich číslo /MCID jedinečné v rámci tej strany. Na strane štruktúry nesie slovník strany kľúč /StructParents menujúci riadok dokumentového /ParentTree a ten riadok je pole, ktorej prvok na indexe n je štrukturálny prvok vlastniaci MCID n

Strana pracovného hárka obsahuje bunky tabuľky a teraz aj figúry. Ak tagger buniek počíta svoje identifikátory od nuly a tagger figúr tiež počíta od nuly, prvá figúra si nárokuje slot, ktorý už vlastní prvá bunka. Nič na výslednom súbore nie je zdeformované natoľko, aby to parser odmietol: strom štruktúry je neporušený, marked content je vyvážený a validátor vidí dokument s parent tree. Čo dostane čítačka obrazovky, je bunka tabuľky ohlásená ako obraz alebo obraz ohlásený s textom bunky. Exportér preto alokuje z jedného počítadla na úrovni strany zdieľaného oboma taggermi a zmrazí záznam strany až v momente, keď je známe číslo objektu strany, keďže riadok parent-tree nemožno zapísať skôr, než strana, na ktorú odkazuje, má identitu

Nezávislé taggery buniek a figúr sa zrazia na slote nula parent tree; jedno počítadlo MCID na úrovni strany drží každú značku namapovanú na jedného vlastníka
Súbor so zrážkou stále prejde štrukturálnym validátorom; zlé je len oznámenie čítačky obrazovky

Figure musí obaliať celú viditeľnú inštanciu

Naivné umiestnenie je obaliť operátor Do, ktorý volá image XObject, keďže to je operátor, ktorý kreslí obrázok. To nestačí. Obrázok pracovného hárka sa často kreslí s tieňom za sebou a cestou orezania okolo seba a tie značky sú časťou viditeľného objektu. Ponechané mimo scope /Figure sa stanú neoznačeným obsahom, čo je presne stav, ktorý audit štruktúry označí

Scope marked-content sa preto otvára pred tieňom a zatvára po nakreslení obrazu, pričom pokrýva aj orez. Zdieľanie sa zachováva tam, kde je zdieľanie správne: dve bunky ukazujúce to isté užitočné zaťaženie obrázka stále odkazujú na jeden image XObject, pretože to je optimalizácia na úrovni zdrojov a nemá nič spoločné so sémantikou. Čo každá viditeľná inštancia dostáva, je vlastný MCID a vlastný štrukturálny prvok, pretože dva výskyty toho istého loga na rôznych miestach sú dve veci, ktoré čitateľ stretne. Umiestňovanie obrazov a EMU geometria, ktorá tieto objekty pozicionuje, je pokrytá v článku o geometrii obrazov

Značka BDC otvára scope Figure pred tieňom a orezom a EMC zatvára po nakreslení obrazu Do, pokrývajúc celú viditeľnú inštanciu
Obalenie len operátora obrazu by nechalo tieň a orez ako neoznačený obsah; zdieľanie zdrojov medzi bunkami sa zachováva

Poradie čítania na strane pracovného hárka

Poradie čítania je rozhodnutie, ktoré musí exportér urobiť, pretože tabuľka nemá autorský tok tak, ako ho má dokument. Prijaté pravidlo je stabilné a ľahko vysvetliteľné: pre každú stranu prichádza najprv tabuľka, potom figúry v poradí kreslenia. Čitateľ teda počuje tabuľkový obsah strany a potom jej obrázky, namiesto toho, aby mali obrázky prelínanie na ľubovoľnej pozícii, ktorú kreslené objekty náhodou obsadili v súbore

Toto poradie je per strana, nie per dokument, čo má význam na zošite, ktorý sa stránkuje do desiatok strán: vetva štruktúry každej strany je sebestačná, takže čitateľ sa pohybujúci medzi stranami neskočí späť do skoršej tabuľky. Ak potrebujete kontrolu nad tým, ako sa hárok najprv stránkuje, interakcia nastavenia strany a tlačovej oblasti je popísaná v článku o ochrane a nastavení strany

Čo to certifikuje a čo nie

Certifikuje, že informatívne obrázky sa dostanú k asistívnej technológii so svojím popisom od autora a že mapovanie obsahu do štruktúry je správne, nie len prítomné. Nerobí výstup konformný s PDF/UA a popisovať to tak by bol nárok, ktorý implementácia nedokáže podložiť: grafy sú stále artifactmi a úplné vyhlásenie konformity vyžaduje audit každého typu štruktúry, každého fontu a metadát dokumentu ako celku

Ak je vašou požiadavkou archivačný či konformný profil namiesto zlepšenia prístupnosti, ide o odlišnú konfiguráciu exportu a odlišnú sadu kontrol, popísanú v článku o archivačnom exporte PDF/A. Tie dva sa kombinujú, ale odpovedajú odlišným audítorom

Jeden praktický návrh pre reportingovú pipeline: auditujte alternatívny text v momente, keď sa zošit generuje, nie v čase exportu. Generátor vie, čo každý obraz grafu či vložený diagram predstavuje, a dokáže zapísať skutočný popis do AltText; priebeh v čase exportu vám môže povedať len to, že popis chýba. HotXLS číta a zapisuje XLS, XLSX, ODS a CSV natívne z Delphi a C++Builder bez závislosti na Exceli a jeho voľby konfigurácie exportu sú uvedené na produktovej stránke HotXLS Delphi spreadsheet component