Artigo Técnico

Objetos de Câmara do Excel a partir do Delphi: Instantâneos ao Vivo

O HotXLS cria objetos de câmara do Excel em folhas de cálculo XLSX a partir do Delphi através de AddCamera. Um objeto de câmara é uma imagem permanentemente ligada a um intervalo de células: o Excel volta a renderizá-la a partir do intervalo de origem sempre que o livro é aberto ou a origem é alterada, pelo que um dashboard pode mostrar uma vista ao vivo de uma tabela que vive noutra folha, com qualquer tamanho, e rodada se assim o desejar

A funcionalidade existe no Excel como a ferramenta Câmara, um botão que a maioria dos utilizadores nunca viu, porque não está no friso (ribbon) por predefinição. Resolve um problema real de dashboard melhor do que as alternativas: um intervalo copiado fica desatualizado, um gráfico não consegue mostrar conteúdo arbitrário de células, e uma imagem ligada colada à mão não pode ser gerada por código. Um objeto de câmara é a única construção que é simultaneamente viva e arbitrária

Objeto de câmara do HotXLS criado a partir do Delphi: uma imagem ao vivo de Data!$B$2:$D$4 colocada numa folha de dashboard, que o Excel volta a renderizar ao abrir e em cada edição da origem
Um objeto de câmara permanece permanentemente ligado ao seu intervalo de origem, pelo que o Excel volta a renderizar a imagem ao abrir e em cada edição, com qualquer tamanho e a partir de um intervalo noutra folha

Onde é que isto está documentado, e porque é que isso importa?

A especificação principal de folhas de cálculo não descreve os objetos de câmara; são tratados como um detalhe de implementação. A descrição autorizada vive na documentação de marcação de desenhos, sob o título Camera Tool, e saber isto poupa uma tarde inteira a procurar no documento errado

Estruturalmente, um objeto de câmara é um elemento de imagem comum cujas propriedades de imagem não visuais transportam uma lista de extensões. A extensão é identificada por um GUID fixo, e dentro dela um elemento do espaço de nomes de desenho de 2010 regista duas coisas: o intervalo de origem como uma referência absoluta no estilo A1, opcionalmente qualificada por folha, e um identificador de forma. Tudo o resto acerca da imagem é normal

Anatomia XLSX de um objeto de câmara escrito pelo HotXLS a partir do Delphi: um elemento de imagem comum cuja lista de extensões transporta um elemento do espaço de nomes de desenho de 2010 que regista o intervalo de origem absoluto e um identificador de forma
Estruturalmente, uma câmara é uma imagem comum mais um elemento de extensão do espaço de nomes de desenho de 2010, que regista o intervalo de origem absoluto no estilo A1 e um identificador de forma

Criar uma

Existem duas sobrecargas porque duas formas de nomear um intervalo são convenientes. A forma textual recebe a referência exatamente como será armazenada, o que é o que se quer para uma origem entre folhas. A forma de coordenadas recebe quatro coordenadas de células na mesma folha e constrói a referência absoluta por si:

uses
  lxHandleX;

var
  Book: TXLSXWorkbook;
  Dashboard: TXLSXWorksheet;
  Cam: TXLSXImage;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('reporting.xlsx') <> 1 then
      Exit;
    Dashboard := Book.Sheets[0];

    // Vista ao vivo de Data!$B$2:$D$4, colocada sobre B10:F20 no dashboard
    Cam := Dashboard.AddCamera('Data!$B$2:$D$4', 10, 2, 20, 6);

    // A caixa de colocação assume por predefinição as colunas de 64 px e
    // as linhas de 20 px do próprio Excel; ajuste o tamanho desenhado em EMU depois, se necessário
    Cam.WidthEMU := Round(12.5 * 914400 / 2.54);   // 12.5 cm
    Cam.HeightEMU := Round(6.0 * 914400 / 2.54);

    Book.SaveAs('reporting-dashboard.xlsx');
  finally
    Book.Free;
  end;
end;

O objeto devolvido é um objeto de imagem normal com uma propriedade extra, CameraRange, que é não vazia exatamente quando a imagem é uma câmara. É também assim que se deteta câmaras num livro que não criou: enumere as imagens e verifique a propriedade

Porque é que a imagem de marcador de posição não precisa de ser real?

Toda a imagem num pacote XLSX precisa de uma parte de imagem, e um objeto de câmara não é exceção. Mas o Excel ignora essa imagem: ao carregar, volta a renderizar o intervalo ligado e pinta o resultado. Os bytes incorporados existem apenas como uma cache de apresentação para ferramentas que não implementam o comportamento de câmara

