Skip to content

Desempenho

PDF Oxide v0.3.11 entrega 0.8ms de extração de texto em média em Python em um corpus de 3.830 PDFs — 5× mais rápido que PyMuPDF e 15× mais rápido que pypdf, com 100% de taxa de sucesso em PDFs válidos.

Resultados dos Benchmarks

Corpus: 3.830 PDFs

Três suítes de teste públicas independentes combinadas:

Suíte PDFs Origem
veraPDF 2.907 Corpus de teste de conformidade PDF/A
Mozilla pdf.js 897 Suíte de teste de renderização de PDF do navegador
SafeDocs 26 Corpus de PDFs malformados do DARPA SafeDocs

Por que este corpus é confiável

Esses não são PDFs escolhidos a dedo. Cada suíte é um corpus de teste estabelecido e revisado por pares, mantido por órgãos de padronização ou grandes projetos de código aberto:

  • veraPDF é o validador oficial de conformidade PDF/A usado pela comunidade de padrões PDF há mais de 10 anos. Seus 2.907 arquivos de teste são atômicos — cada um testa exatamente um recurso da especificação PDF — abrangendo todas as versões PDF/A (1A/1B, 2A/2B/2U, 3A/3B/3U, 4/4E/4F), acessibilidade PDF/UA (UA1, UA2), e ambos ISO 32000-1 (PDF 1.7) e ISO 32000-2 (PDF 2.0). Licenciado sob CC BY 4.0.

  • Mozilla pdf.js alimenta a renderização de PDF no Firefox, processando bilhões de PDFs anualmente. Seus 897 arquivos de teste cobrem casos extremos de renderização do mundo real: documentos complexos de múltiplas páginas, tipos de anotação (estilos de borda, destaques, marcações, anexos de arquivo), widgets de formulário, codificações de fonte incomuns, documentos grandes de teste de estresse e casos extremos de content stream. 7 arquivos são intencionalmente corrompidos para testar a rejeição correta de erros.

  • DARPA SafeDocs é um programa de pesquisa de segurança financiado pelo governo dos EUA focado na robustez de parsers. Seus 26 arquivos visam os casos extremos mais difíceis: ciclos de content stream em fontes Type3, trailers startxref duplos, sintaxe PDF compactada, variações de dialeto, casos extremos de imagens inline, aninhamento recursivo de fontes e PDFs criptografados com senhas Unicode (incluindo UTF-16 LE). Esses arquivos são projetados para travar, bloquear ou explorar parsers vulneráveis.

O que este corpus cobre

  • Todas as principais versões de PDF: PDF 1.0 até PDF 2.0
  • Criptografia e senhas: AES-256, RC4, senhas Unicode, codificação UTF-16 LE
  • Casos extremos de segurança: Estruturas recursivas, ciclos de content stream, trailers malformados, corrupção gerada por fuzzing
  • Diversidade de fontes: TrueType, CIDFont, Type1, Type3, codificações CJK, subconjuntos incorporados
  • Complexidade de documentos: De fixtures de página única a documentos com mais de 10.000 páginas, imagens inline, Form XObjects aninhados
  • Rejeição correta: 7 arquivos intencionalmente quebrados (cabeçalhos PDF ausentes, streams xref inválidos) — uma biblioteca que faz “parsing” destes é menos segura, não mais confiável

Dos 3.830 arquivos, 3.823 são PDFs válidos. Os 7 arquivos inválidos são fixtures de teste para tratamento de erros — PDF Oxide rejeita corretamente todos os 7.

Comparação de Bibliotecas Python

Tempo médio de extração de texto por PDF no corpus completo de 3.830 PDFs:

Biblioteca Média p99 Taxa de Sucesso Licença
PDF Oxide 0.8ms 9ms 100% MIT
PyMuPDF 4.6ms 28ms 99.3% AGPL-3.0
pypdfium2 4.1ms 42ms 99.2% Apache-2.0
pymupdf4llm 55.5ms 280ms 99.1% AGPL-3.0
pdftext 7.3ms 82ms 99.0% GPL-3.0
pdfminer 16.8ms 124ms 98.8% MIT
pdfplumber 23.2ms 189ms 98.8% MIT
markitdown 108.8ms 378ms 98.6% MIT
pypdf 12.1ms 97ms 98.4% BSD-3

PDF Oxide é a biblioteca PDF mais rápida disponível para Python. Diferente do PyMuPDF, usa a licença MIT — sem restrições AGPL para uso comercial.

Comparação de Bibliotecas Rust

Biblioteca Média p99 Taxa de Sucesso Extração de Texto
PDF Oxide 0.8ms 9ms 100% Integrada, nível de produção
oxidize_pdf 13.5ms 11ms 99.1% Básica
unpdf 2.8ms 10ms 95.1% Básica
pdf_extract 4.08ms 37ms 91.5% Básica
lopdf 0.3ms 2ms 80.2% Sem extração integrada

