PyPDFForm 3.5.1__py3-none-any.whl → 4.2.0__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.
- PyPDFForm/__init__.py +5 -3
- PyPDFForm/adapter.py +33 -1
- PyPDFForm/ap.py +99 -0
- PyPDFForm/assets/__init__.py +0 -0
- PyPDFForm/assets/blank.py +100 -0
- PyPDFForm/constants.py +20 -2
- PyPDFForm/coordinate.py +7 -11
- PyPDFForm/deprecation.py +30 -0
- PyPDFForm/filler.py +17 -36
- PyPDFForm/font.py +16 -16
- PyPDFForm/hooks.py +169 -31
- PyPDFForm/image.py +0 -3
- PyPDFForm/middleware/__init__.py +35 -0
- PyPDFForm/middleware/base.py +24 -5
- PyPDFForm/middleware/checkbox.py +18 -1
- PyPDFForm/middleware/signature.py +0 -1
- PyPDFForm/patterns.py +71 -13
- PyPDFForm/raw/__init__.py +37 -0
- PyPDFForm/raw/circle.py +65 -0
- PyPDFForm/raw/ellipse.py +69 -0
- PyPDFForm/raw/image.py +79 -0
- PyPDFForm/raw/line.py +65 -0
- PyPDFForm/raw/rect.py +70 -0
- PyPDFForm/raw/text.py +73 -0
- PyPDFForm/template.py +114 -10
- PyPDFForm/types.py +49 -0
- PyPDFForm/utils.py +31 -41
- PyPDFForm/watermark.py +153 -44
- PyPDFForm/widgets/__init__.py +1 -0
- PyPDFForm/widgets/base.py +79 -59
- PyPDFForm/widgets/checkbox.py +30 -30
- PyPDFForm/widgets/dropdown.py +42 -40
- PyPDFForm/widgets/image.py +17 -16
- PyPDFForm/widgets/radio.py +27 -28
- PyPDFForm/widgets/signature.py +96 -60
- PyPDFForm/widgets/text.py +40 -40
- PyPDFForm/wrapper.py +256 -240
- {pypdfform-3.5.1.dist-info → pypdfform-4.2.0.dist-info}/METADATA +33 -26
- pypdfform-4.2.0.dist-info/RECORD +47 -0
- {pypdfform-3.5.1.dist-info → pypdfform-4.2.0.dist-info}/licenses/LICENSE +1 -1
- pypdfform-3.5.1.dist-info/RECORD +0 -35
- /PyPDFForm/{widgets → assets}/bedrock.py +0 -0
- {pypdfform-3.5.1.dist-info → pypdfform-4.2.0.dist-info}/WHEEL +0 -0
- {pypdfform-3.5.1.dist-info → pypdfform-4.2.0.dist-info}/top_level.txt +0 -0
PyPDFForm/watermark.py
CHANGED
|
@@ -7,14 +7,8 @@ It supports drawing text, lines, and images as watermarks.
|
|
|
7
7
|
The module also includes functions to merge these watermarks with the original PDF content
|
|
8
8
|
and to copy specific widgets from the watermarks to the original PDF.
|
|
9
9
|
"""
|
|
10
|
-
# TODO: In `draw_image`, `ImageReader(image_buff)` is created for each image. If the same image is drawn multiple times, consider caching `ImageReader` objects or passing pre-processed image data to avoid redundant processing.
|
|
11
|
-
# TODO: In `create_watermarks_and_draw`, `PdfReader(stream_to_io(pdf))` is called, which re-parses the PDF. If this function is called repeatedly for the same PDF, consider passing the `PdfReader` object directly to avoid redundant parsing.
|
|
12
|
-
# TODO: In `create_watermarks_and_draw`, the function returns a list of watermarks where only one element is populated. This can be inefficient for memory if there are many pages but only one watermark is created. Consider returning only the created watermark and its page number, and let the caller handle placement.
|
|
13
|
-
# TODO: In `merge_watermarks_with_pdf`, `PdfReader(stream_to_io(pdf))` and `PdfReader(stream_to_io(watermarks[i]))` are called in a loop. This leads to repeated parsing of the base PDF and each watermark. It would be more efficient to parse the base PDF once and then merge watermark pages directly into the existing `PdfWriter` object.
|
|
14
|
-
# TODO: In `copy_watermark_widgets`, the function reads the PDF and watermarks multiple times. Similar to `merge_watermarks_with_pdf`, optimize by parsing the base PDF and watermarks once and then manipulating the `PdfWriter` object.
|
|
15
|
-
# TODO: The `copy_watermark_widgets` function has a `TODO: refactor duplicate logic with merge_two_pdfs` comment. This indicates a potential for code duplication and inefficiency. Refactoring this to a shared helper function would improve maintainability and potentially performance.
|
|
16
|
-
# TODO: In `copy_watermark_widgets`, the nested loops iterating through `watermarks`, `watermark_file.pages`, and `page.get(Annots, [])` can be very inefficient for large numbers of watermarks, pages, or annotations. Consider creating a lookup structure for annotations by key to avoid repeated linear scans.
|
|
17
10
|
|
|
11
|
+
from collections import defaultdict
|
|
18
12
|
from io import BytesIO
|
|
19
13
|
from typing import List, Union
|
|
20
14
|
|
|
@@ -84,6 +78,112 @@ def draw_line(canvas: Canvas, **kwargs) -> None:
|
|
|
84
78
|
canvas.line(src_x, src_y, dest_x, dest_y)
|
|
85
79
|
|
|
86
80
|
|
|
81
|
+
def draw_rect(canvas: Canvas, **kwargs) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Draws a rectangle on the given canvas with the specified coordinates, dimensions, and color.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
canvas (Canvas): The ReportLab Canvas object to draw on.
|
|
87
|
+
**kwargs: Keyword arguments containing the rectangle's properties and coordinates.
|
|
88
|
+
- x (float): The x-coordinate of the rectangle's bottom-left corner.
|
|
89
|
+
- y (float): The y-coordinate of the rectangle's bottom-left corner.
|
|
90
|
+
- width (float): The width of the rectangle.
|
|
91
|
+
- height (float): The height of the rectangle.
|
|
92
|
+
- color (tuple): A tuple representing the RGB color of the rectangle's outline.
|
|
93
|
+
- fill_color (tuple): A tuple representing the RGB color of the rectangle's fill.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
None
|
|
97
|
+
"""
|
|
98
|
+
x = kwargs["x"]
|
|
99
|
+
y = kwargs["y"]
|
|
100
|
+
width = kwargs["width"]
|
|
101
|
+
height = kwargs["height"]
|
|
102
|
+
color = kwargs["color"]
|
|
103
|
+
fill_color = kwargs["fill_color"]
|
|
104
|
+
|
|
105
|
+
canvas.setStrokeColorRGB(*(color))
|
|
106
|
+
|
|
107
|
+
fill = 0
|
|
108
|
+
canvas.saveState()
|
|
109
|
+
if fill_color:
|
|
110
|
+
canvas.setFillColorRGB(*(fill_color))
|
|
111
|
+
fill = 1
|
|
112
|
+
|
|
113
|
+
canvas.rect(x, y, width, height, fill=fill)
|
|
114
|
+
canvas.restoreState()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def draw_circle(canvas: Canvas, **kwargs) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Draws a circle on the given canvas with the specified center coordinates, radius, and color.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
canvas (Canvas): The ReportLab Canvas object to draw on.
|
|
123
|
+
**kwargs: Keyword arguments containing the circle's properties and coordinates.
|
|
124
|
+
- center_x (float): The x-coordinate of the circle's center.
|
|
125
|
+
- center_y (float): The y-coordinate of the circle's center.
|
|
126
|
+
- radius (float): The radius of the circle.
|
|
127
|
+
- color (tuple): A tuple representing the RGB color of the circle's outline.
|
|
128
|
+
- fill_color (tuple): A tuple representing the RGB color of the circle's fill.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
None
|
|
132
|
+
"""
|
|
133
|
+
center_x = kwargs["center_x"]
|
|
134
|
+
center_y = kwargs["center_y"]
|
|
135
|
+
radius = kwargs["radius"]
|
|
136
|
+
color = kwargs["color"]
|
|
137
|
+
fill_color = kwargs["fill_color"]
|
|
138
|
+
|
|
139
|
+
canvas.setStrokeColorRGB(*(color))
|
|
140
|
+
|
|
141
|
+
fill = 0
|
|
142
|
+
canvas.saveState()
|
|
143
|
+
if fill_color:
|
|
144
|
+
canvas.setFillColorRGB(*(fill_color))
|
|
145
|
+
fill = 1
|
|
146
|
+
|
|
147
|
+
canvas.circle(center_x, center_y, radius, fill=fill)
|
|
148
|
+
canvas.restoreState()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def draw_ellipse(canvas: Canvas, **kwargs) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Draws an ellipse on the given canvas defined by its bounding box coordinates and color.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
canvas (Canvas): The ReportLab Canvas object to draw on.
|
|
157
|
+
**kwargs: Keyword arguments containing the ellipse's properties and coordinates.
|
|
158
|
+
- x1 (float): The x-coordinate of the first corner of the bounding box.
|
|
159
|
+
- y1 (float): The y-coordinate of the first corner of the bounding box.
|
|
160
|
+
- x2 (float): The x-coordinate of the second corner of the bounding box.
|
|
161
|
+
- y2 (float): The y-coordinate of the second corner of the bounding box.
|
|
162
|
+
- color (tuple): A tuple representing the RGB color of the ellipse's outline.
|
|
163
|
+
- fill_color (tuple): A tuple representing the RGB color of the ellipse's fill.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
None
|
|
167
|
+
"""
|
|
168
|
+
x1 = kwargs["x1"]
|
|
169
|
+
y1 = kwargs["y1"]
|
|
170
|
+
x2 = kwargs["x2"]
|
|
171
|
+
y2 = kwargs["y2"]
|
|
172
|
+
color = kwargs["color"]
|
|
173
|
+
fill_color = kwargs["fill_color"]
|
|
174
|
+
|
|
175
|
+
canvas.setStrokeColorRGB(*(color))
|
|
176
|
+
|
|
177
|
+
fill = 0
|
|
178
|
+
canvas.saveState()
|
|
179
|
+
if fill_color:
|
|
180
|
+
canvas.setFillColorRGB(*(fill_color))
|
|
181
|
+
fill = 1
|
|
182
|
+
|
|
183
|
+
canvas.ellipse(x1, y1, x2, y2, fill=fill)
|
|
184
|
+
canvas.restoreState()
|
|
185
|
+
|
|
186
|
+
|
|
87
187
|
def draw_image(canvas: Canvas, **kwargs) -> None:
|
|
88
188
|
"""
|
|
89
189
|
Draws an image on the given canvas, scaling it to fit within the specified width and height.
|
|
@@ -122,58 +222,67 @@ def draw_image(canvas: Canvas, **kwargs) -> None:
|
|
|
122
222
|
image_buff.close()
|
|
123
223
|
|
|
124
224
|
|
|
125
|
-
def create_watermarks_and_draw(
|
|
126
|
-
pdf: bytes,
|
|
127
|
-
page_number: int,
|
|
128
|
-
action_type: str,
|
|
129
|
-
actions: List[dict],
|
|
130
|
-
) -> List[bytes]:
|
|
225
|
+
def create_watermarks_and_draw(pdf: bytes, to_draw: List[dict]) -> List[bytes]:
|
|
131
226
|
"""
|
|
132
|
-
Creates
|
|
227
|
+
Creates a watermark PDF for each page of the input PDF based on the drawing instructions.
|
|
133
228
|
|
|
134
|
-
This function
|
|
135
|
-
|
|
229
|
+
This function reads the input PDF to determine page sizes, then uses ReportLab
|
|
230
|
+
to create a separate, single-page PDF (a watermark) for each page that has
|
|
231
|
+
drawing instructions.
|
|
136
232
|
|
|
137
233
|
Args:
|
|
138
|
-
pdf (bytes): The PDF file as a byte stream.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
234
|
+
pdf (bytes): The original PDF file as a byte stream.
|
|
235
|
+
to_draw (List[dict]): A list of drawing instructions, where each dictionary
|
|
236
|
+
must contain a "page_number" key (1-based) and a "type" key ("image", "text", or "line")
|
|
237
|
+
along with type-specific parameters.
|
|
142
238
|
|
|
143
239
|
Returns:
|
|
144
|
-
List[bytes]: A list of byte streams
|
|
145
|
-
|
|
240
|
+
List[bytes]: A list of watermark PDF byte streams. An empty byte string (b"")
|
|
241
|
+
is used for pages without any drawing instructions.
|
|
146
242
|
"""
|
|
147
|
-
|
|
148
|
-
buff = BytesIO()
|
|
149
|
-
|
|
150
|
-
canvas = Canvas(
|
|
151
|
-
buff,
|
|
152
|
-
pagesize=(
|
|
153
|
-
float(pdf_file.pages[page_number - 1].mediabox[2]),
|
|
154
|
-
float(pdf_file.pages[page_number - 1].mediabox[3]),
|
|
155
|
-
),
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
action_type_to_func = {
|
|
243
|
+
type_to_func = {
|
|
159
244
|
"image": draw_image,
|
|
160
245
|
"text": draw_text,
|
|
161
246
|
"line": draw_line,
|
|
247
|
+
"rect": draw_rect,
|
|
248
|
+
"circle": draw_circle,
|
|
249
|
+
"ellipse": draw_ellipse,
|
|
162
250
|
}
|
|
163
251
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
252
|
+
result = []
|
|
253
|
+
|
|
254
|
+
page_to_to_draw = defaultdict(list)
|
|
255
|
+
for each in to_draw:
|
|
256
|
+
page_to_to_draw[each["page_number"]].append(each)
|
|
257
|
+
|
|
258
|
+
pdf_file = PdfReader(stream_to_io(pdf))
|
|
259
|
+
buff = BytesIO()
|
|
260
|
+
|
|
261
|
+
for i, page in enumerate(pdf_file.pages):
|
|
262
|
+
elements = page_to_to_draw[i + 1]
|
|
263
|
+
if not elements:
|
|
264
|
+
result.append(b"")
|
|
265
|
+
continue
|
|
266
|
+
|
|
267
|
+
buff.seek(0)
|
|
268
|
+
buff.flush()
|
|
269
|
+
|
|
270
|
+
canvas = Canvas(
|
|
271
|
+
buff,
|
|
272
|
+
pagesize=(
|
|
273
|
+
float(page.mediabox[2]),
|
|
274
|
+
float(page.mediabox[3]),
|
|
275
|
+
),
|
|
276
|
+
)
|
|
167
277
|
|
|
168
|
-
|
|
169
|
-
|
|
278
|
+
for element in elements:
|
|
279
|
+
type_to_func[element["type"]](canvas, **element)
|
|
170
280
|
|
|
171
|
-
|
|
172
|
-
|
|
281
|
+
canvas.save()
|
|
282
|
+
buff.seek(0)
|
|
283
|
+
result.append(buff.read())
|
|
173
284
|
|
|
174
|
-
return
|
|
175
|
-
watermark if i == page_number - 1 else b"" for i in range(len(pdf_file.pages))
|
|
176
|
-
]
|
|
285
|
+
return result
|
|
177
286
|
|
|
178
287
|
|
|
179
288
|
def merge_watermarks_with_pdf(
|
PyPDFForm/widgets/__init__.py
CHANGED
PyPDFForm/widgets/base.py
CHANGED
|
@@ -12,8 +12,7 @@ Classes:
|
|
|
12
12
|
functionality for rendering and manipulation.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
# TODO: In `watermarks`, the list comprehension `[watermark.read() if i == self.page_number - 1 else b"" for i in range(page_count)]` creates a new `BytesIO` object and reads from it for each widget. If many widgets are created, this could be optimized by creating the `BytesIO` object once and passing it around, or by directly returning the watermark bytes and its page number.
|
|
15
|
+
from __future__ import annotations
|
|
17
16
|
|
|
18
17
|
from dataclasses import dataclass
|
|
19
18
|
from inspect import signature
|
|
@@ -28,35 +27,6 @@ from ..constants import fieldFlags, required
|
|
|
28
27
|
from ..utils import stream_to_io
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
@dataclass
|
|
32
|
-
class Field:
|
|
33
|
-
"""
|
|
34
|
-
Base dataclass for all PDF form fields.
|
|
35
|
-
|
|
36
|
-
This class defines the common properties that all types of form fields
|
|
37
|
-
(e.g., text fields, checkboxes, radio buttons) share. Specific field types
|
|
38
|
-
will extend this class to add their unique attributes.
|
|
39
|
-
|
|
40
|
-
Attributes:
|
|
41
|
-
name (str): The name of the form field. This is used to identify the
|
|
42
|
-
field within the PDF document.
|
|
43
|
-
page_number (int): The 1-based page number on which the field is located.
|
|
44
|
-
x (float): The x-coordinate of the field's position on the page.
|
|
45
|
-
y (float): The y-coordinate of the field's position on the page.
|
|
46
|
-
required (Optional[bool]): Indicates whether the field is required to be
|
|
47
|
-
filled by the user. Defaults to None, meaning not explicitly set.
|
|
48
|
-
tooltip (Optional[str]): A tooltip message that appears when the user
|
|
49
|
-
hovers over the field. Defaults to None.
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
name: str
|
|
53
|
-
page_number: int
|
|
54
|
-
x: float
|
|
55
|
-
y: float
|
|
56
|
-
required: Optional[bool] = None
|
|
57
|
-
tooltip: Optional[str] = None
|
|
58
|
-
|
|
59
|
-
|
|
60
30
|
class Widget:
|
|
61
31
|
"""
|
|
62
32
|
Base class for all widgets in PyPDFForm.
|
|
@@ -106,6 +76,7 @@ class Widget:
|
|
|
106
76
|
"""
|
|
107
77
|
super().__init__()
|
|
108
78
|
self.page_number = page_number
|
|
79
|
+
self.name = name
|
|
109
80
|
self.acro_form_params = {
|
|
110
81
|
"name": name,
|
|
111
82
|
"x": x,
|
|
@@ -181,44 +152,93 @@ class Widget:
|
|
|
181
152
|
"""
|
|
182
153
|
getattr(canvas.acroForm, self.ACRO_FORM_FUNC)(**self.acro_form_params)
|
|
183
154
|
|
|
184
|
-
|
|
155
|
+
@staticmethod
|
|
156
|
+
def bulk_watermarks(widgets: List[Widget], stream: bytes) -> List[bytes]:
|
|
185
157
|
"""
|
|
186
|
-
Generates watermarks for
|
|
158
|
+
Generates watermarks for multiple widgets in bulk.
|
|
187
159
|
|
|
188
|
-
This method
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
160
|
+
This static method processes a list of widgets and a PDF stream to create
|
|
161
|
+
a list of watermark streams, one for each page of the PDF. Widgets are
|
|
162
|
+
grouped by their page number, and all widgets for a given page are drawn
|
|
163
|
+
onto a single ReportLab canvas, which is then returned as the watermark
|
|
164
|
+
stream for that page. This is more efficient than generating watermarks
|
|
165
|
+
for each widget individually.
|
|
192
166
|
|
|
193
167
|
Args:
|
|
194
|
-
|
|
168
|
+
widgets (List[Widget]): A list of Widget objects to be watermarked.
|
|
169
|
+
stream (bytes): The PDF stream to be watermarked.
|
|
195
170
|
|
|
196
171
|
Returns:
|
|
197
|
-
List[bytes]:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
172
|
+
List[bytes]: A list of watermark streams (bytes), where the index
|
|
173
|
+
corresponds to the 0-based page index of the original PDF.
|
|
174
|
+
Each element is a byte stream representing the combined
|
|
175
|
+
watermark for that page. Pages without any widgets will
|
|
176
|
+
have an empty byte string (b"").
|
|
201
177
|
"""
|
|
178
|
+
result = []
|
|
179
|
+
|
|
202
180
|
pdf = PdfReader(stream_to_io(stream))
|
|
203
|
-
page_count = len(pdf.pages)
|
|
204
181
|
watermark = BytesIO()
|
|
205
182
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
183
|
+
widgets_by_page = {}
|
|
184
|
+
for widget in widgets:
|
|
185
|
+
if widget.page_number not in widgets_by_page:
|
|
186
|
+
widgets_by_page[widget.page_number] = []
|
|
187
|
+
widgets_by_page[widget.page_number].append(widget)
|
|
188
|
+
|
|
189
|
+
for i, page in enumerate(pdf.pages):
|
|
190
|
+
page_num = i + 1
|
|
191
|
+
if page_num not in widgets_by_page:
|
|
192
|
+
result.append(b"")
|
|
193
|
+
continue
|
|
213
194
|
|
|
214
|
-
|
|
215
|
-
|
|
195
|
+
watermark.seek(0)
|
|
196
|
+
watermark.flush()
|
|
216
197
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
198
|
+
canvas = Canvas(
|
|
199
|
+
watermark,
|
|
200
|
+
pagesize=(
|
|
201
|
+
float(page.mediabox[2]),
|
|
202
|
+
float(page.mediabox[3]),
|
|
203
|
+
),
|
|
204
|
+
)
|
|
220
205
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
206
|
+
for widget in widgets_by_page[page_num]:
|
|
207
|
+
getattr(widget, "_required_handler")(canvas)
|
|
208
|
+
widget.canvas_operations(canvas)
|
|
209
|
+
|
|
210
|
+
canvas.showPage()
|
|
211
|
+
canvas.save()
|
|
212
|
+
watermark.seek(0)
|
|
213
|
+
result.append(watermark.read())
|
|
214
|
+
|
|
215
|
+
return result
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@dataclass
|
|
219
|
+
class Field:
|
|
220
|
+
"""
|
|
221
|
+
Base dataclass for all PDF form fields.
|
|
222
|
+
|
|
223
|
+
This class defines the common properties that all types of form fields
|
|
224
|
+
(e.g., text fields, checkboxes, radio buttons) share. Specific field types
|
|
225
|
+
will extend this class to add their unique attributes.
|
|
226
|
+
|
|
227
|
+
Attributes:
|
|
228
|
+
name (str): The name of the form field. This is used to identify the
|
|
229
|
+
field within the PDF document.
|
|
230
|
+
page_number (int): The 1-based page number on which the field is located.
|
|
231
|
+
x (float): The x-coordinate of the field's position on the page.
|
|
232
|
+
y (float): The y-coordinate of the field's position on the page.
|
|
233
|
+
required (Optional[bool]): Indicates whether the field is required to be
|
|
234
|
+
filled by the user. Defaults to None, meaning not explicitly set.
|
|
235
|
+
tooltip (Optional[str]): A tooltip message that appears when the user
|
|
236
|
+
hovers over the field. Defaults to None.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
name: str
|
|
240
|
+
page_number: int
|
|
241
|
+
x: float
|
|
242
|
+
y: float
|
|
243
|
+
required: Optional[bool] = None
|
|
244
|
+
tooltip: Optional[str] = None
|
PyPDFForm/widgets/checkbox.py
CHANGED
|
@@ -11,40 +11,11 @@ functionality for interacting with checkbox form fields in PDFs.
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
|
-
from typing import Optional, Tuple
|
|
14
|
+
from typing import Optional, Tuple, Type
|
|
15
15
|
|
|
16
16
|
from .base import Field, Widget
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
@dataclass
|
|
20
|
-
class CheckBoxField(Field):
|
|
21
|
-
"""
|
|
22
|
-
Represents a checkbox field in a PDF document.
|
|
23
|
-
|
|
24
|
-
This dataclass extends the `Field` base class and defines the specific
|
|
25
|
-
attributes that can be configured for a checkbox field.
|
|
26
|
-
|
|
27
|
-
Attributes:
|
|
28
|
-
_field_type (str): The type of the field, fixed as "checkbox".
|
|
29
|
-
size (Optional[float]): The size of the checkbox.
|
|
30
|
-
button_style (Optional[str]): The visual style of the checkbox button
|
|
31
|
-
(e.g., "check", "circle", "cross").
|
|
32
|
-
tick_color (Optional[Tuple[float, ...]]): The color of the checkmark or tick.
|
|
33
|
-
bg_color (Optional[Tuple[float, ...]]): The background color of the checkbox.
|
|
34
|
-
border_color (Optional[Tuple[float, ...]]): The color of the checkbox's border.
|
|
35
|
-
border_width (Optional[float]): The width of the checkbox's border.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
_field_type: str = "checkbox"
|
|
39
|
-
|
|
40
|
-
size: Optional[float] = None
|
|
41
|
-
button_style: Optional[str] = None
|
|
42
|
-
tick_color: Optional[Tuple[float, ...]] = None
|
|
43
|
-
bg_color: Optional[Tuple[float, ...]] = None
|
|
44
|
-
border_color: Optional[Tuple[float, ...]] = None
|
|
45
|
-
border_width: Optional[float] = None
|
|
46
|
-
|
|
47
|
-
|
|
48
19
|
class CheckBoxWidget(Widget):
|
|
49
20
|
"""
|
|
50
21
|
Represents a checkbox widget in a PDF form.
|
|
@@ -74,3 +45,32 @@ class CheckBoxWidget(Widget):
|
|
|
74
45
|
COLOR_PARAMS = ["tick_color", "bg_color", "border_color"]
|
|
75
46
|
ALLOWED_HOOK_PARAMS = ["size"]
|
|
76
47
|
ACRO_FORM_FUNC = "checkbox"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class CheckBoxField(Field):
|
|
52
|
+
"""
|
|
53
|
+
Represents a checkbox field in a PDF document.
|
|
54
|
+
|
|
55
|
+
This dataclass extends the `Field` base class and defines the specific
|
|
56
|
+
attributes that can be configured for a checkbox field.
|
|
57
|
+
|
|
58
|
+
Attributes:
|
|
59
|
+
_widget_class (Type[Widget]): The widget class associated with this field type.
|
|
60
|
+
size (Optional[float]): The size of the checkbox.
|
|
61
|
+
button_style (Optional[str]): The visual style of the checkbox button
|
|
62
|
+
(e.g., "check", "circle", "cross").
|
|
63
|
+
tick_color (Optional[Tuple[float, ...]]): The color of the checkmark or tick.
|
|
64
|
+
bg_color (Optional[Tuple[float, ...]]): The background color of the checkbox.
|
|
65
|
+
border_color (Optional[Tuple[float, ...]]): The color of the checkbox's border.
|
|
66
|
+
border_width (Optional[float]): The width of the checkbox's border.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
_widget_class: Type[Widget] = CheckBoxWidget
|
|
70
|
+
|
|
71
|
+
size: Optional[float] = None
|
|
72
|
+
button_style: Optional[str] = None
|
|
73
|
+
tick_color: Optional[Tuple[float, ...]] = None
|
|
74
|
+
bg_color: Optional[Tuple[float, ...]] = None
|
|
75
|
+
border_color: Optional[Tuple[float, ...]] = None
|
|
76
|
+
border_width: Optional[float] = None
|
PyPDFForm/widgets/dropdown.py
CHANGED
|
@@ -11,49 +11,12 @@ specific functionality for interacting with dropdown form fields in PDFs.
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
|
-
from typing import List, Optional, Tuple, Union
|
|
14
|
+
from typing import List, Optional, Tuple, Type, Union
|
|
15
15
|
|
|
16
|
-
from .base import Field
|
|
16
|
+
from .base import Field, Widget
|
|
17
17
|
from .text import TextWidget
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
@dataclass
|
|
21
|
-
class DropdownField(Field):
|
|
22
|
-
"""
|
|
23
|
-
Represents a dropdown field in a PDF document.
|
|
24
|
-
|
|
25
|
-
This dataclass extends the `Field` base class and defines the specific
|
|
26
|
-
attributes that can be configured for a dropdown selection field.
|
|
27
|
-
|
|
28
|
-
Attributes:
|
|
29
|
-
_field_type (str): The type of the field, fixed as "dropdown".
|
|
30
|
-
options (Optional[List[Union[str, Tuple[str, str]]]]): A list of options
|
|
31
|
-
available in the dropdown. Each option can be a string (display value)
|
|
32
|
-
or a tuple of strings (display value, export value).
|
|
33
|
-
width (Optional[float]): The width of the dropdown field.
|
|
34
|
-
height (Optional[float]): The height of the dropdown field.
|
|
35
|
-
font (Optional[str]): The font to use for the dropdown text.
|
|
36
|
-
font_size (Optional[float]): The font size for the dropdown text.
|
|
37
|
-
font_color (Optional[Tuple[float, ...]]): The color of the font as an RGB or RGBA tuple.
|
|
38
|
-
bg_color (Optional[Tuple[float, ...]]): The background color of the dropdown field.
|
|
39
|
-
border_color (Optional[Tuple[float, ...]]): The color of the dropdown's border.
|
|
40
|
-
border_width (Optional[float]): The width of the dropdown's border.
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
_field_type: str = "dropdown"
|
|
44
|
-
|
|
45
|
-
options: Optional[List[Union[str, Tuple[str, str]]]] = None
|
|
46
|
-
width: Optional[float] = None
|
|
47
|
-
height: Optional[float] = None
|
|
48
|
-
# pylint: disable=R0801
|
|
49
|
-
font: Optional[str] = None
|
|
50
|
-
font_size: Optional[float] = None
|
|
51
|
-
font_color: Optional[Tuple[float, ...]] = None
|
|
52
|
-
bg_color: Optional[Tuple[float, ...]] = None
|
|
53
|
-
border_color: Optional[Tuple[float, ...]] = None
|
|
54
|
-
border_width: Optional[float] = None
|
|
55
|
-
|
|
56
|
-
|
|
57
20
|
class DropdownWidget(TextWidget):
|
|
58
21
|
"""
|
|
59
22
|
Represents a dropdown widget in a PDF form.
|
|
@@ -93,4 +56,43 @@ class DropdownWidget(TextWidget):
|
|
|
93
56
|
]
|
|
94
57
|
super().__init__(name, page_number, x, y, **kwargs)
|
|
95
58
|
self.acro_form_params["wkind"] = "choice"
|
|
96
|
-
self.acro_form_params["value"] =
|
|
59
|
+
self.acro_form_params["value"] = (
|
|
60
|
+
self.acro_form_params["options"][0] or " " # reportlab bug
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass
|
|
65
|
+
class DropdownField(Field):
|
|
66
|
+
"""
|
|
67
|
+
Represents a dropdown field in a PDF document.
|
|
68
|
+
|
|
69
|
+
This dataclass extends the `Field` base class and defines the specific
|
|
70
|
+
attributes that can be configured for a dropdown selection field.
|
|
71
|
+
|
|
72
|
+
Attributes:
|
|
73
|
+
_widget_class (Type[Widget]): The widget class associated with this field type.
|
|
74
|
+
options (Optional[List[Union[str, Tuple[str, str]]]]): A list of options
|
|
75
|
+
available in the dropdown. Each option can be a string (display value)
|
|
76
|
+
or a tuple of strings (display value, export value).
|
|
77
|
+
width (Optional[float]): The width of the dropdown field.
|
|
78
|
+
height (Optional[float]): The height of the dropdown field.
|
|
79
|
+
font (Optional[str]): The font to use for the dropdown text.
|
|
80
|
+
font_size (Optional[float]): The font size for the dropdown text.
|
|
81
|
+
font_color (Optional[Tuple[float, ...]]): The color of the font as an RGB or RGBA tuple.
|
|
82
|
+
bg_color (Optional[Tuple[float, ...]]): The background color of the dropdown field.
|
|
83
|
+
border_color (Optional[Tuple[float, ...]]): The color of the dropdown's border.
|
|
84
|
+
border_width (Optional[float]): The width of the dropdown's border.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
_widget_class: Type[Widget] = DropdownWidget
|
|
88
|
+
|
|
89
|
+
options: Optional[List[Union[str, Tuple[str, str]]]] = None
|
|
90
|
+
width: Optional[float] = None
|
|
91
|
+
height: Optional[float] = None
|
|
92
|
+
# pylint: disable=R0801
|
|
93
|
+
font: Optional[str] = None
|
|
94
|
+
font_size: Optional[float] = None
|
|
95
|
+
font_color: Optional[Tuple[float, ...]] = None
|
|
96
|
+
bg_color: Optional[Tuple[float, ...]] = None
|
|
97
|
+
border_color: Optional[Tuple[float, ...]] = None
|
|
98
|
+
border_width: Optional[float] = None
|
PyPDFForm/widgets/image.py
CHANGED
|
@@ -12,26 +12,11 @@ leveraging the existing infrastructure for positioning and rendering.
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
from dataclasses import dataclass
|
|
15
|
+
from typing import Type
|
|
15
16
|
|
|
16
17
|
from .signature import SignatureField, SignatureWidget
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
@dataclass
|
|
20
|
-
class ImageField(SignatureField):
|
|
21
|
-
"""
|
|
22
|
-
Represents an image field in a PDF document.
|
|
23
|
-
|
|
24
|
-
This dataclass extends the `SignatureField` base class and defines the
|
|
25
|
-
specific attributes for an image input field. It inherits `width` and
|
|
26
|
-
`height` from `SignatureField` as images also have dimensions.
|
|
27
|
-
|
|
28
|
-
Attributes:
|
|
29
|
-
_field_type (str): The type of the field, fixed as "image".
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
_field_type: str = "image"
|
|
33
|
-
|
|
34
|
-
|
|
35
20
|
class ImageWidget(SignatureWidget):
|
|
36
21
|
"""
|
|
37
22
|
Represents an image widget in a PDF form.
|
|
@@ -47,3 +32,19 @@ class ImageWidget(SignatureWidget):
|
|
|
47
32
|
"""
|
|
48
33
|
|
|
49
34
|
BEDROCK_WIDGET_TO_COPY = "image"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class ImageField(SignatureField):
|
|
39
|
+
"""
|
|
40
|
+
Represents an image field in a PDF document.
|
|
41
|
+
|
|
42
|
+
This dataclass extends the `SignatureField` base class and defines the
|
|
43
|
+
specific attributes for an image input field. It inherits `width` and
|
|
44
|
+
`height` from `SignatureField` as images also have dimensions.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
_widget_class (Type[ImageWidget]): The widget class associated with this field type.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
_widget_class: Type[ImageWidget] = ImageWidget
|