O PDF não é um formato de documento da mesma forma que o Word ou o RTF. Esses formatos armazenam uma sequência de conteúdo que o renderizador interpreta no momento da exibição, pelo que o resultado depende dos tipos de letra e do motor de layout que estiverem presentes. O PDF armazena o resultado desse processo: instruções de renderização precisas, programas de tipos de letra, fluxos de imagem comprimidos e um grafo de objetos que os liga numa descrição autónoma de cada página. O ficheiro contém informação suficiente para reproduzir cada página de forma idêntica em qualquer renderizador em conformidade, o que é o seu principal objetivo de design e a origem de grande parte da complexidade que encontra quando tenta gerar, analisar ou modificar um PDF programaticamente.
O modelo de objetos
Cada PDF é uma coleção de objetos numerados. Um objeto pode ser um booleano, inteiro, número real, nome, string, array, dicionário, fluxo (stream) ou nulo. Quase tudo o que é interessante é um dicionário, que é um conjunto de pares chave-valor onde as chaves são nomes e os valores são qualquer outro tipo de objeto, incluindo referências a outros objetos por número e contagem de gerações. Um fluxo é um dicionário seguido por uma sequência de bytes, tipicamente comprimida.
O dicionário do catálogo é a raiz. Aponta para the árvore de páginas, que organiza os dicionários de páginas numa estrutura de árvore equilibrada em vez de uma lista plana, para que a navegação para a página 5000 de um documento de 10 000 páginas não exija percorrer cada descritor de página anterior. Cada dicionário de página referencia os seus fluxos de conteúdo (uma ou mais sequências de operadores de descrição de página), o seu dicionário de recursos (que, por sua vez, referencia descritores de tipos de letra, espaços de cores e XObjects de imagem) e a sua media box (o espaço de coordenadas em que a página vive). A origem das coordenadas situa-se no canto inferior esquerdo, com o Y positivo a crescer para cima, em unidades de 1/72 de polegada.
No fim do ficheiro encontra-se a tabela de referências cruzadas, que mapeia cada número de objeto para o seu desvio em bytes no ficheiro. É isto que permite o acesso aleatório: o visualizador lê primeiro a tabela de referências cruzadas e depois navega diretamente para os objetos de que necessita. O PDF 1.5 introduziu os fluxos de referências cruzadas, que comprimem a tabela num objeto de fluxo e agrupam objetos relacionados em fluxos de objetos, reduzindo visivelmente o tamanho do ficheiro para documentos com muitos objetos pequenos.
Fluxos de conteúdo e o modelo gráfico
O conteúdo visual de uma página vive num ou mais fluxos de conteúdo. Cada fluxo é uma sequência de operadores de PDF intercalados com os seus operandos. O operador de texto BT inicia um objeto de texto, Tf seleciona um tipo de letra e tamanho a partir do dicionário de recursos, Td posiciona o cursor de texto, Tj ou TJ desenha uma string e ET fecha o objeto de texto. Os gráficos vetoriais seguem um padrão semelhante: m define um ponto inicial de caminho, l anexa um segmento de linha, c anexa uma curva de Bezier e f ou S preenche ou traça o contorno do caminho.
O estado gráfico (graphics state) rege tudo o que acontece entre operadores: matriz de transformação atual, largura de linha, espaço de cores, cor de preenchimento, cor do traço e o caminho de recorte (clipping path). Operadores como q e Q colocam (push) e retiram (pop) o estado gráfico de uma pilha, que é a forma como o PDF implementa transformações de coordenadas locais e substituições de estado temporárias sem afetar o contexto ao seu redor. Os Form XObjects generalizam isto: um fluxo de conteúdo autónomo com o seu próprio dicionário de recursos que pode ser desenhado numa página em posições e escalas arbitrárias com um único operador Do.
Incorporação de tipos de letra e extração de texto
O PDF pode referenciar tipos de letra por nome e depender do visualizador para efetuar uma substituição, mas na prática qualquer documento que pretenda partilhar deve incorporar os dados do tipo de letra. Um tipo de letra Type 1 ou TrueType/OpenType incorporado num PDF contém um dicionário descritor de tipo de letra que aponta para um fluxo de ficheiro de tipo de letra. Para tipos de letra TrueType, esse fluxo contém o programa de tipo de letra binário; para o Type 1, trata-se de dados PFB. O subsetting, que é o que qualquer gerador de PDF profissional faz, elimina os glifos que não são referenciados pelo documento, mantendo o tamanho do ficheiro gerível mesmo para grandes tipos de letra Unicode.
A extração de texto é onde a incorporação de tipos de letra se torna complexa. A representação visual de um caractere é determinada por um glifo no programa de tipo de letra incorporado. O valor Unicode desse caractere é determinado por um fluxo ToUnicode CMap anexado ao dicionário do tipo de letra. Quando o ToUnicode CMap está em falta ou incorreto, o visualizador de PDF consegue renderizar o texto de forma legível mas não o consegue extrair como Unicode significativo, razão pela qual o copiar e colar de alguns PDFs produz lixo. O PDF Etiquetado (Tagged PDF - ISO 32000 §14.8) adiciona uma segunda camada: uma árvore de estrutura lógica que mapeia o conteúdo da página para funções semânticas do documento, como parágrafos, cabeçalhos e células de tabela. Os leitores de ecrã e os motores de refluxo utilizam a árvore de estrutura em vez da ordem bruta do fluxo de conteúdo, o que explica por que razão um PDF visualmente bem organizado pode ainda ser inacessível se a etiquetagem estiver ausente ou incorreta.
Atualizações incrementais e assinaturas digitais
Quando guarda alterações num PDF existente sem o reescrever do zero, os novos objetos são anexados após o corpo original do ficheiro, juntamente com uma nova secção de referências cruzadas e um novo dicionário de trailer. O trailer atualizado aponta para os novos dados de referências cruzadas, e os objetos substituídos permanecem no ficheiro, mas deixam de ser referenciados pela nova cadeia de referências cruzadas. Esta é a atualização incremental e tem duas consequências importantes.
Primeiro, o ficheiro cresce com cada ciclo de gravação. Um documento editado e guardado repetidamente acumula camadas de objetos obsoletos. Ferramentas como o QPDF podem linearizar ou comprimir e reescrever um ficheiro para recuperar esse espaço, mas o comportamento padrão é a acumulação. Segundo, as assinaturas digitais dependem das atualizações incrementais para o seu modelo de integridade. Uma assinatura ISO 32000 cobre um intervalo de bytes do ficheiro, tipicamente tudo exceto o marcador de posição para o próprio valor da assinatura. Quaisquer alterações pós-assinatura que surjam como atualizações incrementais adicionais são visíveis para um leitor de validação como modificações efetuadas após a assinatura, que é exatamente o registo de auditoria pretendido. Contudo, isto também significa que certas modificações, como adicionar uma assinatura de aprovação ou preencher campos de formulário, são explicitamente permitidas pela norma sem invalidar a assinatura original, desde que as alterações estejam em conformidade com as definições de permissão do documento (ISO 32000-2 §12.7.6). Uma modificação que fique fora dessas permissões é sinalizada como não autorizada. Acertar nesta distinção é fundamental quando está a gerar documentos que serão assinados posteriormente.
Níveis de conformidade e a linhagem ISO 32000
O PDF começou como um formato proprietário da Adobe em 1993, absorveu o modelo de imagem do PostScript e, ao longo de quinze versões, acumulou funcionalidades: encriptação no 1.1, formulários interativos no 1.2, assinaturas digitais e estrutura lógica no 1.3, transparência no 1.4, fluxos de objetos no 1.5, encriptação AES no 1.6. A Adobe submeteu o PDF 1.7 à ISO em 2007, resultando na norma ISO 32000-1:2008. A norma ISO 32000-2:2020 cobre o PDF 2.0, que clarificou várias áreas subespecificadas, reviu a derivação de chaves AES-256 (revisão 6 a substituir a revisão 5) e adicionou suporte explícito para ficheiros associados e multimédia rica.
As subnormas derivam da mesma base. O PDF/A (ISO 19005) troca funcionalidades por estabilidade de arquivo: sem encriptação, sem dependências de conteúdos externos, todos os tipos de letra incorporados, espaços de cores independentes do dispositivo e metadados XMP obrigatórios. O PDF/A-1 baseia-se no PDF 1.4, o PDF/A-2 no PDF 1.7 e o PDF/A-3 permite ficheiros incorporados de qualquer formato. O PDF/X (ISO 15930) é o subconjunto de produção gráfica: intenções de saída (output intents), caixas de sangramento e corte, e sem transparência em níveis de conformidade mais antigos. O PDF/UA (ISO 14289) exige uma estrutura etiquetada, mapeamentos Unicode e metadados de idioma para acessibilidade. Estes não são formatos concorrentes; são conjuntos de restrições adicionais sobre o PDF principal, e um único ficheiro pode estar em conformidade com mais do que uma norma em simultâneo, desde que as restrições não entrem em conflito.
Para qualquer pessoa que escreva código que gere ou processe PDF, a referência prática é a norma ISO 32000-2, com atenção redobrada às secções que cobrem o modelo de referências cruzadas (§7.5), o estado gráfico (§8.4), operadores de estado de texto (§9.3), descritores de tipos de letra e ToUnicode (§9.6 e §9.10), formulários interativos (§12.7) e assinaturas digitais (§12.8). A norma é extensa, mas a maioria dos trabalhos programáticos em PDF toca repetidamente numa parte restrita da mesma. Compreender o modelo de objetos e o mecanismo de referências cruzadas é o ponto de partida; tudo o resto é especialização.