Skip to content

Commit

Permalink
BUG: JavaScript executed twice (#1439)
Browse files Browse the repository at this point in the history
Fixes #1425, #1420, #482
  • Loading branch information
pubpub-zz committed Nov 20, 2022
1 parent 906c338 commit 03f82d2
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 32 deletions.
41 changes: 16 additions & 25 deletions PyPDF2/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,39 +420,30 @@ def add_js(self, javascript: str) -> None:
>>> output.add_js("this.print({bUI:true,bSilent:false,bShrinkToFit:true});")
# Example: This will launch the print window when the PDF is opened.
"""
# Names / JavaScript prefered to be able to add multiple scripts
if "/Names" not in self._root_object:
self._root_object[NameObject(CA.NAMES)] = DictionaryObject()
names = cast(DictionaryObject, self._root_object[CA.NAMES])
if "/JavaScript" not in names:
names[NameObject("/JavaScript")] = DictionaryObject(
{NameObject("/Names"): ArrayObject()}
)
# cast(DictionaryObject, names[NameObject("/JavaScript")])[NameObject("/Names")] = ArrayObject()
js_list = cast(
ArrayObject, cast(DictionaryObject, names["/JavaScript"])["/Names"]
)

js = DictionaryObject()
js.update(
{
NameObject(PA.TYPE): NameObject("/Action"),
NameObject("/S"): NameObject("/JavaScript"),
NameObject("/JS"): NameObject(f"({javascript})"),
NameObject("/JS"): TextStringObject(f"{javascript}"),
}
)
js_indirect_object = self._add_object(js)

# We need a name for parameterized javascript in the pdf file, but it can be anything.
js_string_name = str(uuid.uuid4())

js_name_tree = DictionaryObject()
js_name_tree.update(
{
NameObject("/JavaScript"): DictionaryObject(
{
NameObject(CA.NAMES): ArrayObject(
[create_string_object(js_string_name), js_indirect_object]
)
}
)
}
)
self._add_object(js_name_tree)

self._root_object.update(
{
NameObject("/OpenAction"): js_indirect_object,
NameObject(CA.NAMES): js_name_tree,
}
)
js_list.append(create_string_object(str(uuid.uuid4())))
js_list.append(self._add_object(js))

def addJS(self, javascript: str) -> None: # pragma: no cover
"""
Expand Down
13 changes: 6 additions & 7 deletions tests/test_javascript.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@pytest.fixture()
def pdf_file_writer():
reader = PdfReader(RESOURCE_ROOT / "crazyones.pdf")
reader = PdfReader(RESOURCE_ROOT / "issue-604.pdf")
writer = PdfWriter()
writer.append_pages_from_reader(reader)
return writer
Expand All @@ -27,17 +27,16 @@ def test_add_js(pdf_file_writer):
assert (
"/JavaScript" in pdf_file_writer._root_object["/Names"]
), "add_js should add a JavaScript name tree under the name catalog."
assert (
"/OpenAction" in pdf_file_writer._root_object
), "add_js should add an OpenAction to the catalog."


def test_overwrite_js(pdf_file_writer):
def test_added_js(pdf_file_writer):
def get_javascript_name():
assert "/Names" in pdf_file_writer._root_object
assert "/JavaScript" in pdf_file_writer._root_object["/Names"]
assert "/Names" in pdf_file_writer._root_object["/Names"]["/JavaScript"]
return pdf_file_writer._root_object["/Names"]["/JavaScript"]["/Names"][0]
return pdf_file_writer._root_object["/Names"]["/JavaScript"]["/Names"][
-2
] # return -2 in order to get the latest javascript

pdf_file_writer.add_js("this.print({bUI:true,bSilent:false,bShrinkToFit:true});")
first_js = get_javascript_name()
Expand All @@ -47,4 +46,4 @@ def get_javascript_name():

assert (
first_js != second_js
), "add_js should overwrite the previous script in the catalog."
), "add_js should add to the previous script in the catalog."

0 comments on commit 03f82d2

Please sign in to comment.