1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
import warnings
from abc import ABC
from typing import TYPE_CHECKING, Optional, Union
from .syntax import PDFString, build_obj_dict, create_dictionary_string
if TYPE_CHECKING:
from .encryption import StandardSecurityHandler
from .syntax import Destination
class Action(ABC):
def __init__(self, next_action: Optional["Action"] = None) -> None:
"""
Args:
next (PDFObject | str): optional reference to another Action to trigger after this one
"""
self.next = next_action
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
raise NotImplementedError
def _serialize(
self,
key_values: Optional[dict[str, object]] = None,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
if key_values is None:
key_values = {}
if self.next:
key_values["Next"] = self.next
obj_dict = build_obj_dict(key_values, _security_handler, _obj_id)
return create_dictionary_string(obj_dict, field_join=" ")
class URIAction(Action):
def __init__(self, uri: str, next_action: Optional[Action] = None) -> None:
super().__init__(next_action)
self.uri = uri
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
return super()._serialize(
{"s": "/URI", "u_r_i": PDFString(self.uri, encrypt=True)},
_security_handler=_security_handler,
_obj_id=_obj_id,
)
class NamedAction(Action):
def __init__(self, action_name: str, next_action: Optional[Action] = None) -> None:
super().__init__(next_action)
if action_name not in ("NextPage", "PrevPage", "FirstPage", "LastPage"):
warnings.warn("Non-standard named action added")
self.action_name = action_name
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
return super()._serialize(
{"s": "/Named", "n": f"/{self.action_name}"},
_security_handler=_security_handler,
_obj_id=_obj_id,
)
class GoToAction(Action):
def __init__(
self, dest: Union[str, "Destination"], next_action: Optional[Action] = None
) -> None:
super().__init__(next_action)
if isinstance(dest, str) and dest.startswith("#"):
dest = PDFString(dest[1:], encrypt=True)
self.dest = dest
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
return super()._serialize(
{"s": "/GoTo", "d": self.dest},
_security_handler=_security_handler,
_obj_id=_obj_id,
)
class GoToRemoteAction(Action):
def __init__(
self, file: str, dest: "Destination", next_action: Optional[Action] = None
) -> None:
super().__init__(next_action)
self.file = file
self.dest = dest
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
return super()._serialize(
{"s": "/GoToR", "f": PDFString(self.file, encrypt=True), "d": self.dest},
_security_handler=_security_handler,
_obj_id=_obj_id,
)
class LaunchAction(Action):
"As of 2022, this does not seem honored by neither Adobe Acrobat nor Sumatra readers."
def __init__(self, file: str, next_action: Optional[Action] = None) -> None:
super().__init__(next_action)
self.file = file
def serialize(
self,
_security_handler: Optional["StandardSecurityHandler"] = None,
_obj_id: Optional[int] = None,
) -> str:
return super()._serialize(
{"s": "/Launch", "f": PDFString(self.file, encrypt=True)},
_security_handler=_security_handler,
_obj_id=_obj_id,
)
# Annotation & actions that we tested implementing,
# but that revealed not be worth the effort:
# * Popup annotation & Hide action: as of june 2021,
# do not seem support neither by Adobe Acrobat nor by Sumatra.
# Moreover, they both use to indirect reference annotations,
# and hence implementing them would need some consequent refactoring,
# as annotations are currently defined "inline", not as dedicated PDF objects.
|