Cuando HotXLS exporta una hoja a PDF con el etiquetado automático activado, las imágenes de la hoja que llevan texto alternativo ahora se emiten como elementos de estructura /Figure independientes con una entrada /Alt en Unicode, identificadores de contenido marcado densos y locales por página, y entradas exactas en el árbol de padres. Las imágenes sin texto alternativo se quedan como artifacts decorativos, y los gráficos también se quedan como artifacts. Ese alcance preciso importa: hace que las imágenes informativas sean alcanzables para un lector de pantalla, y no es lo mismo que la conformidad plena con PDF/UA
La mecánica detrás de esto es más interesante que la descripción de la función, porque dos de sus piezas son el tipo de detalle que produce en silencio un PDF estructuralmente válido cuya estructura apunta al contenido equivocado
Qué cuenta como imagen informativa
Solo un AltText no vacío. La propiedad TXLSXImage.AltText hace de ida y vuelta el atributo descr de OOXML de las propiedades no visuales de la imagen, que es donde Excel guarda el texto que un usuario teclea en el panel de texto alternativo. Esa es la única señal en el archivo de que el autor consideró que la imagen lleva información y no decoración, así que es la única señal en la que confía el exportador
Dos casi-aciertos no se aceptan deliberadamente. El campo de título, guardado por separado de la descripción, no es un sustituto: un título es un nombre para el objeto, no un equivalente textual del objeto, y promoverlo a /Alt produciría un documento que pasa una comprobación automatizada mientras anuncia "Picture 3" a un lector de pantalla. Una descripción vacía tampoco es un hueco que haya que rellenar con un marcador de posición; significa que la imagen se queda como artifact, que es el resultado correcto para un logo o una línea divisoria. Los gráficos también se quedan como artifacts por ahora, porque el equivalente textual de un gráfico son sus datos y sintetizar uno a partir de las series sería inventar y no extraer
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];
// Auditar antes de exportar: una imagen sin descripción
// se exportará como artifact decorativo
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;
Por qué la página necesita un único asignador de MCID
Porque el árbol de padres es un arreglo indexado por identificador de contenido marcado, y dos asignadores producen dos entradas que reclaman la misma casilla. El PDF etiquetado conecta contenido y estructura en ambas direcciones. Del lado del contenido, un tramo del flujo de contenido de la página se envuelve en operadores BDC y EMC que llevan un número /MCID único dentro de esa página. Del lado de la estructura, el diccionario de página lleva una clave /StructParents que nombra una fila del /ParentTree del documento, y esa fila es un arreglo cuyo elemento en el índice n es el elemento de estructura dueño del MCID n
Una página de hoja de cálculo contiene celdas de tabla y, ahora, figuras. Si el etiquetador de celdas cuenta sus identificadores desde cero y el etiquetador de figuras también cuenta desde cero, la primera figura reclama la casilla que la primera celda ya posee. Nada del archivo resultante está tan mal formado como para que un analizador lo rechace: el árbol de estructura está intacto, el contenido marcado está balanceado y un validador ve un documento con árbol de padres. Lo que recibe un lector de pantalla es una celda de tabla anunciada como imagen, o una imagen anunciada con el texto de una celda. El exportador asigna entonces desde un contador de nivel de página compartido por ambos etiquetadores, y congela el record de la página solo cuando el número de objeto de la página ya se conoce, ya que la fila del árbol de padres no puede escribirse antes de que la página a la que se refiera tenga identidad
La Figure debe envolver toda la instancia visible
La colocación ingenua es envolver el operador Do que invoca el XObject de imagen, ya que ese es el operador que dibuja la imagen. No basta. Una imagen de hoja de cálculo suele dibujarse con una sombra detrás y una ruta de recorte alrededor, y esas marcas son parte del objeto visible. Dejadas fuera del ámbito /Figure se vuelven contenido sin marcar, que es exactamente el estado que señala una auditoría de estructura
Así que el ámbito de contenido marcado se abre antes de la sombra y se cierra después del dibujo de la imagen, cubriendo también el recorte. El uso compartido se preserva donde compartir es correcto: dos celdas que muestran la misma carga útil de imagen siguen referenciando un XObject de imagen, porque eso es una optimización de nivel de recursos y no tiene nada que ver con la semántica. Lo que recibe cada instancia visible es su propio MCID y su propio elemento de estructura, porque dos apariciones del mismo logo en lugares distintos son dos cosas que un lector encuentra. La colocación de imágenes y la geometría EMU que posiciona estos objetos se cubre en el artículo de geometría de imágenes
Orden de lectura en una página de hoja
El orden de lectura es una decisión que el exportador tiene que tomar, porque una hoja de cálculo no tiene un flujo autorado como lo tiene un documento. La regla adoptada es estable y fácil de explicar: para cada página, primero la tabla, luego las figuras en orden de dibujo. Un lector escucha entonces el contenido tabular de la página y después sus imágenes, en lugar de tener imágenes intercaladas en cualquier posición que los objetos de dibujo casualmente ocuparan en el archivo
Ese orden es por página y no por documento, lo que importa en un libro que pagina en docenas de páginas: la rama de estructura de cada página es autocontenida, así que un lector que se mueve entre páginas no salta de vuelta a una tabla anterior. Si necesitan control sobre cómo pagina la hoja en primer lugar, la interacción de configuración de página y área de impresión se describe en el artículo de protección y configuración de página
Qué certifica esto y qué no
Certifica que las imágenes informativas llegan a la tecnología de asistencia con su descripción suministrada por el autor, y que el mapeo de contenido a estructura es correcto y no solo presente. No vuelve la salida conforme a PDF/UA, y describirla así sería una afirmación que la implementación no puede sostener: los gráficos siguen siendo artifacts, y una declaración plena de conformidad exige una auditoría de cada tipo de estructura, cada fuente y los metadatos del documento como un todo
Si su requisito es un perfil de archivo o de conformidad y no una mejora de accesibilidad, esa es una configuración de exportación distinta y un conjunto de comprobaciones distinto, descrito en el artículo de exportación de archivo PDF/A. Ambas se combinan, pero responden a auditores diferentes
Una sugerencia práctica para un pipeline de reportes: auditen el texto alternativo en el punto donde se genera el libro, no en el momento de exportar. El generador sabe qué representa cada imagen de gráfico o diagrama incrustado, y puede escribir una descripción real en AltText; una pasada en el momento de exportar solo puede decirles que falta una descripción. HotXLS lee y escribe XLS, XLSX, ODS y CSV de forma nativa desde Delphi y C++Builder sin dependencia de Excel, y sus opciones de configuración de exportación están en la página del producto HotXLS Delphi spreadsheet component