Skip to content

Commit

Permalink
MAINT: Deduplicate Code
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinThoma committed Jun 23, 2022
1 parent 7d820f0 commit 081c65b
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 109 deletions.
89 changes: 31 additions & 58 deletions PyPDF2/_merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
from ._reader import PdfReader
from ._utils import StrByteType, deprecate_with_replacement, str_
from ._writer import PdfWriter
from .constants import GoToActionArguments
from .constants import PagesAttributes as PA
from .constants import TypArguments, TypFitArguments
from .generic import (
ArrayObject,
Bookmark,
Expand Down Expand Up @@ -158,7 +160,7 @@ def merge(
bookmark_typ = Bookmark(
TextStringObject(bookmark),
NumberObject(self.id_count),
NameObject("/Fit"),
NameObject(TypFitArguments.FIT),
)
self.bookmarks += [bookmark_typ, outline] # type: ignore
else:
Expand Down Expand Up @@ -488,65 +490,33 @@ def _write_bookmarks(
def _write_bookmark_on_page(
self, bookmark: Union[Bookmark, Destination], page: _MergedPage
) -> None:
# b[NameObject('/Page')] = p.out_pagedata
bm_type = cast(BookmarkTypes, bookmark["/Type"])
args = [NumberObject(page.id), NameObject(bm_type)]
# nothing more to add
# if b['/Type'] == '/Fit' or b['/Type'] == '/FitB'
if bm_type == "/FitH" or bm_type == "/FitBH":
if "/Top" in bookmark and not isinstance(bookmark["/Top"], NullObject):
args.append(FloatObject(bookmark["/Top"]))
fit2arg_keys: Dict[str, Tuple[str, ...]] = {
TypFitArguments.FIT_H: (TypArguments.TOP,),
TypFitArguments.FIT_BH: (TypArguments.TOP,),
TypFitArguments.FIT_V: (TypArguments.LEFT,),
TypFitArguments.FIT_BV: (TypArguments.LEFT,),
TypFitArguments.XYZ: (TypArguments.LEFT, TypArguments.TOP, "/Zoom"),
TypFitArguments.FIT_R: (
TypArguments.LEFT,
TypArguments.BOTTOM,
TypArguments.RIGHT,
TypArguments.TOP,
),
}
for arg_key in fit2arg_keys.get(bm_type, tuple()):
if arg_key in bookmark and not isinstance(bookmark[arg_key], NullObject):
args.append(FloatObject(bookmark[arg_key]))
else:
args.append(FloatObject(0))
del bookmark["/Top"]
elif bm_type == "/FitV" or bm_type == "/FitBV":
if "/Left" in bookmark and not isinstance(bookmark["/Left"], NullObject):
args.append(FloatObject(bookmark["/Left"]))
else:
args.append(FloatObject(0))
del bookmark["/Left"]
elif bm_type == "/XYZ":
if "/Left" in bookmark and not isinstance(bookmark["/Left"], NullObject):
args.append(FloatObject(bookmark["/Left"]))
else:
args.append(FloatObject(0))
if "/Top" in bookmark and not isinstance(bookmark["/Top"], NullObject):
args.append(FloatObject(bookmark["/Top"]))
else:
args.append(FloatObject(0))
if "/Zoom" in bookmark and not isinstance(bookmark["/Zoom"], NullObject):
args.append(FloatObject(bookmark["/Zoom"]))
else:
args.append(FloatObject(0))
del bookmark["/Top"], bookmark["/Zoom"], bookmark["/Left"]
elif bm_type == "/FitR":
if "/Left" in bookmark and not isinstance(bookmark["/Left"], NullObject):
args.append(FloatObject(bookmark["/Left"]))
else:
args.append(FloatObject(0))
if "/Bottom" in bookmark and not isinstance(
bookmark["/Bottom"], NullObject
):
args.append(FloatObject(bookmark["/Bottom"]))
else:
args.append(FloatObject(0))
if "/Right" in bookmark and not isinstance(bookmark["/Right"], NullObject):
args.append(FloatObject(bookmark["/Right"]))
else:
args.append(FloatObject(0))
if "/Top" in bookmark and not isinstance(bookmark["/Top"], NullObject):
args.append(FloatObject(bookmark["/Top"]))
else:
args.append(FloatObject(0))
del (
bookmark["/Left"],
bookmark["/Right"],
bookmark["/Bottom"],
bookmark["/Top"],
)
del bookmark[arg_key]

bookmark[NameObject("/A")] = DictionaryObject(
{NameObject("/S"): NameObject("/GoTo"), NameObject("/D"): ArrayObject(args)}
{
NameObject(GoToActionArguments.S): NameObject("/GoTo"),
NameObject(GoToActionArguments.D): ArrayObject(args),
}
)

def _associate_dests_to_pages(self, pages: List[_MergedPage]) -> None:
Expand Down Expand Up @@ -621,7 +591,7 @@ def addBookmark(
color: Optional[Tuple[float, float, float]] = None,
bold: bool = False,
italic: bool = False,
fit: FitType = "/Fit",
fit: FitType = TypFitArguments.FIT,
*args: ZoomArgType,
) -> IndirectObject: # pragma: no cover
"""
Expand All @@ -641,7 +611,7 @@ def add_bookmark(
color: Optional[Tuple[float, float, float]] = None,
bold: bool = False,
italic: bool = False,
fit: FitType = "/Fit",
fit: FitType = TypFitArguments.FIT,
*args: ZoomArgType,
) -> IndirectObject:
"""
Expand Down Expand Up @@ -678,7 +648,10 @@ def add_bookmark(
)
dest_array = dest.dest_array
action.update(
{NameObject("/D"): dest_array, NameObject("/S"): NameObject("/GoTo")}
{
NameObject(GoToActionArguments.D): dest_array,
NameObject(GoToActionArguments.S): NameObject("/GoTo"),
}
)
action_ref = self.output._add_object(action)

Expand Down Expand Up @@ -716,7 +689,7 @@ def add_named_destination(self, title: str, pagenum: int) -> None:
dest = Destination(
TextStringObject(title),
NumberObject(pagenum),
NameObject("/FitH"),
NameObject(TypFitArguments.FIT_H),
NumberObject(826),
)
self.named_dests.append(dest)
Expand Down
39 changes: 22 additions & 17 deletions PyPDF2/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from .constants import CatalogDictionary as CD
from .constants import Core as CO
from .constants import DocumentInformationAttributes as DI
from .constants import FieldDictionaryAttributes, GoToActionArguments
from .constants import PageAttributes as PG
from .constants import PagesAttributes as PA
from .constants import TrailerKeys as TK
Expand Down Expand Up @@ -444,16 +445,7 @@ def get_fields(
default, the mapping name is used for keys.
:rtype: dict, or ``None`` if form data could not be located.
"""
field_attributes = {
"/FT": "Field Type",
PA.PARENT: "Parent",
"/T": "Field Name",
"/TU": "Alternate Field Name",
"/TM": "Mapping Name",
"/Ff": "Field Flags",
"/V": "Value",
"/DV": "Default Value",
}
field_attributes = FieldDictionaryAttributes.attributes_dict()
if retval is None:
retval = {}
catalog = cast(DictionaryObject, self.trailer[TK.ROOT])
Expand Down Expand Up @@ -524,11 +516,20 @@ def _check_kids(
self.get_fields(kid.get_object(), retval, fileobj)

def _write_field(self, fileobj: Any, field: Any, field_attributes: Any) -> None:
order = ("/TM", "/T", "/FT", PA.PARENT, "/TU", "/Ff", "/V", "/DV")
order = (
FieldDictionaryAttributes.TM,
FieldDictionaryAttributes.T,
FieldDictionaryAttributes.FT,
FieldDictionaryAttributes.Parent,
FieldDictionaryAttributes.TU,
FieldDictionaryAttributes.Ff,
FieldDictionaryAttributes.V,
FieldDictionaryAttributes.DV,
)
for attr in order:
attr_name = field_attributes[attr]
try:
if attr == "/FT":
if attr == FieldDictionaryAttributes.FT:
# Make the field type value more clear
types = {
"/Btn": "Button",
Expand All @@ -538,12 +539,16 @@ def _write_field(self, fileobj: Any, field: Any, field_attributes: Any) -> None:
}
if field[attr] in types:
fileobj.write(attr_name + ": " + types[field[attr]] + "\n")
elif attr == PA.PARENT:
elif attr == FieldDictionaryAttributes.Parent:
# Let's just write the name of the parent
try:
name = field[PA.PARENT]["/TM"]
name = field[FieldDictionaryAttributes.Parent][
FieldDictionaryAttributes.TM
]
except KeyError:
name = field[PA.PARENT]["/T"]
name = field[FieldDictionaryAttributes.Parent][
FieldDictionaryAttributes.T
]
fileobj.write(attr_name + ": " + name + "\n")
else:
fileobj.write(attr_name + ": " + str(field[attr]) + "\n")
Expand Down Expand Up @@ -785,9 +790,9 @@ def _build_outline(self, node: DictionaryObject) -> Optional[Destination]:
# Action, section 8.5 (only type GoTo supported)
title = node["/Title"]
action = cast(DictionaryObject, node["/A"])
action_type = cast(NameObject, action["/S"])
action_type = cast(NameObject, action[GoToActionArguments.S])
if action_type == "/GoTo":
dest = action["/D"]
dest = action[GoToActionArguments.D]
elif "/Dest" in node and "/Title" in node:
# Destination, section 8.2.1
title = node["/Title"]
Expand Down
39 changes: 29 additions & 10 deletions PyPDF2/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@
from .constants import CatalogAttributes as CA
from .constants import Core as CO
from .constants import EncryptionDictAttributes as ED
from .constants import FieldDictionaryAttributes, GoToActionArguments
from .constants import PageAttributes as PG
from .constants import PagesAttributes as PA
from .constants import StreamAttributes as SA
from .constants import TrailerKeys as TK
from .constants import TypFitArguments
from .generic import (
ArrayObject,
BooleanObject,
Expand Down Expand Up @@ -559,15 +561,29 @@ def update_page_form_field_values(
if PG.PARENT in writer_annot:
writer_parent_annot = writer_annot[PG.PARENT]
for field in fields:
if writer_annot.get("/T") == field:
if writer_annot.get(FieldDictionaryAttributes.T) == field:
writer_annot.update(
{NameObject("/V"): TextStringObject(fields[field])}
{
NameObject(FieldDictionaryAttributes.V): TextStringObject(
fields[field]
)
}
)
if flags:
writer_annot.update({NameObject("/Ff"): NumberObject(flags)})
elif writer_parent_annot.get("/T") == field:
writer_annot.update(
{
NameObject(FieldDictionaryAttributes.Ff): NumberObject(
flags
)
}
)
elif writer_parent_annot.get(FieldDictionaryAttributes.T) == field:
writer_parent_annot.update(
{NameObject("/V"): TextStringObject(fields[field])}
{
NameObject(FieldDictionaryAttributes.V): TextStringObject(
fields[field]
)
}
)

def updatePageFormFieldValues(
Expand Down Expand Up @@ -1051,7 +1067,7 @@ def add_bookmark(
color: Optional[Tuple[float, float, float]] = None,
bold: bool = False,
italic: bool = False,
fit: FitType = "/Fit",
fit: FitType = TypFitArguments.FIT,
*args: ZoomArgType,
) -> IndirectObject:
"""
Expand Down Expand Up @@ -1082,7 +1098,10 @@ def add_bookmark(
)
dest_array = dest.dest_array
action.update(
{NameObject("/D"): dest_array, NameObject("/S"): NameObject("/GoTo")}
{
NameObject(GoToActionArguments.D): dest_array,
NameObject(GoToActionArguments.S): NameObject("/GoTo"),
}
)
action_ref = self._add_object(action)

Expand Down Expand Up @@ -1147,10 +1166,10 @@ def add_named_destination(self, title: str, pagenum: int) -> IndirectObject:
dest = DictionaryObject()
dest.update(
{
NameObject("/D"): ArrayObject(
[page_ref, NameObject("/FitH"), NumberObject(826)]
NameObject(GoToActionArguments.D): ArrayObject(
[page_ref, NameObject(TypFitArguments.FIT_H), NumberObject(826)]
),
NameObject("/S"): NameObject("/GoTo"),
NameObject(GoToActionArguments.S): NameObject("/GoTo"),
}
)

Expand Down
38 changes: 37 additions & 1 deletion PyPDF2/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
PDF Reference, sixth edition, Version 1.7, 2006.
"""

from typing import Dict, Tuple


class Core:
"""Keywords that don't quite belong anywhere else"""
Expand Down Expand Up @@ -202,9 +204,15 @@ class TypFitArguments:
FIT_H = "/FitH"
FIT_BH = "/FitBH"
FIT_R = "/FitR"
XYZ = "/XYZ"


class GoToActionArguments:
S = "/S" # name, required: type of action
D = "/D" # name / byte string /array, required: Destination to jump to

class FieldDistionaryAttributes:

class FieldDictionaryAttributes:
"""TABLE 8.69 Entries common to all field dictionaries (PDF 1.7 reference)"""

FT = "/FT" # name, required for terminal fields
Expand All @@ -218,6 +226,34 @@ class FieldDistionaryAttributes:
DV = "/DV" # text string, optional
AA = "/AA" # dictionary, optional

@classmethod
def attributes(cls) -> Tuple[str, ...]:
return (
cls.FT,
cls.Parent,
cls.Kids,
cls.T,
cls.TU,
cls.TM,
cls.Ff,
cls.V,
cls.DV,
cls.AA,
)

@classmethod
def attributes_dict(cls) -> Dict[str, str]:
return {
cls.FT: "Field Type",
cls.Parent: "Parent",
cls.T: "Field Name",
cls.TU: "Alternate Field Name",
cls.TM: "Mapping Name",
cls.Ff: "Field Flags",
cls.V: "Value",
cls.DV: "Default Value",
}


class DocumentInformationAttributes:
"""TABLE 10.2 Entries in the document information dictionary"""
Expand Down
Loading

0 comments on commit 081c65b

Please sign in to comment.