lopdf é mais rápido nos PDFs que consegue processar, mas falha em 20% do corpus. pdf_oxide é o único crate Rust que combina 100% de confiabilidade com extração de texto integrada. Note que lopdf não fornece extração de texto — você precisa construir decodificação de fontes e análise de espaçamento por conta própria.

Qualidade do Texto

PDF Oxide alcança 99,5% de paridade de texto comparado com PyMuPDF e pypdfium2 no corpus completo. A qualidade foi medida comparando a saída de texto extraído caractere por caractere em todos os 3.823 PDFs válidos.

Detalhamento por Corpus

Corpus PDFs PDF Oxide Média pypdfium2 Média PyMuPDF Média
veraPDF 2.907 0.7ms 3.6ms 4.1ms
Mozilla pdf.js 897 1.1ms 5.8ms 6.2ms
SafeDocs 26 0.9ms 4.0ms 4.3ms

Histórico de Otimização: v0.3.5 → v0.3.8

A v0.3.8 eliminou dois gargalos críticos O(n) que fizeram a média cair de 23.3ms para 0.8ms (Python) no mesmo corpus.

1. Cache em Massa da Árvore de Páginas

Antes: get_page() percorria a árvore de páginas a partir da raiz para cada página não cacheada. Para extração sequencial de todas as páginas, isso era O(n) por página e O(n²) no total.

Depois: No primeiro acesso à página, toda a árvore de páginas é percorrida uma vez e todas as páginas são cacheadas em um HashMap<usize, Object>. Todo acesso subsequente é O(1).

Esta é a correção que trouxe um PDF de 10.000 páginas de 55 segundos para 332 milissegundos.

2. Cache de Offset de Scan-for-Object

Antes: Quando objetos estavam ausentes da tabela xref, scan_for_object() lia o arquivo PDF inteiro para cada objeto ausente. PDFs com tags e centenas de elementos de árvore de estrutura que não estavam no xref desencadeavam centenas de leituras completas do arquivo.

Depois: O arquivo é escaneado uma vez e todos os offsets de objetos são cacheados em um HashMap. Buscas subsequentes são O(1).

3. Extração de Texto em Passagem Única

Antes: extract_spans() executava duas passagens sobre o conteúdo da página — primeiro para classificar o tipo de documento (acadêmico, jornal, formulário, etc.), depois para extrair texto.

Depois: A passagem de classificação foi eliminada completamente. Limiares adaptativos conscientes de fonte agora produzem resultados iguais ou melhores em uma única passagem.

4. Pré-alocação de Content Stream

Antes: parse_content_stream() construía o Vec de operadores começando da capacidade padrão, causando realocações repetidas em content streams grandes.

Depois: O Vec é pré-alocado com base no tamanho do stream (data.len() / 20), que estima aproximadamente um operador a cada 20 bytes.

Metodologia

Todos os benchmarks usam a mesma metodologia:

  1. Cada biblioteca processa todos os 3.830 PDFs usando multiprocessing do Python (um PDF por processo)
  2. Timeout de 60 segundos por PDF — qualquer PDF que exceda isso é contado como falha
  3. O texto extraído é salvo em disco por biblioteca para comparação de qualidade
  4. Tempo de relógio medido da abertura do arquivo até a extração final do texto
  5. Sem execuções de aquecimento, sem cache entre arquivos
  6. Thread única por PDF

O harness de benchmark executa todas as 18 bibliotecas (3 Rust, 15 Python) na mesma máquina, mesmo corpus, mesmas condições.

Reproduzindo os Benchmarks

Os corpora de teste públicos estão disponíveis gratuitamente:

Execute a verificação:

cargo run --release --example verify_corpus -- \
    /path/to/veraPDF-corpus \
    /path/to/pdfjs-test \
    /path/to/safedocs \
    --csv results.csv

Características de Desempenho

Onde PDF Oxide É Rápido

  • Extração de texto: O principal alvo de otimização. Sub-milissegundo para documentos típicos.
  • Extração sequencial de múltiplas páginas: O cache da árvore de páginas torna a extração de todas as páginas de um documento grande quase tão rápida quanto extrair uma.
  • PDFs com tags: Travessia da árvore de estrutura e resolução de objetos agora são cacheadas.
  • PDFs malformados: Parsing tolerante com estratégias de fallback evita retentativas caras.

O Que Escala Linearmente

  • Contagem de páginas: Cada página é processada independentemente. 100 páginas leva aproximadamente 100x uma página.
  • Tamanho do content stream: O parsing de operadores é linear no comprimento do stream.
  • Extração de imagens: Proporcional ao número e tamanho das imagens.

Quando Esperar Resultados Mais Lentos

  • PDFs escaneados com OCR: O processamento OCR (se habilitado) é significativamente mais lento que a extração de texto.
  • Renderização: A renderização de páginas para imagens depende da complexidade do conteúdo e do DPI alvo.
  • PDFs fortemente criptografados: A descriptografia AES-256 adiciona overhead por stream.
  • PDFs com milhares de fontes: O parsing de fontes é cacheado por documento, mas o parsing inicial escala com a contagem de fontes.

Próximos Passos