Exporte um documento do Microsoft Word ou Excel com Salvar como PDF e o ficheiro no disco é, na maioria das vezes, um ficheiro de referência híbrida. Ele carrega suas informações de referência cruzada duas vezes: uma vez como a tabela clássica de largura fixa que terminava cada PDF até a versão 1.4, e uma vez como um fluxo de referência cruzada compactado do qual a maior parte do documento realmente depende. Uma única chave de trailer, /XRefStm, une as duas visualizações, e se uma ferramenta vê ou não o documento inteiro se resume a se ela segue essa chave
Este artigo examina os ficheiros híbridos do lado do consumo: como são os bytes no final do ficheiro, como as duas visualizações se distanciam durante a edição e como um pipeline Delphi pode detectar e rotear entradas híbridas. Como um carregador mescla as visualizações, e por que a ordem não é negociável, é o assunto do nosso artigo do HotPDF sobre o carregamento de ficheiros de referência híbrida; este é sobre reconhecer o layout em primeiro lugar
Por que as exportações do Office gravam o índice duas vezes
O PDF 1.5 introduziu dois recursos que mudaram a forma do ficheiro: fluxos de referência cruzada, que armazenam o índice de objetos como dados binários compactados em vez de uma tabela de texto sem formatação, e fluxos de objetos, que agrupam muitos pequenos objetos em um contêiner compactado por Flate. Um gravador que os usa produz ficheiros menores, mas um leitor de PDF 1.4 não pode abrir o resultado, porque as estruturas nas quais ele se baseia, a palavra-chave xref e o dicionário trailer, sumiram
A ISO 32000-1 §7.5.8.4 define o meio-termo. Um ficheiro de referência híbrida grava ambos: uma tabela de referência cruzada clássica endereçando os objetos que um leitor antigo deve alcançar, o catálogo e a árvore de páginas entre eles, e um fluxo de referência cruzada que indexa todo o resto. Os objetos dobrados em fluxos de objetos são marcados como livres na tabela clássica, então um leitor 1.4 os ignora sem reclamar; suas localizações reais existem apenas no fluxo. O trailer clássico então carrega uma chave /XRefStm mantendo o deslocamento de bytes desse fluxo. Um visualizador antigo nunca lê a chave e renderiza o ficheiro da visualização de tabela. Um visualizador moderno a segue e vê o documento completo. O Word e o Excel emitem exatamente esse layout há anos, e é por isso que os ficheiros híbridos não são um caso extremo exótico, mas uma grande parte do que os pipelines de negócios recebem
Como é o final de um ficheiro híbrido
O layout é mais fácil de entender a partir dos bytes. Aqui está o final de um pequeno ficheiro híbrido, com deslocamentos encurtados; em uma exportação real do Office, o valor de /XRefStm é normalmente um grande deslocamento próximo ao final do ficheiro. A ordem de leitura é a caminhada de trás para frente descrita em nossa visão geral da estrutura de ficheiro PDF: encontre %%EOF, leia startxref, pule para a tabela
Dois detalhes neste dump carregam todo o mecanismo. Primeiro, startxref aponta para a seção clássica, de propósito: esse é o endereço onde um leitor antigo deve chegar. O fluxo de referência cruzada é acessível apenas através da chave /XRefStm dentro do dicionário trailer, então um analisador que nunca procura por essa chave nunca aprende que o fluxo existe. Segundo, os objetos 2 e 3 são mentiras de um tipo benigno. A tabela clássica os declara livres, mas eles são objetos reais dentro de um contêiner compactado; a marcação livre é o que impede que um leitor 1.4 tropece em entradas que não pode usar. Um consumidor que confia apenas na visualização clássica conclui que a maior parte deste documento não existe
Como as duas visualizações se distanciam
Um ficheiro híbrido recém-saído do Word é internamente consistente: ambas as visualizações descrevem o mesmo documento, cada uma dentro do seu escopo declarado. O problema começa quando o ficheiro é editado por uma ferramenta que entende apenas uma das visualizações. Considere um utilitário de carimbo que anexa uma atualização incremental de estilo clássico: novos objetos, uma nova seção xref, uma cadeia /Prev para a seção anterior e um novo trailer. Se esse trailer omitir a chave /XRefStm, a visualização do fluxo fica órfã; se ele copiar o valor antigo, a visualização do fluxo ainda descreve o documento como ele era antes da edição. De qualquer forma, os dois índices agora discordam sobre o que o ficheiro contém
O ficheiro resultante tem uma assinatura de falha distinta: objetos visíveis em uma visualização estão ausentes ou desatualizados na outra. Um leitor que resolve através da visualização do fluxo encontra a versão pré-edição de um objeto atualizado, ou nenhuma entrada para um anexado. Um leitor na visualização da tabela vê a edição, mas perde a noção dos objetos compactados que apenas o fluxo localiza. Na prática, isso surge como campos de formulário que sobrevivem em um visualizador e desaparecem em outro, anotações que uma passagem de carimbo parece ter excluído ou buscas que chegam a um objeto totalmente errado
O que torna esses ficheiros caros para depurar é que o Adobe Acrobat geralmente os abre sem reclamar: quando o índice discorda dos bytes, ele silenciosamente reconstrói os dados de referência cruzada procurando por cabeçalhos de objetos, de modo que quem produziu o ficheiro quebrado não vê nada de errado. A falha surge mais tarde, quando o ficheiro chega a um consumidor estrito, um validador preflight, um serviço de assinatura, um trabalho de ingestão de arquivamento, que confia na estrutura declarada e relata objetos ausentes ou uma incompatibilidade de referência cruzada. "Ele abre bem no Acrobat" é como quase todo ticket de dessincronização híbrida começa
Detectando um ficheiro híbrido em Delphi puro
Classificar entradas não requer uma biblioteca de PDF. A chave /XRefStm só pode ocorrer dentro de um dicionário trailer clássico, e o trailer ativo fica nos últimos kilobytes do ficheiro, porque a especificação exige que %%EOF apareça perto do final físico. Ler uma janela final delimitada e pesquisá-la é o suficiente para a triagem:
Os três resultados se alinham com os três layouts. Um ficheiro apenas clássico tem um trailer, mas nenhum /XRefStm: Falso. Um ficheiro que se compromete totalmente com fluxos de referência cruzada não tem a palavra-chave trailer, suas chaves de trailer vivem no dicionário do fluxo: também Falso, corretamente, porque tal ficheiro é compactado, não híbrido. Apenas o layout de índice duplo retorna Verdadeiro
Para uso em produção, dois endurecimentos valem as linhas extras. Analise o inteiro após /XRefStm, busque esse deslocamento e confirme se um objeto de fluxo com /Type /XRef realmente está lá; um ficheiro truncado pode carregar a chave enquanto o fluxo sumiu, o que pertence a um balde diferente de um híbrido saudável. E trate o tamanho da janela como um parâmetro: 2 KB cobrem a saída comum do Office, mas um dicionário de trailer incomumente grande pode empurrar a palavra-chave para fora do alcance, e ampliar a janela é melhor do que declarar o ficheiro clássico por acidente
Roteando ficheiros híbridos por meio de um pipeline Delphi
A detecção compra uma decisão de roteamento. Para ficheiros que são apenas lidos, renderizados ou validados, use um carregador que resolva ambas as visualizações e verifique o comportamento em vez dos bytes. O componente PDFium analisa a cadeia /XRefStm durante o carregamento, portanto a tabela de objetos que seu código vê é a mesclada, e as verificações descritas em nosso artigo sobre validação de objetos e fluxos de referência cruzada se aplicam inalteradas. Se um híbrido dessincronizado estiver danificado o suficiente para recusar o carregamento, o motor o relata através de seu conjunto de erros, FPDF_ERR_SUCCESS, FPDF_ERR_UNKNOWN, FPDF_ERR_FILE, FPDF_ERR_FORMAT, FPDF_ERR_PASSWORD, FPDF_ERR_SECURITY e FPDF_ERR_PAGE, sendo FPDF_ERR_FORMAT aquele produzido por danos estruturais. No entanto, não se apoie nesse sinal: o PDFium é tolerante por design e reconstrói ficheiros mais inconsistentes silenciosamente, portanto, um carregamento bem-sucedido prova que o ficheiro era recuperável, não que suas duas visualizações concordam. A verificação de consistência significativa é comparar o que uma caminhada completa pelo objeto encontra com o que o /Size do trailer declara
Para ficheiros que seu pipeline modifica, a política mais segura é impedi-los de serem híbridos de forma alguma. Um carregamento seguido de um salvamento completo pelo HotPDF reescreve o documento com uma única referência cruzada autoconsistente em um formato: sem /XRefStm, sem segunda visualização para perder a sincronia, cada objeto de propriedade de exatamente uma entrada de índice. Essa normalização é o que você quer antes da ingestão em ficheiro, antes de um RIP ou serviço de assinatura de downstream estrito, e depois de qualquer edição aplicada a uma entrada híbrida. Funciona porque o carregador mesclou as visualizações corretamente na entrada, o mecanismo que o artigo de referência híbrida do HotPDF detalha
A única classe de ficheiros a ser deixada de lado são os documentos assinados digitalmente. Uma reescrita completa move cada byte, o que invalida qualquer assinatura calculada sobre os intervalos originais. Uma alteração em um híbrido assinado deve entrar como uma atualização incremental adequada que mantenha as duas visualizações; um ficheiro que precisa apenas de leitura deve passar intacto. A normalização é para ficheiros que você possui; ficheiros assinados você apenas anexa a eles
Os PDFs de referência híbrida não são malformados; eles são a ponte de compatibilidade do próprio formato, e os aplicações do Office continuarão a produzi-los enquanto os leitores PDF 1.4 sobreviverem na base de instalação. Um pipeline que pode detectar a chave /XRefStm, validar o documento mesclado com o PDFium Component e regenerar uma saída limpa de índice único com o HotPDF Component os trata como eles são: entradas comuns com um sinalizador extra no trailer