Fix incorrect placement of background when merging PDFs (#5407)

* fix incorrect placement of background when merging PDFs

* add PDF MediaBox correction to code to merge_background as well as render_background
This commit is contained in:
✨ Q (it/its) ✨
2025-09-05 12:26:30 +02:00
committed by GitHub
parent 0c721c17e5
commit fc18659196

View File

@@ -41,6 +41,8 @@ import os
import re import re
import subprocess import subprocess
import tempfile import tempfile
import pypdf
import pypdf.generic
import unicodedata import unicodedata
import uuid import uuid
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
@@ -1187,8 +1189,7 @@ class Renderer:
for i, page in enumerate(fg_pdf.pages): for i, page in enumerate(fg_pdf.pages):
bg_page = self.bg_pdf.pages[i] bg_page = self.bg_pdf.pages[i]
if bg_page.rotation != 0: _correct_page_media_box(bg_page)
bg_page.transfer_rotation_to_content()
page.merge_page(bg_page, over=False) page.merge_page(bg_page, over=False)
output.add_page(page) output.add_page(page)
@@ -1257,8 +1258,7 @@ def merge_background(fg_pdf: PdfWriter, bg_pdf: PdfWriter, out_file, compress):
else: else:
for i, page in enumerate(fg_pdf.pages): for i, page in enumerate(fg_pdf.pages):
bg_page = bg_pdf.pages[i] bg_page = bg_pdf.pages[i]
if bg_page.rotation != 0: _correct_page_media_box(bg_page)
bg_page.transfer_rotation_to_content()
page.merge_page(bg_page, over=False) page.merge_page(bg_page, over=False)
# pdf_header is a string like "%pdf-X.X" # pdf_header is a string like "%pdf-X.X"
@@ -1268,6 +1268,29 @@ def merge_background(fg_pdf: PdfWriter, bg_pdf: PdfWriter, out_file, compress):
fg_pdf.write(out_file) fg_pdf.write(out_file)
def _correct_page_media_box(page: pypdf.PageObject):
if page.rotation != 0:
page.transfer_rotation_to_content()
media_box = page.mediabox
trsf = pypdf.Transformation()
if media_box.bottom != 0:
trsf = trsf.translate(0, -media_box.bottom)
if media_box.left != 0:
trsf = trsf.translate(-media_box.left, 0)
page.add_transformation(trsf, False)
for b in ["/MediaBox", "/CropBox", "/BleedBox", "/TrimBox", "/ArtBox"]:
if b in page:
rr = pypdf.generic.RectangleObject(page[b])
pt1 = trsf.apply_on(rr.lower_left)
pt2 = trsf.apply_on(rr.upper_right)
page[pypdf.generic.NameObject(b)] = pypdf.generic.RectangleObject((
min(pt1[0], pt2[0]),
min(pt1[1], pt2[1]),
max(pt1[0], pt2[0]),
max(pt1[1], pt2[1]),
))
@deconstructible @deconstructible
class PdfLayoutValidator: class PdfLayoutValidator:
def __call__(self, value): def __call__(self, value):