pdfdancer-client-python 0.3.14__py3-none-any.whl → 3.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pdfdancer/__init__.py +77 -22
- pdfdancer/_runtime_version.py +8 -3
- pdfdancer/_version.py +2 -2
- pdfdancer/image_builder.py +23 -3
- pdfdancer/models.py +127 -470
- pdfdancer/page_builder.py +6 -17
- pdfdancer/path_builder.py +127 -6
- pdfdancer/{pdfdancer_v1.py → pdfdancer_v2.py} +848 -1310
- pdfdancer/text_editing.py +1472 -0
- pdfdancer/types.py +94 -399
- {pdfdancer_client_python-0.3.14.dist-info → pdfdancer_client_python-3.0.1.dist-info}/METADATA +181 -137
- pdfdancer_client_python-3.0.1.dist-info/RECORD +18 -0
- {pdfdancer_client_python-0.3.14.dist-info → pdfdancer_client_python-3.0.1.dist-info}/WHEEL +1 -1
- pdfdancer/paragraph_builder.py +0 -554
- pdfdancer/text_line_builder.py +0 -290
- pdfdancer_client_python-0.3.14.dist-info/RECORD +0 -19
- {pdfdancer_client_python-0.3.14.dist-info → pdfdancer_client_python-3.0.1.dist-info}/licenses/LICENSE +0 -0
- {pdfdancer_client_python-0.3.14.dist-info → pdfdancer_client_python-3.0.1.dist-info}/licenses/NOTICE +0 -0
- {pdfdancer_client_python-0.3.14.dist-info → pdfdancer_client_python-3.0.1.dist-info}/top_level.txt +0 -0
pdfdancer/page_builder.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Mapping, Optional, Union
|
|
4
4
|
|
|
5
5
|
from .exceptions import ValidationException
|
|
6
6
|
from .models import AddPageRequest, Orientation, PageRef, PageSize
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from .
|
|
9
|
+
from .pdfdancer_v2 import PDFDancer
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class PageBuilder:
|
|
@@ -47,20 +47,7 @@ class PageBuilder:
|
|
|
47
47
|
self._page_number = int(page_number)
|
|
48
48
|
return self
|
|
49
49
|
|
|
50
|
-
def
|
|
51
|
-
"""
|
|
52
|
-
Deprecated: Use at_page() instead. This method will be removed in a future release.
|
|
53
|
-
"""
|
|
54
|
-
import warnings
|
|
55
|
-
|
|
56
|
-
warnings.warn(
|
|
57
|
-
"at_index() is deprecated, use at_page() instead",
|
|
58
|
-
DeprecationWarning,
|
|
59
|
-
stacklevel=2,
|
|
60
|
-
)
|
|
61
|
-
return self.at_page(page_number + 1)
|
|
62
|
-
|
|
63
|
-
def orientation(self, orientation: Orientation) -> "PageBuilder":
|
|
50
|
+
def orientation(self, orientation: Union[Orientation, str]) -> "PageBuilder":
|
|
64
51
|
if orientation is None:
|
|
65
52
|
raise ValidationException("Orientation cannot be null")
|
|
66
53
|
if isinstance(orientation, str):
|
|
@@ -77,7 +64,9 @@ class PageBuilder:
|
|
|
77
64
|
self._orientation = Orientation.LANDSCAPE
|
|
78
65
|
return self
|
|
79
66
|
|
|
80
|
-
def page_size(
|
|
67
|
+
def page_size(
|
|
68
|
+
self, page_size: Union[PageSize, str, Mapping[str, Any]]
|
|
69
|
+
) -> "PageBuilder":
|
|
81
70
|
if page_size is None:
|
|
82
71
|
raise ValidationException("Page size cannot be null")
|
|
83
72
|
self._page_size = PageSize.coerce(page_size)
|
pdfdancer/path_builder.py
CHANGED
|
@@ -5,13 +5,14 @@ Provides fluent interface for constructing vector paths with lines and curves.
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import math
|
|
8
9
|
from typing import TYPE_CHECKING, List, Optional
|
|
9
10
|
|
|
10
11
|
from .exceptions import ValidationException
|
|
11
12
|
from .models import Bezier, Color, Line, Path, PathSegment, Point, Position
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
14
|
-
from .
|
|
15
|
+
from .pdfdancer_v2 import PDFDancer
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class PathBuilder:
|
|
@@ -31,16 +32,20 @@ class PathBuilder:
|
|
|
31
32
|
"""
|
|
32
33
|
if client is None:
|
|
33
34
|
raise ValidationException("Client cannot be null")
|
|
35
|
+
if page_number < 1:
|
|
36
|
+
raise ValidationException("Page number must be >= 1")
|
|
34
37
|
|
|
35
38
|
self._client = client
|
|
36
39
|
self._page_number = page_number
|
|
37
40
|
self._segments: List[PathSegment] = []
|
|
38
41
|
self._even_odd_fill: bool = False
|
|
39
|
-
self._current_stroke_color: Optional[Color] = Color
|
|
42
|
+
self._current_stroke_color: Optional[Color] = Color.BLACK
|
|
40
43
|
self._current_fill_color: Optional[Color] = None
|
|
41
44
|
self._current_stroke_width: float = 1.0
|
|
42
45
|
self._current_dash_array: Optional[List[float]] = None
|
|
43
46
|
self._current_dash_phase: Optional[float] = None
|
|
47
|
+
self._current_point: Optional[Point] = None
|
|
48
|
+
self._subpath_start: Optional[Point] = None
|
|
44
49
|
|
|
45
50
|
def stroke_color(self, color: Color) -> "PathBuilder":
|
|
46
51
|
"""
|
|
@@ -78,8 +83,8 @@ class PathBuilder:
|
|
|
78
83
|
Returns:
|
|
79
84
|
Self for method chaining
|
|
80
85
|
"""
|
|
81
|
-
if width
|
|
82
|
-
raise ValidationException("Stroke width must be
|
|
86
|
+
if not math.isfinite(width) or width < 0:
|
|
87
|
+
raise ValidationException("Stroke width must be finite and nonnegative")
|
|
83
88
|
self._current_stroke_width = width
|
|
84
89
|
return self
|
|
85
90
|
|
|
@@ -96,10 +101,62 @@ class PathBuilder:
|
|
|
96
101
|
Returns:
|
|
97
102
|
Self for method chaining
|
|
98
103
|
"""
|
|
99
|
-
self.
|
|
104
|
+
self._validate_dash(dash_array, dash_phase)
|
|
105
|
+
self._current_dash_array = list(dash_array)
|
|
100
106
|
self._current_dash_phase = dash_phase
|
|
101
107
|
return self
|
|
102
108
|
|
|
109
|
+
def move_to(self, x: float, y: float) -> "PathBuilder":
|
|
110
|
+
self._validate_coordinates(x, y)
|
|
111
|
+
self._current_point = Point(x, y)
|
|
112
|
+
self._subpath_start = self._current_point
|
|
113
|
+
return self
|
|
114
|
+
|
|
115
|
+
def line_to(self, x: float, y: float) -> "PathBuilder":
|
|
116
|
+
if self._current_point is None:
|
|
117
|
+
raise ValidationException("Call move_to() before line_to()")
|
|
118
|
+
self._validate_coordinates(x, y)
|
|
119
|
+
next_point = Point(x, y)
|
|
120
|
+
self.add_line(self._current_point, next_point)
|
|
121
|
+
self._current_point = next_point
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
def bezier_to(
|
|
125
|
+
self,
|
|
126
|
+
control1_x: float,
|
|
127
|
+
control1_y: float,
|
|
128
|
+
control2_x: float,
|
|
129
|
+
control2_y: float,
|
|
130
|
+
x: float,
|
|
131
|
+
y: float,
|
|
132
|
+
) -> "PathBuilder":
|
|
133
|
+
if self._current_point is None:
|
|
134
|
+
raise ValidationException("Call move_to() before bezier_to()")
|
|
135
|
+
self._validate_coordinates(control1_x, control1_y, control2_x, control2_y, x, y)
|
|
136
|
+
end = Point(x, y)
|
|
137
|
+
self.add_bezier(
|
|
138
|
+
self._current_point,
|
|
139
|
+
Point(control1_x, control1_y),
|
|
140
|
+
Point(control2_x, control2_y),
|
|
141
|
+
end,
|
|
142
|
+
)
|
|
143
|
+
self._current_point = end
|
|
144
|
+
return self
|
|
145
|
+
|
|
146
|
+
def close_path(self) -> "PathBuilder":
|
|
147
|
+
if self._current_point is None or self._subpath_start is None:
|
|
148
|
+
raise ValidationException("Call move_to() before close_path()")
|
|
149
|
+
if self._current_point != self._subpath_start:
|
|
150
|
+
self.line_to(self._subpath_start.x, self._subpath_start.y)
|
|
151
|
+
self._current_point = self._subpath_start
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
def add_segment(self, segment: PathSegment) -> "PathBuilder":
|
|
155
|
+
if segment is None:
|
|
156
|
+
raise ValidationException("Path segment cannot be null")
|
|
157
|
+
self._segments.append(segment)
|
|
158
|
+
return self
|
|
159
|
+
|
|
103
160
|
def solid(self) -> "PathBuilder":
|
|
104
161
|
"""
|
|
105
162
|
Set segments to solid (no dash pattern).
|
|
@@ -176,6 +233,7 @@ class PathBuilder:
|
|
|
176
233
|
Returns:
|
|
177
234
|
Self for method chaining
|
|
178
235
|
"""
|
|
236
|
+
self._validate_coordinates(x, y, width, height)
|
|
179
237
|
if width <= 0:
|
|
180
238
|
raise ValidationException("Rectangle width must be positive")
|
|
181
239
|
if height <= 0:
|
|
@@ -195,6 +253,69 @@ class PathBuilder:
|
|
|
195
253
|
|
|
196
254
|
return self
|
|
197
255
|
|
|
256
|
+
def rectangle(
|
|
257
|
+
self, x: float, y: float, width: float, height: float
|
|
258
|
+
) -> "PathBuilder":
|
|
259
|
+
return self.add_rectangle(x, y, width, height)
|
|
260
|
+
|
|
261
|
+
def circle(self, center_x: float, center_y: float, radius: float) -> "PathBuilder":
|
|
262
|
+
self._validate_coordinates(center_x, center_y, radius)
|
|
263
|
+
if radius <= 0:
|
|
264
|
+
raise ValidationException("Circle radius must be positive")
|
|
265
|
+
kappa = 0.5522847498 * radius
|
|
266
|
+
return (
|
|
267
|
+
self.move_to(center_x, center_y + radius)
|
|
268
|
+
.bezier_to(
|
|
269
|
+
center_x + kappa,
|
|
270
|
+
center_y + radius,
|
|
271
|
+
center_x + radius,
|
|
272
|
+
center_y + kappa,
|
|
273
|
+
center_x + radius,
|
|
274
|
+
center_y,
|
|
275
|
+
)
|
|
276
|
+
.bezier_to(
|
|
277
|
+
center_x + radius,
|
|
278
|
+
center_y - kappa,
|
|
279
|
+
center_x + kappa,
|
|
280
|
+
center_y - radius,
|
|
281
|
+
center_x,
|
|
282
|
+
center_y - radius,
|
|
283
|
+
)
|
|
284
|
+
.bezier_to(
|
|
285
|
+
center_x - kappa,
|
|
286
|
+
center_y - radius,
|
|
287
|
+
center_x - radius,
|
|
288
|
+
center_y - kappa,
|
|
289
|
+
center_x - radius,
|
|
290
|
+
center_y,
|
|
291
|
+
)
|
|
292
|
+
.bezier_to(
|
|
293
|
+
center_x - radius,
|
|
294
|
+
center_y + kappa,
|
|
295
|
+
center_x - kappa,
|
|
296
|
+
center_y + radius,
|
|
297
|
+
center_x,
|
|
298
|
+
center_y + radius,
|
|
299
|
+
)
|
|
300
|
+
.close_path()
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def _validate_coordinates(*values: float) -> None:
|
|
305
|
+
if any(not math.isfinite(value) for value in values):
|
|
306
|
+
raise ValidationException("Coordinates must be finite numbers")
|
|
307
|
+
|
|
308
|
+
@staticmethod
|
|
309
|
+
def _validate_dash(dash_array: List[float], dash_phase: float) -> None:
|
|
310
|
+
if dash_array is None:
|
|
311
|
+
raise ValidationException("Dash pattern cannot be null")
|
|
312
|
+
if any(not math.isfinite(value) or value < 0 for value in dash_array):
|
|
313
|
+
raise ValidationException("Dash values must be finite and nonnegative")
|
|
314
|
+
if dash_array and all(value == 0 for value in dash_array):
|
|
315
|
+
raise ValidationException("Dash pattern cannot be all zero")
|
|
316
|
+
if not math.isfinite(dash_phase) or dash_phase < 0:
|
|
317
|
+
raise ValidationException("Dash phase must be finite and nonnegative")
|
|
318
|
+
|
|
198
319
|
def even_odd_fill(self, enabled: bool = True) -> "PathBuilder":
|
|
199
320
|
"""
|
|
200
321
|
Set the fill rule to even-odd (vs nonzero winding).
|
|
@@ -772,7 +893,7 @@ class RectangleBuilder:
|
|
|
772
893
|
top_left = Point(self._x, self._y + self._height)
|
|
773
894
|
|
|
774
895
|
# Create four lines forming the rectangle
|
|
775
|
-
lines = [
|
|
896
|
+
lines: List[PathSegment] = [
|
|
776
897
|
Line(
|
|
777
898
|
p0=bottom_left,
|
|
778
899
|
p1=bottom_right,
|