_rectangle.py 3.7 KB

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