Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pypdf/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,18 @@ class PageObject(DictionaryObject):

original_page: "PageObject" # very local use in writer when appending

def __new__(cls, *args: tuple[Any], **kwargs: dict[Any, Any]) -> "PageObject":
"""__new__ used here to make sure instance.pdf attribute
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an explaining comment, not a docstring, thus please make it a "simple" comment. Are we able to re-use some of the values used here in the __init__ method?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what values do you mean? i would want __init__ to handle initialization of attribute because that is a python standard.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values initialized to None here.

is set. related to #3467.
"""
instance = super().__new__(cls)

instance.pdf = None
instance.inline_images = None
instance.indirect_reference = None

return instance

def __init__(
self,
pdf: Optional[PdfCommonDocProtocol] = None,
Expand Down
4 changes: 3 additions & 1 deletion pypdf/generic/_data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ def clone(
visited: set[tuple[int, int]] = set() # (idnum, generation)
d__ = cast(
"DictionaryObject",
self._reference_clone(self.__class__(), pdf_dest, force_duplicate),
self._reference_clone(self.__new__(self.__class__), pdf_dest, force_duplicate),
# self.__new__(self.__class__) because we want instance of type __class__,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should go before, not after the code.

# where we copy values into later below
)
if ignore_fields is None:
ignore_fields = []
Expand Down
25 changes: 25 additions & 0 deletions tests/generic/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pytest

from pypdf import PdfReader, PdfWriter
from pypdf.annotations._markup_annotations import Polygon
from pypdf.constants import AFRelationship
from pypdf.errors import PdfReadError, PyPdfError
from pypdf.generic import (
Expand Down Expand Up @@ -575,3 +576,27 @@ def test_embedded_file__order():
"test.txt", attachment4.pdf_object.indirect_reference,
"xyz.txt", attachment3.pdf_object.indirect_reference,
]


def test_merge_page_with_annotation():
# added and adapted from issue #3467
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is superfluous.

writer = PdfWriter()
writer2 = PdfWriter()
writer.add_blank_page(100, 100)
writer2.add_blank_page(100, 100)

annotation = Polygon(
vertices=[(50, 550), (200, 650), (70, 750), (50, 700)],
)

writer.add_annotation(0, annotation)

page1 = writer.pages[0]
page2 = writer2.pages[0]
page2.merge_page(page1)

assert page2.annotations[0].get_object()["/Type"] == annotation["/Type"]
assert page2.annotations[0].get_object()["/Subtype"] == annotation["/Subtype"]
assert page2.annotations[0].get_object()["/Vertices"] == annotation["/Vertices"]
assert page2.annotations[0].get_object()["/IT"] == annotation["/IT"]
assert page2.annotations[0].get_object()["/Rect"] == annotation["/Rect"]