Core operations: - Compress PDF (3 presets: screen, ebook, printer, prepress) - PDF/A detection and conversion to regular PDF - Compress while preserving PDF/A structure - Merge multiple PDFs - Split/extract pages by range - Rotate pages - Extract text and images Interface: - Streamlit web GUI (app.py) - FastAPI REST API with auto OpenAPI docs (api.py) Docs: - README.md, ARCHITECTURE.md, API.md - Unit tests (15/15 passing)
5.2 KiB
5.2 KiB
Arquitetura do pdf-toolkit
Visão geral
O pdf-toolkit é um sistema de duas faces: GUI (Streamlit) e API REST (FastAPI), ambas compartilhando o mesmo núcleo (core/) e configurações (config.py).
┌─────────────────────┐ ┌──────────────────────┐
│ Streamlit (app.py) │ │ FastAPI (api.py) │
│ ─ Porta 8550 │ │ ─ Porta 8555 │
│ ─ Upload drag-drop │ │ ─ Swagger /docs │
│ ─ Preview visual │ │ ─ Redoc /redoc │
└────────┬────────────┘ └──────────┬───────────┘
│ │
└──────────┬──────────────────┘
│
┌──────────▼───────────┐
│ core/ (engine) │
│ ┌─────────────────┐ │
│ │ engine.py │ │← Orquestrador (facade)
│ │ validators.py │ │← Valida entradas
│ │ compress.py │ │← Compressão/redução
│ │ pdfa.py │ │← PDF/A detection & strip
│ │ operations.py │ │← Merge, split, rotate...
│ └─────────────────┘ │
└──────────────────────┘
Fluxo de dados
- Entrada: bytes do PDF via upload (Streamlit) ou HTTP multipart (API)
- Validação:
validators.validate_pdf()checa magic number, lê metadados - Detecção PDF/A:
pdfa.detect_pdfa()verifica XMP metadata e OutputIntents - Transformação: operação específica (compressão, split, etc.)
- Saída: bytes transformados → download (Streamlit) ou Response (API)
Módulo core/engine.py
PDFEngine é uma classe de fachada que unifica todos os submódulos. Cada método:
- Recebe
bytes(ou lista de bytes) - Retorna
bytes(ou metadados dict) - Propaga exceções para o caller (Streamlit ou FastAPI)
engine = PDFEngine()
info = engine.inspect(data, "doc.pdf")
comprimido = engine.compress(data, preset="ebook")
Módulo core/compress.py
Estratégia de compressão
- Para cada página, varre
/Resources/XObjectem busca de/Subtype == /Image - Extrai dados brutos da imagem
- Redimensiona proporcionalmente se exceder
max_dim(LANCZOS) - Re-comprime em JPEG com
qualitydefinida - Substitui
_datado objeto XObject - Re-escreve o PDF com
PdfWriter.write_stream()(já faz compressão de streams)
Por que não usamos linearização?
pypdf não suporta linearização true (fast web view). A opção linearize_pdf() apenas re-escreve o PDF, o que já melhora a estrutura. Para linearização real, seria necessário Ghostscript ou qpdf.
Módulo core/pdfa.py
Detecção de PDF/A
Dois métodos complementares:
- Metadados XMP: busca padrão
pdfaid:part+pdfaid:conformancevia regex - OutputIntents: verifica
/OutputIntentsno dicionário raiz do PDF (obrigatório em PDF/A)
Conversão PDF/A → PDF comum
- Remove metadados XMP que declaram PDF/A
- Remove dicionário
/OutputIntents - Preserva conteúdo visual integralmente
- Mantém metadados não-PDF/A (autor, título, etc.)
Módulo core/operations.py
Operações independentes que não dependem entre si:
| Função | Descrição |
|---|---|
merge_pdfs() |
Concatena PDFs em ordem |
split_pdf() |
Extrai intervalos → múltiplos PDFs |
extract_pages() |
Extrai páginas específicas → 1 PDF |
rotate_pages() |
Rotaciona páginas (90/180/270) |
extract_text() |
Extrai texto de todas as páginas |
extract_images() |
Extrai imagens embutidas |
API (FastAPI)
A API usa File (multipart) para upload e Response para download.
Validação automática via FastAPI:
- Tipo dos parâmetros
- Limite de tamanho (
_read_file()) - Presets válidos
Documentação: /docs (Swagger) e /redoc (Redoc) são gerados automaticamente.
Streamlit (GUI)
A GUI organiza-se em:
- Sidebar: upload + seleção de operação + parâmetros + botão executar
- Área principal: preview dos arquivos ou resultados
Estados:
- Antes de executar: exibe metadados dos PDFs carregados
- Executando: barra de progresso com descrição
- Resultado: download individual ou ZIP com múltiplos arquivos
Dependências
| Pacote | Uso |
|---|---|
streamlit |
Interface web |
fastapi + uvicorn |
API REST |
pypdf |
Leitura/escrita de PDF |
Pillow |
Processamento de imagens |
python-multipart |
Upload na API |
Próximas melhorias possíveis
- Integração com Ghostscript para compressão mais agressiva
- Preview visual de páginas via
pdf2image+poppler-utils - Suporte a PDFs criptografados (senha)
- OCR em PDFs scaneados (Tesseract)
- Concorrência em lote com
asyncio/ThreadPoolExecutor - Autenticação na API (API keys)
- Dockerfile para deploy