def add_base_methods(object: typing.Any) -> typing.Any: """ This function / decorator adds methods to a given object. These added methods are useful for: - handling linkage (parent/child relationships), - serialization (JSON) - hashing - implementing the "listener" design pattern - etc """ def _to_json_serializable(to_convert=None): """ Convert this object to a representation that can be serialized as JSON """ if isinstance(to_convert, dict): return { to_json_serializable(k): to_json_serializable(v) for k, v in to_convert.items() } if isinstance(to_convert, list): return [to_json_serializable(x) for x in to_convert] if isinstance(to_convert, Decimal): return float(to_convert) if (isinstance(to_convert, HexadecimalString) or isinstance(to_convert, String) or isinstance(to_convert, Name) or isinstance(to_convert, CanvasOperatorName)): return str(to_convert) return None def to_json_serializable(self): """ This function converts this Object to something that can be JSON serialized """ return _to_json_serializable(self) def image_hash_method(self): """ This function hashes Image objects """ w = self.width h = self.height pixels = [ self.getpixel((0, 0)), self.getpixel((0, h - 1)), self.getpixel((w - 1, 0)), self.getpixel((w - 1, h - 1)), ] hashcode = 1 for p in pixels: if isinstance(p, typing.List) or isinstance(p, typing.Tuple): hashcode += 32 * hashcode + sum(p) else: hashcode += 32 * hashcode + p return hashcode def deepcopy_mod(self, memodict={}): """ This function overrides the __deepcopy__ method this was needed """ prev_function_ptr = self.__deepcopy__ self.__deepcopy__ = None # copy out = copy.deepcopy(self, memodict) # restore self.__deepcopy__ = prev_function_ptr # add base methods add_base_methods(out) # return return out # get_parent def get_parent(self): """ This function returns the parent Object of the current Object """ if "_parent" not in vars(self): setattr(self, "_parent", None) return self._parent # set_parent def set_parent(self, parent): """ This function sets the parent Object of the current Object """ if "_parent" not in vars(self): setattr(self, "_parent", None) self._parent = parent return self # get_root def get_root(self): """ This function returns the root parent Object of the current Object """ e = self while e.get_parent() is not None: e = e.get_parent() return e # add_event_listener def add_event_listener(self, event_listener: "EventListener"): """ This function adds an EventListener to this Object """ if "_event_listeners" not in vars(self): setattr(self, "_event_listeners", []) self._event_listeners.append(event_listener) return self # get_event_listener def get_event_listeners(self) -> typing.List["EventListener"]: """ This function returns a typing.List[EventListener] for this Object """ if "_event_listeners" not in vars(self): setattr(self, "_event_listeners", []) return self._event_listeners # _event_occurred def _event_occurred(self, event: "Event"): # type: ignore [name-defined] if "_event_listeners" not in vars(self): setattr(self, "_event_listeners", []) for l in self._event_listeners: l._event_occurred(event) if self.get_parent() is not None: self.get_parent()._event_occurred(event) return self # set_reference def set_reference(self, reference: "Reference"): """ This function sets the Reference for this Object, returning self """ if "_reference" not in vars(self): setattr(self, "_reference", None) assert (self._reference is None or reference is None or self._reference.object_number == reference.object_number or (self._reference.parent_stream_object_number == reference.parent_stream_object_number and self._reference.index_in_parent_stream == reference.index_in_parent_stream)) self._reference = reference return self # get_reference def get_reference(self) -> typing.Optional["Reference"]: """ This function returns the Reference for this Object or None if no Reference was set """ if "_reference" not in vars(self): setattr(self, "_reference", None) return self._reference # set_can_be_referenced def set_can_be_referenced(self, a_flag: bool): """ This function sets whether or not this Object can be referenced. When an object can not be referenced, it is always embedded immediately in the PDF byte stream. """ if "_can_be_referenced" not in vars(self): setattr(self, "_can_be_referenced", None) self._can_be_referenced = a_flag return self # can_be_referenced def can_be_referenced(self) -> bool: """ This function returns whether or not this Object can be referenced. When an object can not be referenced, it is always embedded immediately in the PDF byte stream. """ if "_can_be_referenced" not in vars(self): setattr(self, "_can_be_referenced", True) return self._can_be_referenced object.set_parent = types.MethodType(set_parent, object) object.get_parent = types.MethodType(get_parent, object) object.get_root = types.MethodType(get_root, object) object.add_event_listener = types.MethodType(add_event_listener, object) object.get_event_listeners = types.MethodType(get_event_listeners, object) object._event_occurred = types.MethodType(_event_occurred, object) object.set_reference = types.MethodType(set_reference, object) object.get_reference = types.MethodType(get_reference, object) object.set_can_be_referenced = types.MethodType(set_can_be_referenced, object) object.can_be_referenced = types.MethodType(can_be_referenced, object) object.to_json_serializable = types.MethodType(to_json_serializable, object) if isinstance(object, Image): object.__deepcopy__ = types.MethodType(deepcopy_mod, object) object.__hash__ = types.MethodType(image_hash_method, object)