Files
pdf-toolkit/docs/ARCHITECTURE.md
CM Consultor 84d4a1eab5 feat: initial release — pdf-toolkit v1.0.0
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)
2026-08-09 02:15:22 +00:00

149 lines
5.2 KiB
Markdown

# 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