Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Add color and font format to returned outline #1104

Merged
merged 3 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all 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 PyPDF2/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
DictionaryObject,
EncodedStreamObject,
Field,
FloatObject,
IndirectObject,
NameObject,
NullObject,
Expand Down Expand Up @@ -837,6 +838,17 @@ def _build_outline(self, node: DictionaryObject) -> Optional[Destination]:
outline[NameObject("/Title")] = title # type: ignore
else:
raise PdfReadError(f"Unexpected destination {dest!r}")

# if outline created, add color and format if present
if outline:
if "/C" in node:
# Color of outline in (R, G, B) with values ranging 0.0-1.0
outline[NameObject("/C")] = ArrayObject(FloatObject(c) for c in node["/C"]) # type: ignore
if "/F" in node:
# specifies style characteristics bold and/or italic
# 1=italic, 2=bold, 3=both
outline[NameObject("/F")] = node["/F"]

return outline

@property
Expand Down
21 changes: 20 additions & 1 deletion PyPDF2/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
Union,
cast,
)

from enum import IntFlag
from ._codecs import ( # noqa: rev_encoding
_pdfdoc_encoding,
_pdfdoc_encoding_rev,
Expand Down Expand Up @@ -1732,6 +1732,15 @@ def additionalActions(self) -> Optional[DictionaryObject]: # pragma: no cover
return self.additional_actions


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

italic = 1
bold = 2


class Destination(TreeObject):
"""
A class representing a destination within a PDF file.
Expand Down Expand Up @@ -1879,6 +1888,16 @@ def bottom(self) -> Optional[FloatObject]:
"""Read-only property accessing the bottom vertical coordinate."""
return self.get("/Bottom", None)

@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", [FloatObject(0), FloatObject(0), FloatObject(0)])

@property
def font_format(self) -> Optional[OutlineFontFlag]:
"""Read-only property accessing the font type. 1=italic, 2=bold, 3=both"""
return self.get("/F", 0)


class Bookmark(Destination):
def write_to_stream(
Expand Down
14 changes: 14 additions & 0 deletions tests/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,3 +858,17 @@ def test_header(src, pdf_header):
reader = PdfReader(src)

assert reader.pdf_header == pdf_header


def test_outline_color():
url = "https://corpora.tika.apache.org/base/docs/govdocs1/924/924546.pdf"
name = "tika-924546.pdf"
reader = PdfReader(BytesIO(get_pdf_from_url(url, name=name)))
assert reader.outlines[0].color == [0, 0, 1]


def test_outline_font_format():
url = "https://corpora.tika.apache.org/base/docs/govdocs1/924/924546.pdf"
name = "tika-924546.pdf"
reader = PdfReader(BytesIO(get_pdf_from_url(url, name=name)))
assert reader.outlines[0].font_format == 2