""" 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, compress_pdf_with_stats 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 sem retornar um resultado maior que o original. A regravação com pypdf pode aumentar PDFs que já estão comprimidos ou que não possuem imagens adequadas para reamostragem. Nesse caso, preservamos o original em vez de entregar um arquivo maior. """ result, stats = compress_pdf_with_stats(data, preset=preset) if stats["reduced"]: return result return data @staticmethod def compress_with_stats(data: bytes, preset: str = "ebook") -> Tuple[bytes, dict]: """Comprime e retorna (bytes, estatísticas) para feedback na UI.""" result, stats = compress_pdf_with_stats(data, preset=preset) if stats["reduced"]: return result, stats return data, stats @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)