O PDF 1.5 introduziu duas estruturas de armazenamento que o formato de arquivo anterior não tinha qualquer forma de exprimir: o fluxo de objetos e o fluxo de referência cruzada. Um fluxo de objetos consiste num único recetáculo com compressão Flate, com a etiqueta /Type /ObjStm, o qual contém muitos pequenos objetos indiretos compactados de uma extremidade à outra em vez de espalhados pelo corpo do arquivo. Um fluxo de referência cruzada é a tabela de pesquisa do arquivo reescrita sob a forma de binário comprimido perante campos de dimensão intermutável, de modo a ficar no lugar ocupado pela tabela ASCII de largura estanque e de caráter fixo na qual encerravam todos os PDFs até atingir a versão 1.4. Caminham juntos. A partir do momento em que os objetos são agrupados num fluxo, a velha tabela de texto perde toda e qualquer capacidade a nível de endereçamento sobre os mesmos, o que confere a necessidade de acompanhamento pelo xref binário
Coloque isto em contraste com a disposição clássica e será fácil de constatar o custo que é suprimido. Num arquivo PDF 1.4, cada objeto indireto assenta sem compressão por trás do seu próprio cabeçalho obj, e a tabela na secção final gasta exatamente 20 bytes de ASCII por entrada, sendo-lhe proibida qualquer compressão. Um documento com 200 000 objetos transporta sensivelmente 4 MB de dados de referência cruzada antes que seja desenhado um único glifo, com todos os corpos de dicionário não comprimidos empilhados sobre os referidos. O PDF 1.5 ataca ambos os números de uma só vez: os dicionários organizam-se nos contentores Flate e a tabela de 4 MB reduz-se a algumas centenas de kilobytes de binário. A norma ISO 32000-1 define as duas estruturas nas alíneas §7.5.7 e §7.5.8
Onde a poupança recai na realidade
Os fluxos de objetos afetam unicamente os objetos sem fluxo, comprimindo assim a estrutura e não os píxeis. O conteúdo da página já se encontrava sujeito à compressão Flate antes da versão 1.5, e os dados das imagens possuem os seus próprios codecs, razão pela qual uma brochura muito povoada de imagens mal se altera. Os arquivos que entram em derrapagem são os da estrutura pesada: AcroForms com milhares de dicionários a nível de campos, árvores de tópicos profundas, elementos dotados com a estrutura para PDF com etiquetas. Estes objetos são ínfimos, numerosos e virtualmente idênticos entre si, sendo essa repetição a característica aproveitada pelo Flate a partir do momento em que estão acomodados perante um único buffer em vez de dispersos pelo corpo com respetivos cabeçalhos encravados no permeio dos mesmos
É fácil subestimar a parte correspondente à sobrecarga que os velhos arquivos representam e de fato acarretam. Um arquivo de formulários que tenha absorvido anos de edições pode muito bem gastar mais de metade dos seus bytes em cabeçalhos de dicionário, preenchimento (padding) de referências cruzadas e revisões nas quais jamais se deterá o olho de qualquer leitor. As duas funcionalidades aqui presentes reclamam e servem-se das duas primeiras das opções mencionadas. A terceira - as revisões acumuladas - cede os seus intentos à mercê unicamente num quadro passível da compactação tão logo o arquivo já não tenha a obrigatoriedade prefigurada em sede de memorizar sobre o fato correspondente aos seus desígnios históricos
No HotPDF, o usuário liga ambos os parâmetros utilizando um par de propriedades, sendo a forma como dependem um do outro mais importante do que a ordem pela qual os escreve:
O UseObjectStreams requer que o UseXRefStream seja definido como True. Chega-se a um objeto com compressão através de uma entrada xref do tipo 2, que regista um número de fluxo de objetos acrescido de um índice, sendo que uma linha de texto clássica de 20 bytes não possui espaço para guardar esse par. Por isso, utilizar por si só o UseObjectStreams não surte qualquer efeito de cariz visível; o bom funcionamento face a esta vertente impõe e determina a configuração em parelha dos dois indicadores face ao prévio momento perante um quadro anterior ao de um BeginDoc. Se os definir após o BeginDoc, o HotPDF já se terá comprometido com a disposição mais antiga
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'catalog-2026.pdf';
Pdf.UseXRefStream := True; // binary xref, prerequisite for ObjStm
Pdf.UseObjectStreams := True; // pack objects into /Type /ObjStm
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 760, 0, 'Compressed structure demo');
Pdf.EndDoc; // emits XRefStm + ObjStm containers
finally
Pdf.Free;
end;
end;O porquê de ambas assumirem o desligado (off) enquanto predefinição
O HotPDF deixa ambas as propriedades como False por predefinição e o motivo evidencia-se na integração com código antigo a jusante. Um leitor que entenda apenas o PDF 1.4 não acusa que não sabe lidar com objetos comprimidos. Em vez disso depara-se com um fluxo de referência cruzada, constata a ausência da totalidade das palavras-chave que esperava no trailer e comunica que a tabela de referência cruzada está danificada ou pura e simplesmente recusa-se a abrir o arquivo. Se a sua saída fluir para uma porta de fax datada, uma impressora de hardware com a execução de um intérprete nela incorporado, ou caso se trate de um parser que alguém tenha escrito em face à especificação 1.4 da há uma década, mantenha ambas as bandeiras inativas no respetivo canal e resigne-se a conviver com arquivos mais extensos e pesados. Num quadro de entrega vocacionado à web, em conformidade ao qual todos os visores da norma comum já leem o PDF 1.5 há quase vinte anos, ativar as referidas bandeiras representará uma enorme compressão adquirida praticamente a troco de nada
Existe um efeito secundário do qual convém alertar a sua equipa de suporte técnico. Depois de os dicionários ficarem reunidos em fluxos de objetos, deixa de fazer sentido efetuar a comparação byte a byte entre os dois arquivos produzidos, já que a alteração de um único campo pode levar ao redesenho (re-Flate) de um recetáculo inteiro, baralhando e confundindo os preceitos de conformidade sobre tudo aquilo que lhe suceda a seguir. Submeta este tipo de arquivos ao contraste de diferenças baseadas no conteúdo dos objetos, não prescindindo perante isto de qualquer comparação binária
Atualizações incrementais e as posições de bytes (byte offsets) que as protegem
Uma assinatura digital cobre um /ByteRange explícito: duas extensões do arquivo físico, dadas como byte offsets absolutos, sobre as quais o digest CMS foi obtido. Reescrever o arquivo, mesmo para algo visualmente idêntico no tela, e esses offsets mover-se-ão todos. O digest deixa de coincidir e a assinatura surge como corrompida. É este o problema exato que a norma ISO 32000-1 §7.5.6 resolve com as atualizações incrementais. Novos objetos ou modificados são acrescentados após o %%EOF existente, e uma nova secção de referências cruzadas é escrita na qual a entrada /Prev aponta para a anterior. Os bytes originais nunca são perturbados, pelo que uma revisão assinada continua a ser verificável e o Acrobat pode apresentar cada uma de forma autónoma no painel de assinaturas
O HotPDF expõe isto através do seu próprio ponto de entrada:
Há duas coisas que atrapalham as pessoas. O BeginIncrementalUpdate tem de receber o nome do arquivo original porque a secção xref anexada regista offsets que apenas têm sentido em relação a esses exatos bytes originais; se apontar para uma cópia com outro nome ou novamente guardada, os offsets vão descrever um arquivo que já não existe. E o ato de guardar funciona unicamente por via da anexação na sua base estrutural pelo que a saída é sempre maior do que a entrada. Este aumento não constitui nenhum desperdício para ser limpo. É precisamente a mesma propriedade que mantém intactas as revisões assinadas previamente
Pdf.BeginIncrementalUpdate('contract-signed.pdf');
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 10);
Pdf.CurrentPage.TextOut(50, 760, 0, 'Addendum recorded 2026-06-11');
Pdf.SaveIncrementalUpdate('contract-updated.pdf'); // appends the delta onlyModificar um arquivo carregado passa pelo LoadFromFile
Os programadores que descobriram o HotPDF pela primeira vez através da sua API de geração tendem a deparar-se com um determinado obstáculo. O BeginDoc abre um documento totalmente novo, o que se torna na ferramenta errada quando a sua intenção passa por alterar um documento já existente. Em vez disso, editar um arquivo existente faz-se através das chamadas de documento carregado:
Misture os dois e o sintoma é um arquivo de saída com todo o novo conteúdo e sem nada do original, porque o BeginDoc construiu um documento completamente novo ao lado daquele que supunha estar a editar. Leia LoadFromFile em conjunto com o SaveLoadedDocument como um vocabulário e BeginDoc associado com EndDoc como outro de raiz diferente. Uma rotina que faça recurso de ambos com e perante um mesmo arquivo encontra-se no limiar e será via de regra quase sempre portadora e com laivos do errado e equivocado em erro
PageCount := Pdf.LoadFromFile('base.pdf');
Pdf.InsertPagesFromDocument(OtherDoc, '1-3', 5); // pages 1-3 after page 5
Pdf.MovePage(2, 5);
Pdf.SaveLoadedDocument('modified.pdf');Quando se deve compactar um arquivo com dados anexados
A gravação apenas de acrescentos acarreta um custo mais lento. Uma tarefa noturna que carimba uma linha de estado no mesmo PDF produz 365 revisões ao longo de um ano, e cada revisão arrasta atrás de si uma nova secção xref. Quando esse histórico tiver ultrapassado a sua utilidade e caso nenhuma assinatura do arquivo necessite de sobreviver, poderá limpar todas as referências ao reserializá-lo através da rota do documento carregado:
Este novo ato de guardar constitui uma reescrita total. Descarta propositadamente as revisões anteriores e quebra qualquer assinatura que ainda subsista no arquivo, pelo que o deve colocar sob o escrutínio da mesma política que adotar para qualquer outro passo de cariz destrutivo. Uma regra de produção que se justifica: proceda à compactação quando a contagem de revisões ultrapassar um limiar, ou quando as referências adicionais (overhead) anexadas ultrapassarem determinada quota face ao arquivo original e nunca compacte um documento cujo painel de assinaturas contenha seja o que for
Pdf.LoadFromFile('stamped.pdf');
Pdf.SaveLoadedDocument('compacted.pdf');Verificar a saída antes do envio
A verificação para este par de características é muito simples. Abra o resultado no Adobe Acrobat e verifique três aspetos: as propriedades do documento indicarão a utilização do PDF 1.5 ou mais recente, a partir do momento em que os fluxos de objetos estiverem ativados; o painel de assinaturas irá também continuar a validar todas as revisões assinadas previamente após uma atualização incremental; por fim, a contagem de páginas e os marcadores resistirão sem danos a todo e qualquer ciclo de carregamentos, alterações e gravações. Num cenário de saída de arquivo, certifique-se de que passa o arquivo através do veraPDF, uma vez que o xref comprimido constitui exatamente a tipologia da estrutura de escrutínio que os validadores rigorosos observam de forma mais exaustiva do que a aplicada através de um leitor ou visualizador complacente alguma vez o venha a fazer. Se o seu trabalho se relacionar com a inclusão de arquivos de elevada e enorme capacidade de dados para entrada, não deixe de conjugar de forma orgânica as vertentes inerentes face ao plano das atualizações incrementais ao preceito e lógicas do guia passo a passo da API Direct File para fluxos de PDF de grandes dimensões, não se esquecendo o fato ao que decorra do abordado no artigo sobre as assinaturas digitais do HotPDF e o PAdES
Ambas as características são fornecidas como parte integrante do Componente HotPDF para o Delphi e o C++Builder, a par das APIs de assinatura, de encriptação, de criação ou de geração de formulários também estas referidas noutros locais do blogue. A página do produto fornece ligações à referência API na totalidade caso se pretenda delinear os preceitos supra referidos para chamadas com o seu pipeline de documentos