fix: compressão real p/ stream DCTDecode + auth c/ chave vazia

- Substitui xobj._data por page.images[].replace() em compress.py e pdfa.py
- Adiciona compress_with_stats() com feedback honesto na UI
- Trata PDFTOOLKIT_API_KEY vazia como modo dev (auth desabilitado)
- Atualiza engine.py e app.py para exibir redução real ou 'já otimizado'
This commit is contained in:
CM Consultor
2026-08-09 05:01:16 +00:00
parent 4496e9cb55
commit e97adca143
5 changed files with 239 additions and 111 deletions

View File

@@ -139,30 +139,36 @@ def strip_pdfa(data: bytes) -> bytes:
def compress_pdfa(data: bytes, quality: int = 60, max_dim: int = 2000) -> bytes:
"""
Comprime imagens internas mantendo a estrutura PDF/A.
Usa a mesma lógica de compress.compress_pdf mas preserva
metadados XMP e OutputIntents.
Usa a mesma lógica de compress_pdf (ImageFile.replace)
mas preserva metadados XMP e OutputIntents.
"""
from .compress import _downsample_image
from PIL import Image as PILImage
from .compress import _prepare_image
reader = PdfReader(io.BytesIO(data))
writer = PdfWriter()
writer.metadata = reader.metadata
writer = PdfWriter(clone_from=reader)
for page in reader.pages:
if "/XObject" in page.get("/Resources", {}):
xobjects = page["/Resources"]["/XObject"]
for obj_name in list(xobjects.keys()):
xobj = xobjects[obj_name]
if xobj.get("/Subtype") == "/Image":
try:
raw = xobj.get_data()
if raw:
compressed = _downsample_image(raw, quality, max_dim)
xobj._data = compressed
except Exception:
pass
writer.add_page(page)
replaced = 0
for page in writer.pages:
try:
images = list(page.images)
except Exception:
continue
for img_file in images:
if getattr(img_file, "indirect_reference", None) is None:
continue
try:
pil = img_file.image
if pil is None:
continue
prepared, save_kwargs = _prepare_image(
pil, quality=quality, max_dim=max_dim
)
img_file.replace(prepared, **save_kwargs)
replaced += 1
except Exception:
pass
out_buf = io.BytesIO()
writer.write_stream(out_buf)
writer.write(out_buf)
return out_buf.getvalue()