Artigo Técnico

Figuras de PDF etiquetado a partir de imagens Excel

Quando o HotXLS exporta uma folha de cálculo para PDF com etiquetagem automática ativada, as imagens da folha que transportam texto alternativo passam agora a emitir como elementos de estrutura /Figure independentes com uma entrada /Alt Unicode, identificadores de conteúdo marcado densos e locais à página, e entradas exatas na árvore de pais. As imagens sem texto alternativo mantêm-se como artifacts decorativos, e os gráficos também se mantêm artifacts. Esse âmbito preciso importa: torna as imagens informativas alcançáveis a um leitor de ecrã, e não é a mesma coisa que a conformidade completa com PDF/UA

A mecânica por trás disso é mais interessante do que a descrição da funcionalidade, porque duas dessas peças são o tipo de detalhe que produz silenciosamente um PDF estruturalmente válido cuja estrutura aponta para o conteúdo errado

O que conta como imagem informativa?

Só um AltText não vazio. A propriedade TXLSXImage.AltText faz a viagem de ida e volta do atributo OOXML descr das propriedades não visuais da imagem, que é onde o Excel guarda o texto que um utilizador escreve no painel de texto alternativo. Esse é o único sinal no ficheiro de que o autor considerou que a imagem transporta informação em vez de decoração, por isso é o único sinal em que o exportador confia

Duas quase-opções são deliberadamente não aceites. O campo de título, guardado separadamente da descrição, não é um substituto: um título é um nome para o objeto, não um equivalente textual dele, e promovê-lo para /Alt produziria um documento que passa numa verificação automatizada enquanto anuncia "Imagem 3" a um leitor de ecrã. Uma descrição vazia também não é um buraco a preencher com um marcador; significa que a imagem se mantém artifact, que é o desfecho correto para um logótipo ou uma régua divisória. Os gráficos também permanecem artifacts por agora, porque o equivalente textual de um gráfico são os seus dados e sintetizar um a partir das séries seria invenção em vez de extração

Imagens com AltText não vazio exportam como elementos de estrutura Figure PDF com o seu próprio MCID; descrições vazias e gráficos mantêm-se artifacts
Só a descrição do autor em AltText sinaliza uma imagem informativa; um título sozinho nunca se torna o texto alternativo
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: uma imagem sem descrição
    // será exportada 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;

Porque é que a página precisa de um único alocador de MCID?

Porque a árvore de pais é um array indexado pelo identificador de conteúdo marcado, e dois alocadores produzem duas entradas a reclamar o mesmo lugar. O PDF etiquetado liga o conteúdo à estrutura nos dois sentidos. No lado do conteúdo, um segmento do content stream da página é embrulhado em operadores BDC e EMC que transportam um número /MCID único dentro dessa página. No lado da estrutura, o dicionário da página transporta uma chave /StructParents que nomeia uma linha do /ParentTree do documento, e essa linha é um array cujo elemento no índice n é o elemento de estrutura que possui o MCID n

Uma página de folha de cálculo contém células de tabela e, agora, figuras. Se o etiquetador de células contar os seus identificadores a partir de zero e o etiquetador de figuras também contar a partir de zero, a primeira figura reclama o lugar que a primeira célula já possui. Nada no ficheiro resultante é suficientemente malformado para um parser o rejeitar: a árvore de estrutura está intacta, o conteúdo marcado está equilibrado, e um validador vê um documento com uma árvore de pais. O que um leitor de ecrã recebe é uma célula de tabela anunciada como imagem, ou uma imagem anunciada com o texto de uma célula. O exportador portanto aloca a partir de um contador ao nível da página partilhado por ambos os etiquetadores, e congela o registo da página só depois de o número de objeto da página ser conhecido, já que a linha da árvore de pais não pode ser escrita antes de a página a que se refere ter identidade

