Reputation: 65
When I use PyPDF2 to merge two PDF documents, I set the Page Mode to /UseOutlines so that the PDF will display the bookmark pane when the document is opened.
from PyPDF2 import PdfMerger, PdfReader
merger = PdfMerger()
merger.append(PdfReader(filename), import_bookmarks=True)
merger.setPageMode('/UseOutlines')
merger.setPageLayout('/SinglePage')
However, whenever the PDF document is opened the bookmarks are always expanded. Is there a property that I can modify to force the bookmarks to be collapsed when the document is opened?
Upvotes: 1
Views: 1914
Reputation: 11
I have not seen any graphical pdf reader programs that complain about a zero value of /Count (they display the books marks as collapsed with this value), but to be fully PDF spec compliant one should instead set the bookmark /Count to -(number of entries) to make it display as compressed (this works as well in the graphical pdf readers I have checked).
Upvotes: 0
Reputation: 11
this is possible without changing the PyPDF2 source code:
from PyPDF2 import generic
def compress_picklist(writer, baseref=None):
"""sets /Count to zero to compress bookmark picklist"""
parent = baseref
if baseref is None:
parent = writer.get_outline_root()
parent = parent.get_object()
parent[generic.NameObject("/Count")] = generic.NumberObject(0)
# call compress_picklist after every call to add_outline_item
pdf_writer.add_outline_item(item.title, n2, baseref)
compress_picklist(pdf_writer, baseref)
Upvotes: 1
Reputation: 41
I'm using pypdf==3.11.0
.
The bookmarks (outline) tree cannot be collapsed by default using any parameter currently implemented. It is possible by changing:
pypdf/generic/_data_structures.py, Class TreeObject, def insert_child
From:
if "/Count" in parent:
parent[NameObject("/Count")] = NumberObject(
cast(int, parent[NameObject("/Count")]) + n
)
inc_parent_counter(parent.get("/Parent", None), n)
To:
if "/Count" in parent:
parent[NameObject("/Count")] = NumberObject(0)
inc_parent_counter(parent.get("/Parent", None), n)
Upvotes: 1
Reputation: 1
pymupdf can be used to collapse bookmarks:
...
doc = fitz.open("...pdf")
toc = doc.get_toc(False)
lvl1 = [(i, item[1]) for i, item in enumerate(toc) if item[0] == 1]
for i, title in lvl1:
...
d['kind'] = 1
d['collapse'] = True
d['page'] = ...
doc.set_toc_item(i, dest_dict=d)
# output pdf
doc.save(pdfname)
Upvotes: 0
Reputation: 41
Quite late but after a bit of digging and with the hint of @Eugene I found a solution.
You have to do small adjustments on the source code: (Tested for version 1.26.0)
Change the definition of the method addBookmark (~ line 690) to:
def addBookmark(self, title, pagenum, parent=None, color=None, bold=False, italic=False, fit='/Fit', collapse=False, *args):
(add the parameter collapse=False)
Then at the end of the same method change the line (~ line 750) to:
parent.addChild(bookmarkRef, self, collapse)
(add collapse)
Now we have to adjust the addChild method (~ line 665):
def addChild(self, child, pdf, collapse=False):
(again add the parameter collapse=False)
Then exchange the line (~ line 677) in the same method:
self[NameObject('/Count')] = NumberObject(self[NameObject('/Count')] + 1)
with
if collapse: self[NameObject('/Count')] = NumberObject(self[NameObject('/Count')] - 1)
else: self[NameObject('/Count')] = NumberObject(self[NameObject('/Count')] + 1)
That's it!
If you now call the method 'addBookmark()' with parameter 'collapse=True' all bookmarks are closed.
Upvotes: 4
Reputation: 2878
An open outline in PDF contains the /Count
key in the dictionary indicating the number of children inside the outline. To display an outline as closed it should have this key removed or set to -1
. But unfortunately no way to specify it in PyPDF2 yet.
Upvotes: 1