1from typing import Any, Tuple, Union
2
3from ._base import FloatObject, NumberObject
4from ._data_structures import ArrayObject
5
6
7class RectangleObject(ArrayObject):
8 """
9 This class is used to represent *page boxes* in pypdf.
10
11 These boxes include:
12
13 * :attr:`artbox <pypdf._page.PageObject.artbox>`
14 * :attr:`bleedbox <pypdf._page.PageObject.bleedbox>`
15 * :attr:`cropbox <pypdf._page.PageObject.cropbox>`
16 * :attr:`mediabox <pypdf._page.PageObject.mediabox>`
17 * :attr:`trimbox <pypdf._page.PageObject.trimbox>`
18 """
19
20 def __init__(
21 self, arr: Union["RectangleObject", Tuple[float, float, float, float]]
22 ) -> None:
23 # must have four points
24 assert len(arr) == 4
25 # automatically convert arr[x] into NumberObject(arr[x]) if necessary
26 ArrayObject.__init__(self, [self._ensure_is_number(x) for x in arr]) # type: ignore
27
28 def _ensure_is_number(self, value: Any) -> Union[FloatObject, NumberObject]:
29 if not isinstance(value, (FloatObject, NumberObject)):
30 value = FloatObject(value)
31 return value
32
33 def scale(self, sx: float, sy: float) -> "RectangleObject":
34 return RectangleObject(
35 (
36 float(self.left) * sx,
37 float(self.bottom) * sy,
38 float(self.right) * sx,
39 float(self.top) * sy,
40 )
41 )
42
43 def __repr__(self) -> str:
44 return f"RectangleObject({list(self)!r})"
45
46 @property
47 def left(self) -> FloatObject:
48 return self[0]
49
50 @left.setter
51 def left(self, f: float) -> None:
52 self[0] = FloatObject(f)
53
54 @property
55 def bottom(self) -> FloatObject:
56 return self[1]
57
58 @bottom.setter
59 def bottom(self, f: float) -> None:
60 self[1] = FloatObject(f)
61
62 @property
63 def right(self) -> FloatObject:
64 return self[2]
65
66 @right.setter
67 def right(self, f: float) -> None:
68 self[2] = FloatObject(f)
69
70 @property
71 def top(self) -> FloatObject:
72 return self[3]
73
74 @top.setter
75 def top(self, f: float) -> None:
76 self[3] = FloatObject(f)
77
78 @property
79 def lower_left(self) -> Tuple[float, float]:
80 """
81 Property to read and modify the lower left coordinate of this box
82 in (x,y) form.
83 """
84 return self.left, self.bottom
85
86 @lower_left.setter
87 def lower_left(self, value: Tuple[float, float]) -> None:
88 self[0], self[1] = (self._ensure_is_number(x) for x in value)
89
90 @property
91 def lower_right(self) -> Tuple[float, float]:
92 """
93 Property to read and modify the lower right coordinate of this box
94 in (x,y) form.
95 """
96 return self.right, self.bottom
97
98 @lower_right.setter
99 def lower_right(self, value: Tuple[float, float]) -> None:
100 self[2], self[1] = (self._ensure_is_number(x) for x in value)
101
102 @property
103 def upper_left(self) -> Tuple[float, float]:
104 """
105 Property to read and modify the upper left coordinate of this box
106 in (x,y) form.
107 """
108 return self.left, self.top
109
110 @upper_left.setter
111 def upper_left(self, value: Tuple[float, float]) -> None:
112 self[0], self[3] = (self._ensure_is_number(x) for x in value)
113
114 @property
115 def upper_right(self) -> Tuple[float, float]:
116 """
117 Property to read and modify the upper right coordinate of this box
118 in (x,y) form.
119 """
120 return self.right, self.top
121
122 @upper_right.setter
123 def upper_right(self, value: Tuple[float, float]) -> None:
124 self[2], self[3] = (self._ensure_is_number(x) for x in value)
125
126 @property
127 def width(self) -> float:
128 return self.right - self.left
129
130 @property
131 def height(self) -> float:
132 return self.top - self.bottom