Artigo Técnico

Linearização de PDF e Fast Web View: Como Funciona

Coloque um relatório digitalizado de 80 MB atrás de um link, abra-o em um navegador e veja o que acontece: o visualizador fica em um painel em branco até que uma grande fração desses bytes chegue, então pinta a página um de uma só vez. Pule para a página 40 e, em um arquivo mal construído, todo o download pode reiniciar. A parte frustrante é que o leitor só queria a primeira página. A linearização é a resposta estrutural a esse problema. Ela reorganiza um PDF para que um visualizador possa renderizar a página inicial a partir de um pequeno prefixo do arquivo e buscar o resto sob demanda, razão pela qual a Adobe comercializa o recurso como "Fast Web View"

Nada disso é um formato de arquivo diferente. Um PDF linearizado é um PDF comum que um leitor em conformidade abrirá sem tratamento especial. O truque está inteiramente em como os bytes são ordenados e em duas estruturas extras que o arquivo carrega. O ISO 32000-1 especifica todo o arranjo no Anexo F e, uma vez que você tenha visto o layout, o comportamento deixa de parecer mágica e começa a parecer uma troca deliberada da ordem do arquivo pela latência da primeira renderização (first-paint)

O que a linearização realmente reorganiza

Um PDF normal pode espalhar seus objetos em quase qualquer ordem. A tabela de referência cruzada no final do arquivo é o que faz isso funcionar: um leitor busca até o final, lê o ponteiro startxref, carrega o xref e a partir daí pode localizar cada objeto pelo seu deslocamento (offset). Esse design é excelente para arquivos locais, onde buscar o final não custa nada, e ruim para um arquivo transmitido por uma rede, onde o final é exatamente a parte que chega por último. Para renderizar a página um, um leitor convencional precisa do objeto da página, seu fluxo de conteúdo, as fontes a que ele faz referência e quaisquer imagens que ele desenha, e em um arquivo não ordenado estes podem ficar em qualquer lugar, incluindo o megabyte final

A linearização corrige a ordem. Os objetos necessários para exibir a primeira página são reunidos em um bloco contíguo perto do início, logo após uma pequena seção de cabeçalho, para que cheguem cedo no fluxo de bytes. Tudo o mais, as páginas restantes e os recursos que elas compartilham, segue em uma sequência previsível. Uma segunda tabela de referência cruzada completa ainda vive no final para os leitores que ignoram a otimização, mas um arquivo linearizado também coloca uma referência cruzada da primeira página e os parâmetros que um leitor de streaming precisa na frente. O leitor não precisa mais chegar à cauda antes de poder desenhar qualquer coisa

O conjunto de objetos da primeira página e o dicionário de parâmetros de linearização

O primeiríssimo objeto em um arquivo linearizado, após o cabeçalho %PDF, é o dicionário de parâmetros de linearização. É o que um leitor de streaming procura para decidir se a otimização está presente e como usá-la. O dicionário registra o comprimento de todo o arquivo, o deslocamento (offset) de bytes onde a seção de referência cruzada principal começa, o número do objeto da primeira página e a localização e comprimento do fluxo de dicas (hint stream) que segue. Com esses números, um leitor sabe, apenas pelos kilobytes iniciais, quanto deve buscar para mostrar a página um e onde procurar o índice que permite que ele pule para outro lugar

O Anexo F é rigoroso sobre o que "primeira página" significa aqui. A seção da primeira página tem que conter o próprio objeto da página, seus fluxos de conteúdo e os recursos a que esses fluxos fazem referência, de modo que a página seja autossuficiente assim que esse prefixo for baixado. Recursos compartilhados, uma fonte usada em todas as páginas, um logotipo que se repete em um cabeçalho, são tratados de forma especial: eles aparecem cedo o suficiente para servir à primeira página, mas são sinalizados como compartilhados para que o leitor não os busque novamente quando renderizar a página 30 mais tarde. Essa distinção entre objetos privados da página e compartilhados é a parte que a maioria dos "otimizadores" caseiros erram, e errar é o que produz um arquivo que afirma ser linearizado, mas ainda assim trava

