pdfdancer-client-python 0.2.29__tar.gz → 0.3.1__tar.gz
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_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/.github/workflows/ci.yml +4 -3
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/.gitignore +1 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/CLAUDE.md +2 -2
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/PKG-INFO +4 -4
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/README.md +3 -3
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/pyproject.toml +1 -1
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/image_builder.py +3 -3
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/models.py +23 -23
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/page_builder.py +37 -11
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/paragraph_builder.py +12 -12
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/path_builder.py +17 -17
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/pdfdancer_v1.py +127 -93
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/text_line_builder.py +9 -9
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/types.py +21 -31
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer_client_python.egg-info/PKG-INFO +4 -4
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/pdf_assertions.py +42 -42
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_acroform.py +6 -6
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_bezier_builder.py +21 -21
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_context_manager.py +26 -26
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_form_x_objects.py +2 -2
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_image.py +10 -10
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_line.py +9 -9
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_line_builder.py +27 -27
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_new_pdf.py +5 -5
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_page.py +15 -16
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_paragraph.py +57 -56
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_path.py +6 -6
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_path_builder.py +48 -48
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_path_builder_rectangle.py +63 -63
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_path_comprehensive.py +18 -18
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_rectangle_builder.py +49 -49
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_singular_selection.py +38 -38
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_snapshot.py +37 -35
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_text_line_edit.py +16 -40
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_models.py +10 -10
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_openapi_compliance.py +4 -4
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_path_models.py +4 -4
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_pdf_object_equality.py +23 -23
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/.claude/commands/discuss.md +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/.flake8 +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/.github/workflows/daily-tests.yml +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/LICENSE +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/NOTICE +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/TODO.md +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/check.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/docs/openapi.yml +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/media/logo-orange-512h.webp +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/media/logo-orange-60h.webp +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/release.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/setup.cfg +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/__init__.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/exceptions.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/fingerprint.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer_client_python.egg-info/SOURCES.txt +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/test.sh +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/__init__.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/conftest.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/__init__.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_pdfdancer.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/e2e/test_positioning.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/DancingScript-Regular.ttf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/Empty.pdf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/Showcase.pdf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/basic-paths.pdf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/form-xobject-example.pdf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/logo-80.png +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/fixtures/mixed-form-types.pdf +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_anonymous_token.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_fingerprint.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_rate_limit.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/tests/test_standard_fonts.py +0 -0
- {pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/update-api-spec.sh +0 -0
|
@@ -2,9 +2,9 @@ name: CI
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: [
|
|
5
|
+
branches: [ '**' ]
|
|
6
6
|
pull_request:
|
|
7
|
-
branches: [
|
|
7
|
+
branches: [ '**' ]
|
|
8
8
|
workflow_dispatch:
|
|
9
9
|
|
|
10
10
|
jobs:
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
strategy:
|
|
16
16
|
fail-fast: false
|
|
17
|
-
max-parallel:
|
|
17
|
+
max-parallel: 2
|
|
18
18
|
matrix:
|
|
19
19
|
python-version: [ '3.12' ]
|
|
20
20
|
|
|
@@ -57,6 +57,7 @@ jobs:
|
|
|
57
57
|
runs-on: ${{ matrix.os }}
|
|
58
58
|
strategy:
|
|
59
59
|
fail-fast: false
|
|
60
|
+
max-parallel: 2
|
|
60
61
|
matrix:
|
|
61
62
|
os: [ ubuntu-latest, windows-latest ]
|
|
62
63
|
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
|
@@ -83,7 +83,7 @@ pdf.save("output.pdf")
|
|
|
83
83
|
- **Dual initialization**: `PDFDancer.open()` for existing PDFs, `PDFDancer.new()` for blank PDFs
|
|
84
84
|
- **Session-based operations**: All constructors create server session automatically
|
|
85
85
|
- **Object-oriented API**: Selected objects (paragraphs, images, etc.) have methods like `.delete()`, `.move()`
|
|
86
|
-
- **Page-level operations**: `pdf.page(
|
|
86
|
+
- **Page-level operations**: `pdf.page(number)` provides page-scoped selections and operations
|
|
87
87
|
- **Builder pattern**: `new_paragraph()` and `new_image()` for fluent construction
|
|
88
88
|
- **Strict validation**: All validation matches Java client exactly
|
|
89
89
|
- **Exception handling**: FontNotFoundException, ValidationException, HttpClientException, etc.
|
|
@@ -188,7 +188,7 @@ page.delete()
|
|
|
188
188
|
### API Design
|
|
189
189
|
|
|
190
190
|
- **Use object-oriented patterns**: Selected objects should have methods (`.delete()`, `.move()`, etc.)
|
|
191
|
-
- **Provide page-level operations**: `pdf.page(
|
|
191
|
+
- **Provide page-level operations**: `pdf.page(number)` for page-scoped selections
|
|
192
192
|
- **Support fluent builders**: `new_paragraph()` and `new_image()` return builder instances
|
|
193
193
|
- **Use snake_case for methods**: `select_paragraphs()`, `select_images_at()`, etc.
|
|
194
194
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdfdancer-client-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Python client for PDFDancer API
|
|
5
5
|
Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
|
|
6
6
|
License:
|
|
@@ -251,7 +251,7 @@ pixel-perfect control from Python. The same API is also available for TypeScript
|
|
|
251
251
|
|
|
252
252
|
## Highlights
|
|
253
253
|
|
|
254
|
-
- Locate paragraphs, text lines, images, vector paths, form fields, and pages by
|
|
254
|
+
- Locate paragraphs, text lines, images, vector paths, form fields, and pages by page number, coordinates, or text prefixes.
|
|
255
255
|
- Edit existing content in place with fluent editors and context managers that apply changes safely.
|
|
256
256
|
- Programmatically control third-party PDFs—modify invoices, contracts, and reports you did not author.
|
|
257
257
|
- Add content with precise XY positioning using paragraph and image builders, custom fonts, and color helpers.
|
|
@@ -300,7 +300,7 @@ with PDFDancer.open(
|
|
|
300
300
|
.font(StandardFonts.HELVETICA, 12) \
|
|
301
301
|
.color(Color(70, 70, 70)) \
|
|
302
302
|
.line_spacing(1.4) \
|
|
303
|
-
.at(
|
|
303
|
+
.at(page_number=0, x=72, y=520) \
|
|
304
304
|
.add()
|
|
305
305
|
|
|
306
306
|
# Persist the modified document
|
|
@@ -321,7 +321,7 @@ with PDFDancer.new(token="your-api-token") as pdf:
|
|
|
321
321
|
.font(StandardFonts.TIMES_BOLD, 18) \
|
|
322
322
|
.color(Color(10, 10, 80)) \
|
|
323
323
|
.line_spacing(1.2) \
|
|
324
|
-
.at(
|
|
324
|
+
.at(page_number=0, x=72, y=730) \
|
|
325
325
|
.add()
|
|
326
326
|
|
|
327
327
|
pdf.new_image() \
|
|
@@ -12,7 +12,7 @@ pixel-perfect control from Python. The same API is also available for TypeScript
|
|
|
12
12
|
|
|
13
13
|
## Highlights
|
|
14
14
|
|
|
15
|
-
- Locate paragraphs, text lines, images, vector paths, form fields, and pages by
|
|
15
|
+
- Locate paragraphs, text lines, images, vector paths, form fields, and pages by page number, coordinates, or text prefixes.
|
|
16
16
|
- Edit existing content in place with fluent editors and context managers that apply changes safely.
|
|
17
17
|
- Programmatically control third-party PDFs—modify invoices, contracts, and reports you did not author.
|
|
18
18
|
- Add content with precise XY positioning using paragraph and image builders, custom fonts, and color helpers.
|
|
@@ -61,7 +61,7 @@ with PDFDancer.open(
|
|
|
61
61
|
.font(StandardFonts.HELVETICA, 12) \
|
|
62
62
|
.color(Color(70, 70, 70)) \
|
|
63
63
|
.line_spacing(1.4) \
|
|
64
|
-
.at(
|
|
64
|
+
.at(page_number=0, x=72, y=520) \
|
|
65
65
|
.add()
|
|
66
66
|
|
|
67
67
|
# Persist the modified document
|
|
@@ -82,7 +82,7 @@ with PDFDancer.new(token="your-api-token") as pdf:
|
|
|
82
82
|
.font(StandardFonts.TIMES_BOLD, 18) \
|
|
83
83
|
.color(Color(10, 10, 80)) \
|
|
84
84
|
.line_spacing(1.2) \
|
|
85
|
-
.at(
|
|
85
|
+
.at(page_number=0, x=72, y=730) \
|
|
86
86
|
.add()
|
|
87
87
|
|
|
88
88
|
pdf.new_image() \
|
{pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/image_builder.py
RENAMED
|
@@ -39,7 +39,7 @@ class ImageBuilder:
|
|
|
39
39
|
|
|
40
40
|
class ImageOnPageBuilder:
|
|
41
41
|
|
|
42
|
-
def __init__(self, client: "PDFDancer",
|
|
42
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
43
43
|
"""
|
|
44
44
|
Initialize the image builder with a client reference.
|
|
45
45
|
|
|
@@ -51,14 +51,14 @@ class ImageOnPageBuilder:
|
|
|
51
51
|
|
|
52
52
|
self._client = client
|
|
53
53
|
self._image = Image()
|
|
54
|
-
self.
|
|
54
|
+
self._page_number = page_number
|
|
55
55
|
|
|
56
56
|
def from_file(self, img_path: Path) -> "ImageOnPageBuilder":
|
|
57
57
|
self._image.data = img_path.read_bytes()
|
|
58
58
|
return self
|
|
59
59
|
|
|
60
60
|
def at(self, x, y) -> "ImageOnPageBuilder":
|
|
61
|
-
self._image.position = Position.at_page_coordinates(self.
|
|
61
|
+
self._image.position = Position.at_page_coordinates(self._page_number, x, y)
|
|
62
62
|
return self
|
|
63
63
|
|
|
64
64
|
def add(self) -> bool:
|
|
@@ -262,7 +262,7 @@ class Position:
|
|
|
262
262
|
Spatial locator used to find or place objects on a page.
|
|
263
263
|
|
|
264
264
|
Parameters:
|
|
265
|
-
-
|
|
265
|
+
- page_number: One-based page number this position refers to. Required for most operations
|
|
266
266
|
that place or search on a specific page; use `Position.at_page()` as a shortcut.
|
|
267
267
|
- shape: Optional geometric shape used when matching by area (`POINT`, `LINE`, `CIRCLE`, `RECT`).
|
|
268
268
|
- mode: How to match objects relative to the shape (`INTERSECT` or `CONTAINS`).
|
|
@@ -272,8 +272,8 @@ class Position:
|
|
|
272
272
|
- name: Named anchor or element name to target (e.g. form field name).
|
|
273
273
|
|
|
274
274
|
Builder helpers:
|
|
275
|
-
- `Position.at_page(
|
|
276
|
-
- `Position.at_page_coordinates(
|
|
275
|
+
- `Position.at_page(page_number)` – target a whole page.
|
|
276
|
+
- `Position.at_page_coordinates(page_number, x, y)` – target a point on a page.
|
|
277
277
|
- `Position.by_name(name)` – target object(s) by name.
|
|
278
278
|
- `pos.at_coordinates(Point(x, y))` – switch to a point on the current page.
|
|
279
279
|
- `pos.move_x(dx)`, `pos.move_y(dy)` – offset the current coordinates.
|
|
@@ -294,7 +294,7 @@ class Position:
|
|
|
294
294
|
```
|
|
295
295
|
"""
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
page_number: Optional[int] = None
|
|
298
298
|
shape: Optional[ShapeType] = None
|
|
299
299
|
mode: Optional[PositionMode] = None
|
|
300
300
|
bounding_rect: Optional[BoundingRect] = None
|
|
@@ -303,18 +303,18 @@ class Position:
|
|
|
303
303
|
name: Optional[str] = None
|
|
304
304
|
|
|
305
305
|
@staticmethod
|
|
306
|
-
def at_page(
|
|
306
|
+
def at_page(page_number: int) -> "Position":
|
|
307
307
|
"""
|
|
308
308
|
Creates a position specification for an entire page.
|
|
309
309
|
"""
|
|
310
|
-
return Position(
|
|
310
|
+
return Position(page_number=page_number, mode=PositionMode.CONTAINS)
|
|
311
311
|
|
|
312
312
|
@staticmethod
|
|
313
|
-
def at_page_coordinates(
|
|
313
|
+
def at_page_coordinates(page_number: int, x: float, y: float) -> "Position":
|
|
314
314
|
"""
|
|
315
315
|
Creates a position specification for specific coordinates on a page.
|
|
316
316
|
"""
|
|
317
|
-
position = Position.at_page(
|
|
317
|
+
position = Position.at_page(page_number)
|
|
318
318
|
position.at_coordinates(Point(x, y))
|
|
319
319
|
return position
|
|
320
320
|
|
|
@@ -823,7 +823,7 @@ class FindRequest:
|
|
|
823
823
|
def _position_to_dict(position: Position) -> dict:
|
|
824
824
|
"""Convert Position to dictionary for JSON serialization."""
|
|
825
825
|
result = {
|
|
826
|
-
"
|
|
826
|
+
"pageNumber": position.page_number,
|
|
827
827
|
"textStartsWith": position.text_starts_with,
|
|
828
828
|
"textPattern": position.text_pattern,
|
|
829
829
|
}
|
|
@@ -898,24 +898,24 @@ class PageMoveRequest:
|
|
|
898
898
|
"""Request to reorder pages.
|
|
899
899
|
|
|
900
900
|
Parameters:
|
|
901
|
-
-
|
|
902
|
-
-
|
|
901
|
+
- from_page: 1-based page number of the page to move.
|
|
902
|
+
- to_page: 1-based destination page number.
|
|
903
903
|
|
|
904
904
|
Example:
|
|
905
905
|
```python
|
|
906
906
|
# Move first page to the end
|
|
907
|
-
req = PageMoveRequest(
|
|
907
|
+
req = PageMoveRequest(from_page=1, to_page=doc_page_count)
|
|
908
908
|
payload = req.to_dict()
|
|
909
909
|
```
|
|
910
910
|
"""
|
|
911
911
|
|
|
912
|
-
|
|
913
|
-
|
|
912
|
+
from_page: int
|
|
913
|
+
to_page: int
|
|
914
914
|
|
|
915
915
|
def to_dict(self) -> dict:
|
|
916
916
|
return {
|
|
917
|
-
"
|
|
918
|
-
"
|
|
917
|
+
"fromPage": self.from_page,
|
|
918
|
+
"toPage": self.to_page,
|
|
919
919
|
}
|
|
920
920
|
|
|
921
921
|
|
|
@@ -924,7 +924,7 @@ class AddPageRequest:
|
|
|
924
924
|
"""Request to add a new page to the document.
|
|
925
925
|
|
|
926
926
|
Parameters:
|
|
927
|
-
-
|
|
927
|
+
- page_number: Optional 1-based page number where the new page should be inserted.
|
|
928
928
|
- orientation: Optional page orientation (portrait or landscape).
|
|
929
929
|
- page_size: Optional size of the page.
|
|
930
930
|
|
|
@@ -932,14 +932,14 @@ class AddPageRequest:
|
|
|
932
932
|
with default server behavior.
|
|
933
933
|
"""
|
|
934
934
|
|
|
935
|
-
|
|
935
|
+
page_number: Optional[int] = None
|
|
936
936
|
orientation: Optional[Orientation] = None
|
|
937
937
|
page_size: Optional[PageSize] = None
|
|
938
938
|
|
|
939
939
|
def to_dict(self) -> dict:
|
|
940
940
|
payload: Dict[str, Any] = {}
|
|
941
|
-
if self.
|
|
942
|
-
payload["
|
|
941
|
+
if self.page_number is not None:
|
|
942
|
+
payload["pageNumber"] = int(self.page_number)
|
|
943
943
|
if self.orientation is not None:
|
|
944
944
|
orientation_value: Orientation
|
|
945
945
|
if isinstance(self.orientation, Orientation):
|
|
@@ -1449,14 +1449,14 @@ class PageRef(ObjectRef):
|
|
|
1449
1449
|
|
|
1450
1450
|
Parameters (usually provided by the server):
|
|
1451
1451
|
- internal_id: Identifier of the page object.
|
|
1452
|
-
- position: Position referencing the page (often via `Position.at_page(
|
|
1452
|
+
- position: Position referencing the page (often via `Position.at_page(page_number)`).
|
|
1453
1453
|
- type: Should be `ObjectType.PAGE`.
|
|
1454
1454
|
- page_size: `PageSize` of the page.
|
|
1455
1455
|
- orientation: `Orientation.PORTRAIT` or `Orientation.LANDSCAPE`.
|
|
1456
1456
|
|
|
1457
1457
|
Usage:
|
|
1458
1458
|
- Returned inside `PageSnapshot` objects. You can inspect page size/orientation
|
|
1459
|
-
and use the page
|
|
1459
|
+
and use the page number for subsequent operations.
|
|
1460
1460
|
"""
|
|
1461
1461
|
|
|
1462
1462
|
page_size: Optional[PageSize]
|
|
@@ -1531,7 +1531,7 @@ class PageSnapshot:
|
|
|
1531
1531
|
|
|
1532
1532
|
Usage:
|
|
1533
1533
|
- Iterate over `elements` to find items to modify or move.
|
|
1534
|
-
- Use `page_ref.position.
|
|
1534
|
+
- Use `page_ref.position.page_number` as the page number for follow-up operations.
|
|
1535
1535
|
"""
|
|
1536
1536
|
|
|
1537
1537
|
page_ref: PageRef
|
{pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/page_builder.py
RENAMED
|
@@ -11,10 +11,10 @@ if TYPE_CHECKING:
|
|
|
11
11
|
|
|
12
12
|
class PageBuilder:
|
|
13
13
|
"""
|
|
14
|
-
Fluent builder for adding pages with optional orientation, size, and
|
|
14
|
+
Fluent builder for adding pages with optional orientation, size, and page number.
|
|
15
15
|
|
|
16
16
|
Usage:
|
|
17
|
-
pdf.new_page().
|
|
17
|
+
pdf.new_page().at_page(1).landscape().a4().add()
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
def __init__(self, client: "PDFDancer") -> None:
|
|
@@ -22,18 +22,44 @@ class PageBuilder:
|
|
|
22
22
|
raise ValidationException("Client cannot be null")
|
|
23
23
|
|
|
24
24
|
self._client = client
|
|
25
|
-
self.
|
|
25
|
+
self._page_number: Optional[int] = None
|
|
26
26
|
self._orientation: Optional[Orientation] = None
|
|
27
27
|
self._page_size: Optional[PageSize] = None
|
|
28
28
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
def at_page(self, page_number: int) -> "PageBuilder":
|
|
30
|
+
"""
|
|
31
|
+
Sets the page number where the new page should be inserted (1-based).
|
|
32
|
+
Page 1 is the first page.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
page_number: The 1-based page number (must be >= 1)
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
This builder
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValidationException: If page_number is None or less than 1
|
|
42
|
+
"""
|
|
43
|
+
if page_number is None:
|
|
44
|
+
raise ValidationException("Page number cannot be null")
|
|
45
|
+
if page_number < 1:
|
|
46
|
+
raise ValidationException("Page number must be >= 1 (1-based indexing)")
|
|
47
|
+
self._page_number = int(page_number)
|
|
35
48
|
return self
|
|
36
49
|
|
|
50
|
+
def at_index(self, page_number: int) -> "PageBuilder":
|
|
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
|
+
|
|
37
63
|
def orientation(self, orientation: Orientation) -> "PageBuilder":
|
|
38
64
|
if orientation is None:
|
|
39
65
|
raise ValidationException("Orientation cannot be null")
|
|
@@ -87,13 +113,13 @@ class PageBuilder:
|
|
|
87
113
|
|
|
88
114
|
def _build_request(self) -> Optional[AddPageRequest]:
|
|
89
115
|
if (
|
|
90
|
-
self.
|
|
116
|
+
self._page_number is None
|
|
91
117
|
and self._orientation is None
|
|
92
118
|
and self._page_size is None
|
|
93
119
|
):
|
|
94
120
|
return None
|
|
95
121
|
return AddPageRequest(
|
|
96
|
-
|
|
122
|
+
page_number=self._page_number,
|
|
97
123
|
orientation=self._orientation,
|
|
98
124
|
page_size=self._page_size,
|
|
99
125
|
)
|
{pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/paragraph_builder.py
RENAMED
|
@@ -169,14 +169,14 @@ class ParagraphBuilder:
|
|
|
169
169
|
"Cannot move paragraph without an existing position"
|
|
170
170
|
)
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
if
|
|
172
|
+
page_number = position.page_number
|
|
173
|
+
if page_number is None:
|
|
174
174
|
raise ValidationException(
|
|
175
|
-
"Paragraph position must include a page
|
|
175
|
+
"Paragraph position must include a page number to move"
|
|
176
176
|
)
|
|
177
177
|
|
|
178
178
|
self._position_changed = True
|
|
179
|
-
return self.at(
|
|
179
|
+
return self.at(page_number, x, y)
|
|
180
180
|
|
|
181
181
|
def at_position(self, position: Position) -> "ParagraphBuilder":
|
|
182
182
|
if position is None:
|
|
@@ -186,8 +186,8 @@ class ParagraphBuilder:
|
|
|
186
186
|
self._position_changed = True
|
|
187
187
|
return self
|
|
188
188
|
|
|
189
|
-
def at(self,
|
|
190
|
-
return self.at_position(Position.at_page_coordinates(
|
|
189
|
+
def at(self, page_number: int, x: float, y: float) -> "ParagraphBuilder":
|
|
190
|
+
return self.at_position(Position.at_page_coordinates(page_number, x, y))
|
|
191
191
|
|
|
192
192
|
def add_text_line(
|
|
193
193
|
self, text_line: Union[TextLine, TextObjectRef, str]
|
|
@@ -470,14 +470,14 @@ class ParagraphBuilder:
|
|
|
470
470
|
if paragraph_position is None:
|
|
471
471
|
return None
|
|
472
472
|
|
|
473
|
-
|
|
473
|
+
page_number = paragraph_position.page_number
|
|
474
474
|
base_x = paragraph_position.x()
|
|
475
475
|
base_y = paragraph_position.y()
|
|
476
|
-
if
|
|
476
|
+
if page_number is None or base_x is None or base_y is None:
|
|
477
477
|
return None
|
|
478
478
|
|
|
479
479
|
offset = line_index * self._calculate_baseline_distance(spacing_factor)
|
|
480
|
-
return Position.at_page_coordinates(
|
|
480
|
+
return Position.at_page_coordinates(page_number, base_x, base_y + offset)
|
|
481
481
|
|
|
482
482
|
def _calculate_baseline_distance(self, spacing_factor: float) -> float:
|
|
483
483
|
factor = spacing_factor if spacing_factor > 0 else DEFAULT_LINE_SPACING_FACTOR
|
|
@@ -545,10 +545,10 @@ class ParagraphBuilder:
|
|
|
545
545
|
|
|
546
546
|
class ParagraphPageBuilder(ParagraphBuilder):
|
|
547
547
|
|
|
548
|
-
def __init__(self, client: "PDFDancer",
|
|
548
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
549
549
|
super().__init__(client)
|
|
550
|
-
self.
|
|
550
|
+
self._page_number: Optional[int] = page_number
|
|
551
551
|
|
|
552
552
|
# noinspection PyMethodOverriding
|
|
553
553
|
def at(self, x: float, y: float) -> "ParagraphBuilder":
|
|
554
|
-
return super().at(self.
|
|
554
|
+
return super().at(self._page_number, x, y)
|
{pdfdancer_client_python-0.2.29 → pdfdancer_client_python-0.3.1}/src/pdfdancer/path_builder.py
RENAMED
|
@@ -21,19 +21,19 @@ class PathBuilder:
|
|
|
21
21
|
All coordinates are absolute page coordinates.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
def __init__(self, client: "PDFDancer",
|
|
24
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
25
25
|
"""
|
|
26
|
-
Initialize the path builder with a client reference and page
|
|
26
|
+
Initialize the path builder with a client reference and page number.
|
|
27
27
|
|
|
28
28
|
Args:
|
|
29
29
|
client: The PDFDancer instance for adding the path
|
|
30
|
-
|
|
30
|
+
page_number: The page number (1-indexed)
|
|
31
31
|
"""
|
|
32
32
|
if client is None:
|
|
33
33
|
raise ValidationException("Client cannot be null")
|
|
34
34
|
|
|
35
35
|
self._client = client
|
|
36
|
-
self.
|
|
36
|
+
self._page_number = page_number
|
|
37
37
|
self._segments: List[PathSegment] = []
|
|
38
38
|
self._even_odd_fill: bool = False
|
|
39
39
|
self._current_stroke_color: Optional[Color] = Color(0, 0, 0) # Black default
|
|
@@ -222,7 +222,7 @@ class PathBuilder:
|
|
|
222
222
|
raise ValidationException("Path must have at least one segment")
|
|
223
223
|
|
|
224
224
|
# Create position with only page index set
|
|
225
|
-
position = Position.at_page_coordinates(self.
|
|
225
|
+
position = Position.at_page_coordinates(self._page_number, 0, 0)
|
|
226
226
|
|
|
227
227
|
# Build the Path object
|
|
228
228
|
path = Path(
|
|
@@ -242,19 +242,19 @@ class LineBuilder:
|
|
|
242
242
|
Mirrors the Java client LineBuilder API.
|
|
243
243
|
"""
|
|
244
244
|
|
|
245
|
-
def __init__(self, client: "PDFDancer",
|
|
245
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
246
246
|
"""
|
|
247
247
|
Initialize the line builder.
|
|
248
248
|
|
|
249
249
|
Args:
|
|
250
250
|
client: The PDFDancer instance for adding the line
|
|
251
|
-
|
|
251
|
+
page_number: The page number (1-indexed)
|
|
252
252
|
"""
|
|
253
253
|
if client is None:
|
|
254
254
|
raise ValidationException("Client cannot be null")
|
|
255
255
|
|
|
256
256
|
self._client = client
|
|
257
|
-
self.
|
|
257
|
+
self._page_number = page_number
|
|
258
258
|
self._p0: Optional[Point] = None
|
|
259
259
|
self._p1: Optional[Point] = None
|
|
260
260
|
self._stroke_color: Optional[Color] = Color(0, 0, 0) # Black default
|
|
@@ -387,7 +387,7 @@ class LineBuilder:
|
|
|
387
387
|
)
|
|
388
388
|
|
|
389
389
|
# Create position with only page index set
|
|
390
|
-
position = Position.at_page_coordinates(self.
|
|
390
|
+
position = Position.at_page_coordinates(self._page_number, 0, 0)
|
|
391
391
|
|
|
392
392
|
# Wrap in Path with single segment
|
|
393
393
|
path = Path(position=position, path_segments=[line], even_odd_fill=False)
|
|
@@ -403,19 +403,19 @@ class BezierBuilder:
|
|
|
403
403
|
Mirrors the Java client BezierBuilder API.
|
|
404
404
|
"""
|
|
405
405
|
|
|
406
|
-
def __init__(self, client: "PDFDancer",
|
|
406
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
407
407
|
"""
|
|
408
408
|
Initialize the bezier builder.
|
|
409
409
|
|
|
410
410
|
Args:
|
|
411
411
|
client: The PDFDancer instance for adding the bezier
|
|
412
|
-
|
|
412
|
+
page_number: The page number (1-indexed)
|
|
413
413
|
"""
|
|
414
414
|
if client is None:
|
|
415
415
|
raise ValidationException("Client cannot be null")
|
|
416
416
|
|
|
417
417
|
self._client = client
|
|
418
|
-
self.
|
|
418
|
+
self._page_number = page_number
|
|
419
419
|
self._p0: Optional[Point] = None
|
|
420
420
|
self._p1: Optional[Point] = None
|
|
421
421
|
self._p2: Optional[Point] = None
|
|
@@ -590,7 +590,7 @@ class BezierBuilder:
|
|
|
590
590
|
)
|
|
591
591
|
|
|
592
592
|
# Create position with only page index set
|
|
593
|
-
position = Position.at_page_coordinates(self.
|
|
593
|
+
position = Position.at_page_coordinates(self._page_number, 0, 0)
|
|
594
594
|
|
|
595
595
|
# Wrap in Path with single segment
|
|
596
596
|
path = Path(position=position, path_segments=[bezier], even_odd_fill=False)
|
|
@@ -606,19 +606,19 @@ class RectangleBuilder:
|
|
|
606
606
|
Provides a convenient way to create a rectangle path with a single builder.
|
|
607
607
|
"""
|
|
608
608
|
|
|
609
|
-
def __init__(self, client: "PDFDancer",
|
|
609
|
+
def __init__(self, client: "PDFDancer", page_number: int):
|
|
610
610
|
"""
|
|
611
611
|
Initialize the rectangle builder.
|
|
612
612
|
|
|
613
613
|
Args:
|
|
614
614
|
client: The PDFDancer instance for adding the rectangle
|
|
615
|
-
|
|
615
|
+
page_number: The page number (1-indexed)
|
|
616
616
|
"""
|
|
617
617
|
if client is None:
|
|
618
618
|
raise ValidationException("Client cannot be null")
|
|
619
619
|
|
|
620
620
|
self._client = client
|
|
621
|
-
self.
|
|
621
|
+
self._page_number = page_number
|
|
622
622
|
self._x: Optional[float] = None
|
|
623
623
|
self._y: Optional[float] = None
|
|
624
624
|
self._width: Optional[float] = None
|
|
@@ -812,7 +812,7 @@ class RectangleBuilder:
|
|
|
812
812
|
]
|
|
813
813
|
|
|
814
814
|
# Create position with only page index set
|
|
815
|
-
position = Position.at_page_coordinates(self.
|
|
815
|
+
position = Position.at_page_coordinates(self._page_number, 0, 0)
|
|
816
816
|
|
|
817
817
|
# Wrap in Path with four line segments
|
|
818
818
|
path = Path(
|