Skip to content

Commit

Permalink
Handle bookmarks with null destination
Browse files Browse the repository at this point in the history
  • Loading branch information
mtd91429 committed Jul 9, 2022
1 parent dba85c4 commit 72203eb
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 25 deletions.
58 changes: 34 additions & 24 deletions PyPDF2/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,21 +797,29 @@ def _build_destination(
title: str,
array: List[Union[NumberObject, IndirectObject, NullObject, DictionaryObject]],
) -> Destination:
page, typ = array[0:2]
array = array[2:]
try:
return Destination(title, page, typ, *array) # type: ignore
except PdfReadError:
warnings.warn(f"Unknown destination: {title} {array}", PdfReadWarning)
if self.strict:
raise
else:
# create a link to first Page
tmp = self.pages[0].indirect_ref
indirect_ref = NullObject() if tmp is None else tmp
return Destination(
title, indirect_ref, TextStringObject("/Fit") # type: ignore
)
page, typ = None, None

if isinstance(array, type(None)):
# handle outlines without destination
page = NullObject()
typ = TextStringObject("/Fit")
return Destination(title, page, typ)
else:
page, typ = array[0:2]
array = array[2:]
try:
return Destination(title, page, typ, *array) # type: ignore
except PdfReadError:
warnings.warn(f"Unknown destination: {title} {array}", PdfReadWarning)
if self.strict:
raise
else:
# create a link to first Page
tmp = self.pages[0].indirect_ref
indirect_ref = NullObject() if tmp is None else tmp
return Destination(
title, indirect_ref, TextStringObject("/Fit") # type: ignore
)

def _build_outline(self, node: DictionaryObject) -> Optional[Destination]:
dest, title, outline = None, None, None
Expand All @@ -828,15 +836,17 @@ def _build_outline(self, node: DictionaryObject) -> Optional[Destination]:
title = node["/Title"]
dest = node["/Dest"]

# if destination found, then create outline
if dest:
if isinstance(dest, ArrayObject):
outline = self._build_destination(title, dest) # type: ignore
elif isinstance(dest, str) and dest in self._namedDests:
outline = self._namedDests[dest]
outline[NameObject("/Title")] = title # type: ignore
else:
raise PdfReadError(f"Unexpected destination {dest!r}")
if isinstance(dest, ArrayObject):
outline = self._build_destination(title, dest) # type: ignore
elif isinstance(dest, str) and dest in self._namedDests:
outline = self._namedDests[dest]
outline[NameObject("/Title")] = title # type: ignore
elif isinstance(dest, type(None)):
# outline not required to have destination or GoTo action
# Table 8.4
outline = self._build_destination(title, dest)
else:
raise PdfReadError(f"Unexpected destination {dest!r}")

# if color or text format specifications present, add to outline
if "/C" in node:
Expand Down
8 changes: 7 additions & 1 deletion PyPDF2/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1703,10 +1703,16 @@ def additionalActions(self) -> Optional[DictionaryObject]: # pragma: no cover
deprecate_with_replacement("additionalActions", "additional_actions")
return self.additional_actions


class OutlineItemFlag(IntFlag):
"""
A class used as an enumerable flag for formatting outline font
"""

italic = 1
bold = 2


class Destination(TreeObject):
"""
A class representing a destination within a PDF file.
Expand Down Expand Up @@ -1857,7 +1863,7 @@ def bottom(self) -> Optional[FloatObject]:
@property
def color(self) -> Optional[tuple]:
"""Read-only property accessing the color in (R, G, B) with values 0.0-1.0"""
return self.get("/C", None)
return self.get("/C", (0.0, 0.0, 0.0))

@property
def fmt(self) -> Optional[OutlineItemFlag]:
Expand Down

0 comments on commit 72203eb

Please sign in to comment.