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)
This commit is contained in:
99
core/engine.py
Normal file
99
core/engine.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
Orquestrador principal de transformações de PDF.
|
||||
|
||||
Coordena validação, compressão, operações e conversão PDF/A
|
||||
encadeando as funções dos submódulos.
|
||||
"""
|
||||
|
||||
import io
|
||||
from typing import List, Tuple
|
||||
|
||||
from .validators import validate_pdf, assert_safe_filename
|
||||
from .compress import compress_pdf
|
||||
from .pdfa import detect_pdfa, strip_pdfa, compress_pdfa
|
||||
from .operations import merge_pdfs, split_pdf, extract_pages, rotate_pages
|
||||
from .operations import extract_text, extract_images, preview_pages
|
||||
|
||||
|
||||
class PDFEngine:
|
||||
"""
|
||||
Interface única para todas as operações do toolkit.
|
||||
Cada método recebe bytes e retorna bytes (ou metadados).
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def inspect(data: bytes, filename: str = "") -> dict:
|
||||
"""Valida e retorna metadados do PDF."""
|
||||
info = validate_pdf(data, filename)
|
||||
if info["valid"]:
|
||||
pdfa_info = detect_pdfa(data)
|
||||
info.update(pdfa_info)
|
||||
return info
|
||||
|
||||
@staticmethod
|
||||
def compress(data: bytes, preset: str = "ebook") -> bytes:
|
||||
"""Comprime PDF com re-amostragem de imagens."""
|
||||
return compress_pdf(data, preset=preset)
|
||||
|
||||
@staticmethod
|
||||
def pdfa_to_regular(data: bytes) -> bytes:
|
||||
"""Remove restrições PDF/A gerando PDF comum."""
|
||||
return strip_pdfa(data)
|
||||
|
||||
@staticmethod
|
||||
def compress_pdfa(data: bytes, quality: int = 60) -> bytes:
|
||||
"""Comprime mantendo a estrutura PDF/A."""
|
||||
return compress_pdfa(data, quality=quality)
|
||||
|
||||
@staticmethod
|
||||
def detect_pdfa(data: bytes) -> dict:
|
||||
"""Detecta se é PDF/A e qual nível."""
|
||||
return detect_pdfa(data)
|
||||
|
||||
@staticmethod
|
||||
def merge(files: List[Tuple[bytes, str]]) -> bytes:
|
||||
"""Junta múltiplos PDFs."""
|
||||
return merge_pdfs(files)
|
||||
|
||||
@staticmethod
|
||||
def split(data: bytes, ranges: List[Tuple[int, int]], base: str = "pagina"):
|
||||
"""Divide PDF em intervalos de páginas."""
|
||||
return split_pdf(data, ranges, base)
|
||||
|
||||
@staticmethod
|
||||
def extract(data: bytes, pages: List[int]) -> bytes:
|
||||
"""Extrai páginas específicas."""
|
||||
return extract_pages(data, pages)
|
||||
|
||||
@staticmethod
|
||||
def rotate(data: bytes, rotations: List[Tuple[int, int]]) -> bytes:
|
||||
"""Rotaciona páginas."""
|
||||
return rotate_pages(data, rotations)
|
||||
|
||||
@staticmethod
|
||||
def text(data: bytes) -> str:
|
||||
"""Extrai texto de todas as páginas."""
|
||||
return extract_text(data)
|
||||
|
||||
@staticmethod
|
||||
def images(data: bytes):
|
||||
"""Extrai imagens do PDF."""
|
||||
return extract_images(data)
|
||||
|
||||
@staticmethod
|
||||
def get_info_string(info: dict) -> str:
|
||||
"""Formata metadados para exibição."""
|
||||
lines = [
|
||||
f"📄 **{info.get('filename', 'documento')}**",
|
||||
f" - Tamanho: {info['file_size_mb']:.2f} MB",
|
||||
f" - Páginas: {info['pages']}",
|
||||
]
|
||||
if info.get("valid"):
|
||||
if info["is_pdfa"]:
|
||||
level = info.get("level", "PDF/A")
|
||||
lines.append(f" - 📋 Tipo: {level}")
|
||||
else:
|
||||
lines.append(" - 📋 Tipo: PDF comum")
|
||||
else:
|
||||
lines.append(f" - ⚠️ Erro: {info['error']}")
|
||||
return "\n".join(lines)
|
||||
Reference in New Issue
Block a user