Este facto remove todo um subsistema da implementação. Não há necessidade de rasterizar o intervalo de origem, não há necessidade de um motor de renderização para produzir o instantâneo, e não há risco de a imagem em cache discordar da imagem ao vivo no Excel. O HotXLS escreve um metaficheiro de marcador de posição mínimo — um registo de cabeçalho e um registo de fim de ficheiro, 108 bytes no total — o que mantém o pacote estruturalmente completo e não custa nada

Uma consequência a prever: um visualizador que renderiza XLSX sem implementar objetos de câmara mostra o marcador de posição, que está em branco. Se os seus livros forem consumidos por uma ferramenta dessas, um objeto de câmara é a construção errada, e uma imagem renderizada do intervalo é a correta

Parte de imagem de marcador de posição de um objeto de câmara do HotXLS: o Excel volta a renderizar o intervalo ligado ao carregar e ignora o metaficheiro de 108 bytes, enquanto os visualizadores sem suporte para câmara mostram uma imagem em branco
O Excel ignora os bytes incorporados e volta a renderizar o intervalo ligado ao carregar, pelo que o HotXLS escreve apenas um metaficheiro de marcador de posição de 108 bytes, enquanto um visualizador sem suporte para câmara mostra o marcador de posição em branco

A conversão de unidades fácil de errar

A geometria de desenho em Open XML é medida em English Metric Units (EMU), em que uma polegada equivale a 914 400 EMU e um centímetro a 360 000. Os cabeçalhos de metaficheiro, contudo, registam a sua moldura em unidades de 0,01 milímetro. A conversão entre ambos é uma divisão por 360

Vale a pena nomear isto, porque o erro é silencioso. Converter através de pixels a 96 DPI, em vez disso — multiplicando por 2540 e dividindo por 9525 — produz um valor 96 vezes demasiado grande, e nada o rejeita: o pacote é válido, a imagem é colocada corretamente pela âncora, e apenas a moldura declarada do metaficheiro é um disparate. O modelo EMU e o seu comportamento de arredondamento estão descritos em geometria de imagem, unidades EMU e escala

Preservar em ciclos de leitura/gravação um livro que já tem câmaras

Abrir e gravar um livro preserva os objetos de câmara, incluindo o elemento de extensão e a sua referência de intervalo. Isto importa mais do que criá-los: a maioria dos livros com objetos de câmara foi feita no Excel por um analista, e uma biblioteca que os converte silenciosamente em imagens comuns ao gravar destruiu o comportamento ao vivo em que o analista confiava

// Auditar que imagens são câmaras e para onde apontam
for I := 0 to Sheet.Images.Count - 1 do
  if Sheet.Images[I].CameraRange <> '' then
    Writeln(Format('camera %d -> %s',
      [I, Sheet.Images[I].CameraRange]));

Quando se geram dashboards de forma programática, a auditoria é também o teste de regressão: depois de um ciclo de gravar e reabrir, o mesmo número de câmaras tem de apontar para os mesmos intervalos. O tratamento geral de imagens e desenhos, incluindo o modelo de ancoragem que os posiciona, está descrito em gráficos, imagens e desenhos

Quando uma câmara é melhor do que as alternativas

Utilize um objeto de câmara quando a mesma tabela ao vivo tiver de aparecer em várias folhas com tamanhos diferentes, quando um layout de impressão precisar de uma região de uma folha composta ao lado de regiões de outras, ou quando um bloco de resumo tiver de acompanhar edições feitas noutro local sem uma fórmula a ligar cada célula individualmente

Prefira fórmulas comuns quando o alvo for um punhado de células, porque uma fórmula entre folhas é mais simples e todas as ferramentas a compreendem. Prefira um gráfico quando os dados forem genuinamente uma série, e não um bloco formatado. E prefira uma imagem renderizada quando o livro for consumido por ferramentas que não o Excel, ou quando o instantâneo não puder mudar depois da entrega — um relatório arquivado não deve ser ao vivo

Uma nota de layout da prática: uma câmara mostra o intervalo de origem exatamente como está formatado, incluindo células mescladas, formatos condicionais e larguras de coluna. Obter um bloco de dashboard com bom aspeto começa, por isso, por formatar o intervalo de origem como se fosse a saída final, o que é a mesma disciplina descrita em células mescladas e layout de modelos de relatório

Os objetos de câmara, os desenhos e o escritor de pacotes XLSX por trás deles fazem parte da mesma biblioteca para Delphi e C++Builder; a lista completa de funcionalidades está disponível na página do componente de folha de cálculo HotXLS para Delphi