Spaces:
Paused
Paused
| from __future__ import annotations | |
| import logging | |
| from pathlib import Path | |
| import fitz | |
| logger = logging.getLogger(__name__) | |
| def composite_overlay( | |
| original_pdf: Path, | |
| overlay_pdf: Path, | |
| output_pdf: Path, | |
| pages: list[int] | None, | |
| ) -> None: | |
| """Stamp overlay_pdf transparently onto the selected pages of original_pdf. | |
| The output contains ONLY the translated pages (those in ``pages``), in | |
| ascending page order — not the whole original document. When ``pages`` is | |
| None every page is kept. For scanned PDFs the original page image is the | |
| background; the overlay PDF carries translated text and cover rects with | |
| sampled bg colors. PyMuPDF's show_pdf_page() composites them in a single | |
| vector operation. | |
| """ | |
| src = fitz.open(str(original_pdf)) | |
| ov = fitz.open(str(overlay_pdf)) | |
| if pages is None: | |
| selected = list(range(src.page_count)) | |
| else: | |
| selected = sorted(p for p in pages if 0 <= p < src.page_count) | |
| # Overlay page i corresponds to the i-th selected source page: source_builder | |
| # emits rendered pages in ascending page_index order, matching sorted(pages). | |
| # Guard a shorter overlay so a missing page never raises. | |
| n = min(len(selected), ov.page_count) | |
| if n < len(selected): | |
| logger.warning( | |
| "Overlay has fewer pages (%d) than selected (%d); stopping early", | |
| ov.page_count, | |
| len(selected), | |
| ) | |
| out = fitz.open() | |
| for i in range(n): | |
| src_idx = selected[i] | |
| out.insert_pdf(src, from_page=src_idx, to_page=src_idx) | |
| out[i].show_pdf_page(out[i].rect, ov, i, overlay=True) | |
| logger.debug( | |
| "Composited overlay page %d → output page %d (source %d)", i, i, src_idx | |
| ) | |
| ov.close() | |
| src.close() | |
| output_pdf.parent.mkdir(parents=True, exist_ok=True) | |
| out.save( | |
| str(output_pdf), | |
| garbage=4, | |
| deflate=True, | |
| deflate_images=True, | |
| deflate_fonts=True, | |
| use_objstms=1, | |
| clean=True, | |
| ) | |
| out.close() | |
| logger.info("Saved %s (%d pages)", output_pdf, n) | |