# 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 1. **Entrada**: bytes do PDF via upload (Streamlit) ou HTTP multipart (API) 2. **Validação**: `validators.validate_pdf()` checa magic number, lê metadados 3. **Detecção PDF/A**: `pdfa.detect_pdfa()` verifica XMP metadata e OutputIntents 4. **Transformação**: operação específica (compressão, split, etc.) 5. **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) ```python engine = PDFEngine() info = engine.inspect(data, "doc.pdf") comprimido = engine.compress(data, preset="ebook") ``` --- ## Módulo `core/compress.py` ### Estratégia de compressão 1. Para cada página, varre `/Resources/XObject` em busca de `/Subtype == /Image` 2. Extrai dados brutos da imagem 3. Redimensiona proporcionalmente se exceder `max_dim` (LANCZOS) 4. Re-comprime em JPEG com `quality` definida 5. Substitui `_data` do objeto XObject 6. 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: 1. **Metadados XMP**: busca padrão `pdfaid:part` + `pdfaid:conformance` via regex 2. **OutputIntents**: verifica `/OutputIntents` no 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: 1. **Sidebar**: upload + seleção de operação + parâmetros + botão executar 2. **Á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