"""Post-processing PDF (pip-only). Obiettivo: - rimuovere pagine *visivamente* vuote (tipicamente solo footer/logo e numero pagina) che possono comparire in template DOCX complessi dopo la conversione. Implementazione: - usa PyMuPDF (fitz) per rasterizzare ogni pagina a bassa risoluzione - calcola la frazione di pixel "quasi bianchi" e il numero di pixel non bianchi - se la pagina è "troppo bianca" e con pochissimi pixel scuri => considerata vuota - crea un nuovo PDF senza quelle pagine. Nota: La soglia è tarata per il caso tipico "pagina bianca con solo numero pagina". """ from __future__ import annotations from pathlib import Path from typing import List def remove_blank_pages_pdf( pdf_path: Path, *, zoom: float = 0.35, white_thr: int = 245, white_frac_thr: float = 0.995, max_nonwhite_pixels: int = 3500, ) -> int: """Rimuove pagine visivamente vuote da un PDF. Ritorna il numero di pagine rimosse. """ import fitz # PyMuPDF import numpy as np pdf_path = Path(pdf_path) doc = fitz.open(str(pdf_path)) if doc.page_count == 0: return 0 keep: List[int] = [] for i in range(doc.page_count): page = doc.load_page(i) pix = page.get_pixmap(matrix=fitz.Matrix(zoom, zoom), alpha=False) img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, 3) white = np.all(img >= white_thr, axis=2) white_frac = float(white.mean()) nonwhite = int((~white).sum()) # Se è molto bianca e con pochissimi pixel non bianchi => pagina vuota if not (white_frac >= white_frac_thr and nonwhite <= max_nonwhite_pixels): keep.append(i) removed = doc.page_count - len(keep) if removed <= 0: doc.close() return 0 new_doc = fitz.open() new_doc.insert_pdf(doc, from_page=min(keep), to_page=max(keep), start_at=0) # insert_pdf sopra copia range continuo: per keep non contiguo bisogna copiare singole pagine if len(keep) != (max(keep) - min(keep) + 1): new_doc = fitz.open() for i in keep: new_doc.insert_pdf(doc, from_page=i, to_page=i) doc.close() tmp = pdf_path.with_suffix(".tmp.pdf") new_doc.save(str(tmp)) new_doc.close() tmp.replace(pdf_path) return removed