Fluxos de dicas (Hint streams): o índice que torna os saltos de página baratos

Mostrar a página um rapidamente é apenas metade do valor. A outra metade é pular para uma página arbitrária sem baixar tudo o que há no meio, e isso é o que os fluxos de dicas (hint streams) fornecem. Um arquivo linearizado carrega uma tabela de dicas de deslocamento de página e uma tabela de dicas de objeto compartilhado, armazenadas como um fluxo referenciado no dicionário de parâmetros. A tabela de deslocamento de página registra, para cada página, onde seus objetos começam no arquivo e até onde vão. A tabela de objetos compartilhados faz o mesmo para recursos usados em várias páginas

Dadas essas tabelas, um leitor que quer a página 40 não analisa o arquivo sequencialmente. Ele consulta a tabela de dicas para aprender o intervalo de bytes que a página 40 ocupa, pede ao servidor exatamente esse intervalo e renderiza a página assim que esses bytes chegam, puxando quaisquer recursos compartilhados que ainda não possua pelo mesmo mecanismo. O fluxo de dicas é, com efeito, um mapa de acesso aleatório colocado sobre o documento, e é a razão pela qual um arquivo de 500 páginas bem linearizado parece responsivo em um link lento, enquanto um não otimizado do mesmo tamanho não parece

Por que o servidor tem que cooperar

A linearização pressupõe que o transporte pode entregar fatias arbitrárias do arquivo, e vale a pena verificar essa suposição antes de creditar o formato por resultados ruins. O mecanismo é o byte-serving via HTTP: o leitor emite solicitações de intervalo (range requests), e o servidor as responde com respostas 206 Partial Content. Se o servidor não anunciar Accept-Ranges: bytes, ou se um proxy ou CDN à frente dele colapsar as solicitações de intervalo em transferências completas, o leitor não tem como buscar a página 40 isoladamente e recai no download do arquivo inteiro. A estrutura dentro do PDF está então perfeitamente correta e inteiramente desperdiçada

Essa é a falha que mais frequentemente é diagnosticada incorretamente como "a linearização não funciona." O arquivo está bom; o caminho de entrega não. Antes de reconstruir um documento, confirme com uma solicitação condicional que o host realmente retorna conteúdo parcial para o URL que o leitor atinge. Muitos hosts estáticos fazem isso por padrão, e muitos servidores de aplicativos e camadas de cache mal configurados não o fazem

Atualizações incrementais silenciosamente quebram a linearização

Aqui está a restrição que surpreende as pessoas que geram arquivos linearizados corretamente e depois se perguntam por que a otimização evapora. A linearização depende de um único layout cuidadosamente ordenado com seu índice na frente. Uma atualização incremental viola isso por design. Quando uma ferramenta adiciona uma assinatura, preenche um campo de formulário ou anexa uma anotação por meio de um salvamento incremental, ela não reescreve o arquivo. Ela anexa os objetos alterados, uma nova seção de referência cruzada e um novo trailer ao final, deixando os bytes originais intactos. Esse anexo é o ponto central das atualizações incrementais: é rápido e preserva a revisão anterior para auditoria ou validação de assinatura

O efeito colateral é que o arquivo agora tem seus dados de referência cruzada mais recentes na cauda, após o bloco da primeira página cuidadosamente posicionado, e o dicionário de parâmetros de linearização na frente descreve um layout que não corresponde mais ao arquivo. Um leitor em conformidade detecta a incompatibilidade e trata o documento como um PDF normal, não linearizado. O Fast Web View desapareceu, embora a estrutura linearizada original ainda esteja lá na primeira metade do arquivo. Se você anexar várias atualizações, cada uma empilha outra revisão no final e a lacuna entre o índice frontal obsoleto e o estado real aumenta