Etiquetadores independentes de células e figuras colidem no lugar zero da árvore de pais; um contador de MCID ao nível da página mantém cada marca mapeada a um dono
O ficheiro com colisão ainda passa num validador estrutural; só o anúncio do leitor de ecrã está errado

A Figure tem de embrulhar toda a instância visível

A colocação ingénua é embrulhar o operador Do que invoca o XObject da imagem, já que é o operador que desenha a imagem. Não chega. Uma imagem de folha de cálculo é frequentemente desenhada com uma sombra atrás e um caminho de recorte à volta, e essas marcas fazem parte do objeto visível. Deixadas fora do âmbito /Figure tornam-se conteúdo não marcado, que é exatamente o estado que uma auditoria de estrutura sinaliza

Por isso o âmbito de conteúdo marcado abre antes da sombra e fecha depois do desenho da imagem, cobrindo também o recorte. A partilha é preservada onde a partilha está correta: duas células que mostrem o mesmo conteúdo de imagem continuam a referenciar um único XObject de imagem, porque isso é uma otimização ao nível de recursos e nada tem a ver com semântica. O que cada instância visível recebe é o seu próprio MCID e o seu próprio elemento de estrutura, porque duas ocorrências do mesmo logótipo em lugares diferentes são duas coisas que um leitor encontra. A colocação de imagens e a geometria EMU que posiciona esses objetos está coberta no artigo sobre geometria de imagens

A marca BDC abre o âmbito da Figure antes da sombra e do recorte e o EMC fecha depois do desenho da imagem Do, cobrindo toda a instância visível
Embrulhar só o operador de imagem deixaria sombra e recorte como conteúdo não marcado; a partilha de recursos entre células é preservada

Ordem de leitura numa página de folha de cálculo

A ordem de leitura é uma decisão que o exportador tem de tomar, porque uma folha de cálculo não tem fluxo autoral da forma como um documento tem. A regra adotada é estável e fácil de explicar: para cada página, a tabela vem primeiro, depois as figuras pela ordem de desenho. Um leitor portanto ouve o conteúdo tabular da página e depois as suas imagens, em vez de ter imagens entrelaçadas na posição que os objetos de desenho por acaso ocuparam no ficheiro

Essa ordem é por página e não por documento, o que importa num livro que pagina em dezenas de páginas: o ramo de estrutura de cada página é autossuficiente, pelo que um leitor a mover-se entre páginas não salta de volta para uma tabela anterior. Se precisa de controlo sobre como a folha pagina em primeiro lugar, a interação de configuração de página e área de impressão está descrita no artigo sobre proteção e configuração de página

O que isto certifica, e o que não certifica

Certifica que as imagens informativas chegam à tecnologia de apoio com a descrição fornecida pelo autor, e que o mapeamento de conteúdo para estrutura está correto em vez de meramente presente. Não torna a saída conforme com PDF/UA, e descrevê-la assim seria uma afirmação que a implementação não pode sustentar: os gráficos ainda são artifacts, e uma declaração de conformidade completa exige uma auditoria a cada tipo de estrutura, a cada fonte, e aos metadados do documento como um todo

Se o seu requisito é um perfil de arquivo ou de conformidade em vez de uma melhoria de acessibilidade, essa é uma configuração de exportação diferente e um conjunto diferente de verificações, descrito no artigo sobre exportação de arquivo PDF/A. As duas combinam, mas respondem a auditores diferentes

Uma sugestão prática para uma pipeline de relatórios: auditar o texto alternativo no ponto em que o livro é gerado, não no momento da exportação. O gerador sabe o que cada imagem de gráfico ou diagrama embutido representa, e pode escrever uma descrição real em AltText; uma passagem em tempo de exportação só lhe pode dizer que falta uma descrição. O HotXLS lê e escreve XLS, XLSX, ODS e CSV nativamente a partir de Delphi e C++Builder sem dependência de Excel, e as suas opções de configuração de exportação estão listadas na página de produto do HotXLS Delphi spreadsheet component