Skip to content

Commit

Permalink
ENH: Add PdfWriter.open_destination property (#1431)
Browse files Browse the repository at this point in the history
  • Loading branch information
pubpub-zz committed Nov 25, 2022
1 parent 89bf4c1 commit fdd1058
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
48 changes: 48 additions & 0 deletions PyPDF2/_writer.py
Expand Up @@ -411,6 +411,54 @@ def insertBlankPage(
deprecate_with_replacement("insertBlankPage", "insert_blank_page")
return self.insert_blank_page(width, height, index)

@property
def open_destination(
self,
) -> Union[None, Destination, TextStringObject, ByteStringObject]:
"""
Property to access the opening destination ("/OpenAction" entry in the
PDF catalog).
it returns `None` if the entry does not exist is not set.
:param destination:.
the property can be set to a Destination, a Page or an string(NamedDest) or
None (to remove "/OpenAction")
(value stored in "/OpenAction" entry in the Pdf Catalog)
"""
if "/OpenAction" not in self._root_object:
return None
oa = self._root_object["/OpenAction"]
if isinstance(oa, (str, bytes)):
return create_string_object(str(oa))
elif isinstance(oa, ArrayObject):
try:
page, typ = oa[0:2] # type: ignore
array = oa[2:]
return Destination("OpenAction", page, typ, *array) # type: ignore
except Exception:
raise Exception(f"Invalid Destination {oa}")
else:
return None

@open_destination.setter
def open_destination(self, dest: Union[None, str, Destination, PageObject]) -> None:
if dest is None:
try:
del self._root_object["/OpenAction"]
except KeyError:
pass
elif isinstance(dest, str):
self._root_object[NameObject("/OpenAction")] = TextStringObject(dest)
elif isinstance(dest, Destination):
self._root_object[NameObject("/OpenAction")] = dest.dest_array
elif isinstance(dest, PageObject):
self._root_object[NameObject("/OpenAction")] = Destination(
"Opening",
dest.indirect_ref if dest.indirect_ref is not None else NullObject(),
TextStringObject("/Fit"),
).dest_array

def add_js(self, javascript: str) -> None:
"""
Add Javascript which will launch upon opening this PDF.
Expand Down
42 changes: 42 additions & 0 deletions tests/test_writer.py
Expand Up @@ -9,6 +9,7 @@
from PyPDF2.generic import (
IndirectObject,
NameObject,
NumberObject,
RectangleObject,
StreamObject,
TextStringObject,
Expand Down Expand Up @@ -813,3 +814,44 @@ def test_write_empty_stream():
with pytest.raises(ValueError) as exc:
writer.write("")
assert exc.value.args[0] == "Output(stream=) is empty."


def test_startup_dest():
pdf_file_writer = PdfWriter()
pdf_file_writer.append_pages_from_reader(PdfReader(RESOURCE_ROOT / "issue-604.pdf"))

assert pdf_file_writer.open_destination is None
pdf_file_writer.open_destination = pdf_file_writer.pages[9]
# checked also using Acrobrat to verify the good page is opened
op = pdf_file_writer._root_object["/OpenAction"]
assert op[0] == pdf_file_writer.pages[9].indirect_ref
assert op[1] == "/Fit"
op = pdf_file_writer.open_destination
assert op.raw_get("/Page") == pdf_file_writer.pages[9].indirect_ref
assert op["/Type"] == "/Fit"
pdf_file_writer.open_destination = op
assert pdf_file_writer.open_destination == op

# irrelevant, just for coverage
pdf_file_writer._root_object[NameObject("/OpenAction")][0] = NumberObject(0)
pdf_file_writer.open_destination
with pytest.raises(Exception) as exc:
del pdf_file_writer._root_object[NameObject("/OpenAction")][0]
pdf_file_writer.open_destination
assert "Invalid Destination" in str(exc.value)

pdf_file_writer.open_destination = "Test"
# checked also using Acrobrat to verify open_destination
op = pdf_file_writer._root_object["/OpenAction"]
assert isinstance(op, TextStringObject)
assert op == "Test"
op = pdf_file_writer.open_destination
assert isinstance(op, TextStringObject)
assert op == "Test"

# irrelevant, this is just for coverage
pdf_file_writer._root_object[NameObject("/OpenAction")] = NumberObject(0)
assert pdf_file_writer.open_destination is None
pdf_file_writer.open_destination = None
assert "/OpenAction" not in pdf_file_writer._root_object
pdf_file_writer.open_destination = None

0 comments on commit fdd1058

Please sign in to comment.