Se o seu fluxo de trabalho precisa de edições e do Fast Web View, a regra segue diretamente da estrutura: edite de forma incremental enquanto o documento estiver em fluxo e, em seguida, relinearize uma vez no final. Uma reescrita completa é o que restaura o layout. Em termos de HotPDF, isso significa que uma edição em andamento passa por BeginIncrementalUpdate e SaveIncrementalUpdate, que anexam um delta, enquanto a etapa de acabamento carrega o documento inteiro e o serializa de novo com LoadFromFile seguido de SaveLoadedDocument, que descarta as revisões antigas acumuladas e emite um layout limpo. A mesma troca aparece com fluxos de objetos: habilitar UseObjectStreams junto com UseXRefStream comprime a referência cruzada e empacota os objetos firmemente, o que ajuda no tamanho do arquivo, mas, como qualquer escolha estrutural, tem que ser aplicada durante essa reescrita final em vez de aparafusada a uma revisão anexada

// In-flight edits: append a delta, keep prior revisions intact.
// This leaves the file NOT linearized.
Pdf.BeginIncrementalUpdate('report.pdf');
Pdf.AddPage;
Pdf.CurrentPage.TextOut(72, 760, 0, 'Addendum');
Pdf.SaveIncrementalUpdate('report.pdf');

// Finishing step: full re-serialization produces one clean layout,
// dropping the stacked revisions. Re-run your linearizer on the output.
Pdf.LoadFromFile('report.pdf');
Pdf.SaveLoadedDocument('report-final.pdf');

O HotPDF não expõe uma rotina "linearizar" de uma única chamada, então o padrão prático é produzir um arquivo limpo e totalmente reescrito e executar um otimizador dedicado sobre ele. Ferramentas de linha de comando lidam com o rearranjo diretamente. O qpdf reescreve um arquivo em formato linearizado com uma única flag (sinalizador):

qpdf --linearize report-final.pdf report-web.pdf

Como saber se um arquivo é linearizado

Não confie no nome do arquivo ou na ferramenta que afirma tê-lo produzido; verifique os bytes. A verificação mais direta é o cabeçalho do arquivo: abra-o e procure pelo dicionário de parâmetros de linearização como o primeiro objeto após o cabeçalho, carregando a chave /Linearized. Um atalho voltado para o leitor é a caixa de diálogo Propriedades do Documento do Acrobat, que relata "Fast Web View: Yes" apenas quando a estrutura está genuinamente presente e atual

Para verificações com script, o qpdf relata tanto a presença quanto a integridade da estrutura, o que importa porque um arquivo pode carregar um dicionário de linearização que não reflete mais seu layout, exatamente o estado que uma atualização incremental deixa para trás:

# Reports "File is linearized" and validates hint tables against the layout
qpdf --check report-web.pdf

# Dumps the linearization parameters and hint data in detail
qpdf --show-linearization report-web.pdf

A etapa de validação é a que compensa o esforço. Uma passagem que apenas confirma que o dicionário existe abençoará felizmente um arquivo cujo índice aponta para os deslocamentos (offsets) errados; uma verificação que reconcilia as tabelas de dicas com as posições reais dos objetos é o que lhe diz se a otimização resistirá sob solicitações de intervalo de um leitor real

A linearização continua valendo a pena ser aplicada a qualquer documento grande servido pela web, especialmente para leitores móveis em conexões instáveis, e custa uma pequena porcentagem do tamanho do arquivo pelo índice carregado antecipadamente. As duas coisas a manter claras são que a estrutura dentro do PDF e o byte-serving fora dele têm que estar corretos, e que qualquer edição posterior desfaz a otimização até você reescrever o arquivo. Trate a relinearização como a última etapa no pipeline, depois que todas as outras alterações forem estabelecidas. O comportamento de referência cruzada, fluxo de objetos (object-stream) e atualização incremental descrito aqui faz parte do modelo estrutural que o Componente HotPDF para Delphi e C++Builder implementa; para o contexto mais amplo sobre layout de arquivos veja como um PDF é estruturado, e para o fluxo de trabalho de atualização incremental e arquivos grandes em código veja o processamento de PDFs grandes do Delphi