Gdy HotXLS eksportuje arkusz do PDF z włączonym automatycznym tagowaniem, obrazki arkusza niosące tekst alternatywny emitują teraz jako niezależne elementy struktury /Figure z unikodowym wpisem /Alt, gęstymi lokalnymi dla strony identyfikatorami oznaczonej zawartości i dokładnymi wpisami drzewa rodziców. Obrazki bez tekstu alternatywnego pozostają dekoracyjnymi artefaktami, a wykresy też pozostają artefaktami. Ten precyzyjny zakres się liczy: czyni obrazy informacyjne osiągalnymi dla czytnika ekranu i nie jest tym samym, co pełna zgodność z PDF/UA
Mechanika stojąca za tym jest ciekawsza niż opis funkcji, bo dwa z jej elementów to ten rodzaj szczegółu, który po cichu produkuje strukturalnie poprawny PDF, którego struktura wskazuje na złą zawartość
Co liczy się jako obraz informacyjny?
Tylko niepusty AltText. Własność TXLSXImage.AltText przechodzi w obie strony atrybut OOXML descr niewizualnych własności obrazka, gdzie Excel trzyma tekst, który użytkownik wpisał w panel tekstu alternatywnego. To jedyny sygnał w pliku, że autor uznał obrazek za niosący informację, a nie dekorację, więc to jedyny sygnał, któremu eksporter ufa
Dwa niemal trafienia są celowo nieakceptowane. Pole tytułu, przechowywane osobno od opisu, nie jest zamiennikiem: tytuł to nazwa obiektu, nie jego tekstowy odpowiednik, i awansowanie go do /Alt wyprodukowałoby dokument przechodzący automatyczną kontrolę, a ogłaszający czytnikowi ekranu „Obraz 3”. Pusty opis też nie jest luką do wypełnienia placeholderem; znaczy, że obraz pozostaje artefaktem, co jest poprawnym wynikiem dla logo albo linii rozdzielającej. Wykresy również na razie pozostają artefaktami, bo tekstowym odpowiednikiem wykresu są jego dane, a synteza ich z serii byłaby wymyślaniem, a nie ekstrakcją
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];
// Audyt przed eksportem: obraz bez opisu zostanie
// wyeksportowany jako dekoracyjny 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;
Czemu strona potrzebuje jednego alokatora MCID?
Bo drzewo rodziców jest tablicą indeksowaną identyfikatorem oznaczonej zawartości, a dwa alokatory produkują dwa wpisy roszczące sobie to samo gniazdo. Otagowany PDF łączy zawartość ze strukturą w obu kierunkach. Po stronie zawartości wycinek strumienia zawartości strony jest owinięty operatorami BDC i EMC niosącymi numer /MCID unikalny w obrębie tej strony. Po stronie struktury słownik strony niesie klucz /StructParents nazywający wiersz dokumentowego /ParentTree, a ten wiersz jest tablicą, której element pod indeksem n to element struktury posiadający MCID n
Strona arkusza zawiera komórki tabeli i, teraz, figury. Jeśli tagger komórek liczy swoje identyfikatory od zera i tagger figur też liczy od zera, pierwsza figura roszczy sobie gniazdo, które pierwsza komórka już posiada. Nic w powstałym pliku nie jest zdeformowane na tyle, by parser go odrzucił: drzewo struktury jest nietknięte, oznaczona zawartość jest zbalansowana, a walidator widzi dokument z drzewem rodziców. To, co dostaje czytnik ekranu, to komórka tabeli ogłaszana jako obraz albo obraz ogłaszany z tekstem komórki. Eksporter alokuje więc z jednego licznika poziomu strony współdzielonego przez oba taggery i mrozi rekord strony dopiero, gdy numer obiektu strony jest znany, bo wiersza drzewa rodziców nie da się zapisać, zanim strona, do której się odnosi, zdobędzie tożsamość
Figure musi owijać całą widoczną instancję
Naiwne umiejscowienie to owinięcie operatora Do, który wywołuje XObject obrazu, bo to operator rysujący obrazek. To za mało. Obrazek arkusza jest często rysowany z cieniem za sobą i ścieżką przycinającą wokół, a te znaczniki są częścią widocznego obiektu. Pozostawione poza zakresem /Figure stają się zawartością nieoznaczoną, czyli dokładnie tym stanem, który audyt struktury flaguje
Zakres oznaczonej zawartości otwiera się więc przed cieniem i zamyka po narysowaniu obrazu, obejmując również przycięcie. Współdzielenie jest zachowane tam, gdzie współdzielenie jest poprawne: dwie komórki pokazujące ten sam ładunek obrazka wciąż odwołują jeden XObject obrazu, bo to optymalizacja poziomu zasobów i nie ma nic do rzeczy z semantyką. To, co dostaje każda widoczna instancja, to własny MCID i własny element struktury, bo dwa wystąpienia tego samego logo w różnych miejscach to dwie rzeczy, które czytelnik napotyka. Umiejscowienie obrazów i geometria EMU pozycjonująca te obiekty jest omówiona w artykule o geometrii obrazów
Kolejność czytania na stronie arkusza
Kolejność czytania to decyzja, którą eksporter musi podjąć, bo arkusz kalkulacyjny nie ma autorskiego przepływu tak, jak dokument. Przyjęta reguła jest stabilna i łatwa do wytłumaczenia: dla każdej strony najpierw tabela, potem figury w kolejności rysowania. Czytelnik słyszy więc tabelaryczną zawartość strony, a potem jej obrazy, zamiast mieć obrazy przeplatane w dowolnej pozycji, jaką obiekty rysunkowe akurat zajęły w pliku
Ta kolejność jest per strona, a nie per dokument, co ma znaczenie w skoroszycie paginującym się na dziesiątki stron: gałąź struktury każdej strony jest samowystarczalna, więc czytelnik przechodzący między stronami nie skacze z powrotem do wcześniejszej tabeli. Jeśli potrzebujesz kontroli nad tym, jak arkusz się paginuje w ogóle, interakcja ustawień strony i obszaru wydruku jest opisana w artykule o ochronie i ustawieniach strony
Co to certyfikuje, a czego nie
Certyfikuje, że obrazy informacyjne docierają do technologii wspomagającej z opisem dostarczonym przez autora i że mapowanie zawartości na strukturę jest poprawne, a nie jedynie obecne. Nie czyni wyjścia zgodnym z PDF/UA i opisywanie go w ten sposób byłoby twierdzeniem, którego implementacja nie udźwignie: wykresy wciąż są artefaktami, a pełne oświadczenie zgodności wymaga audytu każdego typu struktury, każdego fontu i metadanych dokumentu jako całości
Jeśli twoim wymaganiem jest profil archiwalny albo zgodnościowy, a nie poprawa dostępności, to inna konfiguracja eksportu i inny zestaw kontroli, opisane w artykule o archiwalnym eksporcie PDF/A. Te dwie się łączą, ale odpowiadają różnym audytorom
Jedna praktyczna sugestia dla potoku raportowania: audytuj tekst alternatywny w punkcie, gdzie skoroszyt jest generowany, nie w chwili eksportu. Generator wie, co przedstawia każdy obraz wykresu albo osadzony diagram, i może wpisać prawdziwy opis do AltText; przebieg w chwili eksportu potrafi ci tylko powiedzieć, że opisu brakuje. HotXLS czyta i pisze XLS, XLSX, ODS i CSV natywnie z Delphi i C++Builder bez zależności od Excela, a jego opcje konfiguracji eksportu są wypisane na stronie produktu HotXLS Delphi spreadsheet component