Skip to content

Commit

Permalink
ENH: Add ability to add hex encoded colors to outline items (#1186)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtd91429 authored Jul 31, 2022
1 parent 42ae312 commit 7c7ef77
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 14 deletions.
4 changes: 2 additions & 2 deletions PyPDF2/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,7 @@ def add_outline_item(
title: str,
pagenum: int,
parent: Union[None, TreeObject, IndirectObject] = None,
color: Optional[Tuple[float, float, float]] = None,
color: Optional[Union[Tuple[float, float, float], str]] = None,
bold: bool = False,
italic: bool = False,
fit: FitType = "/Fit",
Expand All @@ -1178,7 +1178,7 @@ def add_outline_item(
:param parent: A reference to a parent outline item to create nested
outline items.
:param tuple color: Color of the outline item's font as a red, green, blue tuple
from 0.0 to 1.0
from 0.0 to 1.0 or as a Hex String (#RRGGBB)
:param bool bold: Outline item font is bold
:param bool italic: Outline item font is italic
:param str fit: The fit of the destination page. See
Expand Down
23 changes: 11 additions & 12 deletions PyPDF2/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2017,30 +2017,29 @@ def create_string_object(
def _create_outline_item(
action_ref: IndirectObject,
title: str,
color: Optional[Tuple[float, float, float]],
color: Union[Tuple[float, float, float], str, None],
italic: bool,
bold: bool,
) -> TreeObject:
outline_item = TreeObject()

outline_item.update(
{
NameObject("/A"): action_ref,
NameObject("/Title"): create_string_object(title),
}
)

if color is not None:
if color:
if isinstance(color, str):
color = hex_to_rgb(color)
outline_item.update(
{NameObject("/C"): ArrayObject([FloatObject(c) for c in color])}
)

format_flag = 0
if italic:
format_flag += 1
if bold:
format_flag += 2
if format_flag:
if italic or bold:
format_flag = 0
if italic:
format_flag += 1
if bold:
format_flag += 2
outline_item.update({NameObject("/F"): NumberObject(format_flag)})
return outline_item

Expand Down Expand Up @@ -2074,7 +2073,7 @@ def decode_pdfdocencoding(byte_array: bytes) -> str:


def hex_to_rgb(value: str) -> Tuple[float, float, float]:
return tuple(int(value[i : i + 2], 16) / 255.0 for i in (0, 2, 4)) # type: ignore
return tuple(int(value.lstrip("#")[i : i + 2], 16) / 255.0 for i in (0, 2, 4)) # type: ignore


class AnnotationBuilder:
Expand Down
23 changes: 23 additions & 0 deletions tests/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
TESTS_ROOT = Path(__file__).parent.resolve()
PROJECT_ROOT = TESTS_ROOT.parent
RESOURCE_ROOT = PROJECT_ROOT / "resources"
EXTERNAL_ROOT = Path(PROJECT_ROOT) / "sample-files"


def test_writer_clone():
Expand Down Expand Up @@ -633,3 +634,25 @@ def test_deprecate_bookmark_decorator():
match="bookmark is deprecated as an argument. Use outline_item instead",
):
writer.add_outline_item_dict(bookmark=outline_item)


def test_colors_in_outline_item():
reader = PdfReader(EXTERNAL_ROOT / "004-pdflatex-4-pages/pdflatex-4-pages.pdf")
writer = PdfWriter()
writer.clone_document_from_reader(reader)
purple_rgb = (0.50196, 0, 0.50196)
writer.add_outline_item("First Outline Item", pagenum=2, color="800080")
writer.add_outline_item("Second Outline Item", pagenum=3, color="#800080")
writer.add_outline_item("Third Outline Item", pagenum=4, color=purple_rgb)

target = "tmp-named-color-outline.pdf"
with open(target, "wb") as f:
writer.write(f)

reader2 = PdfReader(target)
for outline_item in reader2.outline:
# convert float to string because of mutability
assert [str(c) for c in outline_item.color] == [str(p) for p in purple_rgb]

# Cleanup
os.remove(target) # remove for testing

0 comments on commit 7c7ef77

Please sign in to comment.