PyPDFForm 3.0.1__py3-none-any.whl → 3.1.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.

Potentially problematic release.


This version of PyPDFForm might be problematic. Click here for more details.

PyPDFForm/__init__.py CHANGED
@@ -20,7 +20,7 @@ The library supports various PDF form features, including:
20
20
  PyPDFForm aims to simplify PDF form manipulation, making it accessible to developers of all skill levels.
21
21
  """
22
22
 
23
- __version__ = "3.0.1"
23
+ __version__ = "3.1.0"
24
24
 
25
25
  from .middleware.text import Text # exposing for setting global font attrs
26
26
  from .wrapper import PdfWrapper
PyPDFForm/filler.py CHANGED
@@ -15,6 +15,7 @@ from pypdf import PdfReader, PdfWriter
15
15
  from pypdf.generic import DictionaryObject
16
16
 
17
17
  from .constants import WIDGET_TYPES, Annots
18
+ from .hooks import flatten_generic, flatten_radio
18
19
  from .image import get_draw_image_resolutions, get_image_dimensions
19
20
  from .middleware.checkbox import Checkbox
20
21
  from .middleware.dropdown import Dropdown
@@ -22,9 +23,8 @@ from .middleware.image import Image
22
23
  from .middleware.radio import Radio
23
24
  from .middleware.signature import Signature
24
25
  from .middleware.text import Text
25
- from .patterns import (flatten_generic, flatten_radio, update_checkbox_value,
26
- update_dropdown_value, update_radio_value,
27
- update_text_value)
26
+ from .patterns import (update_checkbox_value, update_dropdown_value,
27
+ update_radio_value, update_text_value)
28
28
  from .template import get_widget_key
29
29
  from .utils import stream_to_io
30
30
  from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
@@ -145,7 +145,9 @@ def fill(
145
145
 
146
146
  # flatten all
147
147
  if flatten:
148
- (flatten_radio if isinstance(widget, Radio) else flatten_generic)(annot)
148
+ (flatten_radio if isinstance(widget, Radio) else flatten_generic)(
149
+ annot, True
150
+ )
149
151
  if widget.value is None:
150
152
  continue
151
153
 
PyPDFForm/hooks.py CHANGED
@@ -4,7 +4,8 @@ This module defines widget hooks that allow for dynamic modification of PDF form
4
4
 
5
5
  It provides functions to trigger these hooks, enabling changes to text field properties
6
6
  like font, font size, color, alignment, and multiline settings, as well as the size
7
- of checkbox and radio button widgets. These hooks are triggered during the PDF form
7
+ of checkbox and radio button widgets. It also provides functions for flattening
8
+ generic and radio button widgets. These hooks are triggered during the PDF form
8
9
  filling process, allowing for customization of the form's appearance and behavior.
9
10
  """
10
11
 
@@ -17,7 +18,7 @@ from pypdf.generic import (ArrayObject, DictionaryObject, FloatObject,
17
18
  NameObject, NumberObject, TextStringObject)
18
19
 
19
20
  from .constants import (COMB, DA, FONT_COLOR_IDENTIFIER, FONT_SIZE_IDENTIFIER,
20
- MULTILINE, Annots, Ff, Opt, Parent, Q, Rect)
21
+ MULTILINE, READ_ONLY, Annots, Ff, Opt, Parent, Q, Rect)
21
22
  from .template import get_widget_key
22
23
  from .utils import stream_to_io
23
24
 
@@ -249,8 +250,78 @@ def update_dropdown_choices(annot: DictionaryObject, val: list) -> None:
249
250
 
250
251
  Args:
251
252
  annot (DictionaryObject): The annotation dictionary for the dropdown field.
252
- val (list): A list of strings representing the new choices for the dropdown.
253
+ val (list): A list of strings or tuples representing the new choices for the dropdown.
253
254
  """
254
255
  annot[NameObject(Opt)] = ArrayObject(
255
- [ArrayObject([TextStringObject(each), TextStringObject(each)]) for each in val]
256
+ [
257
+ (
258
+ ArrayObject([TextStringObject(each[1]), TextStringObject(each[0])])
259
+ if isinstance(each, tuple)
260
+ else ArrayObject([TextStringObject(each), TextStringObject(each)])
261
+ )
262
+ for each in val
263
+ ]
256
264
  )
265
+
266
+
267
+ def flatten_radio(annot: DictionaryObject, val: bool) -> None:
268
+ """
269
+ Flattens a radio button annotation by setting or unsetting the ReadOnly flag,
270
+ making it non-editable or editable based on the `val` parameter.
271
+
272
+ This function modifies the Ff (flags) entry in the radio button's annotation
273
+ dictionary or its parent dictionary if `Parent` exists in `annot`, to set or
274
+ unset the ReadOnly flag, preventing or allowing the user from changing the
275
+ selected option.
276
+
277
+ Args:
278
+ annot (DictionaryObject): The radio button annotation dictionary.
279
+ val (bool): True to flatten (make read-only), False to unflatten (make editable).
280
+ """
281
+ if Parent in annot:
282
+ annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
283
+ (
284
+ int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
285
+ if val
286
+ else int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) & ~READ_ONLY
287
+ )
288
+ )
289
+ else:
290
+ annot[NameObject(Ff)] = NumberObject(
291
+ (
292
+ int(annot.get(NameObject(Ff), 0)) | READ_ONLY
293
+ if val
294
+ else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
295
+ )
296
+ )
297
+
298
+
299
+ def flatten_generic(annot: DictionaryObject, val: bool) -> None:
300
+ """
301
+ Flattens a generic annotation by setting or unsetting the ReadOnly flag,
302
+ making it non-editable or editable based on the `val` parameter.
303
+
304
+ This function modifies the Ff (flags) entry in the annotation dictionary to
305
+ set or unset the ReadOnly flag, preventing or allowing the user from
306
+ interacting with the form field.
307
+
308
+ Args:
309
+ annot (DictionaryObject): The annotation dictionary.
310
+ val (bool): True to flatten (make read-only), False to unflatten (make editable).
311
+ """
312
+ if Parent in annot and Ff not in annot:
313
+ annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
314
+ (
315
+ int(annot.get(NameObject(Ff), 0)) | READ_ONLY
316
+ if val
317
+ else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
318
+ )
319
+ )
320
+ else:
321
+ annot[NameObject(Ff)] = NumberObject(
322
+ (
323
+ int(annot.get(NameObject(Ff), 0)) | READ_ONLY
324
+ if val
325
+ else int(annot.get(NameObject(Ff), 0)) & ~READ_ONLY
326
+ )
327
+ )
@@ -21,7 +21,9 @@ class Widget:
21
21
  as name, value, and schema definition.
22
22
  """
23
23
 
24
- SET_ATTR_TRIGGER_HOOK_MAP = {}
24
+ SET_ATTR_TRIGGER_HOOK_MAP = {
25
+ "readonly": "flatten_generic",
26
+ }
25
27
 
26
28
  def __init__(
27
29
  self,
@@ -39,6 +41,7 @@ class Widget:
39
41
  self._name = name
40
42
  self._value = value
41
43
  self.desc = None
44
+ self.readonly = None
42
45
  self.hooks_to_trigger = []
43
46
 
44
47
  def __setattr__(self, name: str, value: Any) -> None:
@@ -20,10 +20,6 @@ class Checkbox(Widget):
20
20
  implements the schema_definition and sample_value properties.
21
21
  """
22
22
 
23
- SET_ATTR_TRIGGER_HOOK_MAP = {
24
- "size": "update_check_radio_size",
25
- }
26
-
27
23
  def __init__(
28
24
  self,
29
25
  name: str,
@@ -39,6 +35,11 @@ class Checkbox(Widget):
39
35
  Attributes:
40
36
  size (int): The size of the checkbox. Defaults to None.
41
37
  """
38
+ self.SET_ATTR_TRIGGER_HOOK_MAP.update(
39
+ {
40
+ "size": "update_check_radio_size",
41
+ }
42
+ )
42
43
  super().__init__(name, value)
43
44
 
44
45
  self.size = None
@@ -26,11 +26,6 @@ class Dropdown(Widget):
26
26
  sample_value: Returns a sample value for the dropdown.
27
27
  """
28
28
 
29
- SET_ATTR_TRIGGER_HOOK_MAP = {
30
- "font": "update_text_field_font",
31
- "choices": "update_dropdown_choices",
32
- }
33
-
34
29
  def __init__(
35
30
  self,
36
31
  name: str,
@@ -47,6 +42,12 @@ class Dropdown(Widget):
47
42
  font (str): The font of the dropdown field.
48
43
  choices (List[str]): The list of choices for the dropdown.
49
44
  """
45
+ self.SET_ATTR_TRIGGER_HOOK_MAP.update(
46
+ {
47
+ "font": "update_text_field_font",
48
+ "choices": "update_dropdown_choices",
49
+ }
50
+ )
50
51
  super().__init__(name, value)
51
52
 
52
53
  self.font = None
@@ -34,6 +34,11 @@ class Radio(Checkbox):
34
34
  Attributes:
35
35
  number_of_options (int): The number of options for the radio button.
36
36
  """
37
+ self.SET_ATTR_TRIGGER_HOOK_MAP.update(
38
+ {
39
+ "readonly": "flatten_radio",
40
+ }
41
+ )
37
42
  super().__init__(name, value)
38
43
 
39
44
  self.number_of_options = 0
@@ -22,15 +22,6 @@ class Text(Widget):
22
22
  font_size, font_color, comb, alignment, and multiline.
23
23
  """
24
24
 
25
- SET_ATTR_TRIGGER_HOOK_MAP = {
26
- "font": "update_text_field_font",
27
- "font_size": "update_text_field_font_size",
28
- "font_color": "update_text_field_font_color",
29
- "comb": "update_text_field_comb",
30
- "alignment": "update_text_field_alignment",
31
- "multiline": "update_text_field_multiline",
32
- }
33
-
34
25
  def __init__(
35
26
  self,
36
27
  name: str,
@@ -52,6 +43,16 @@ class Text(Widget):
52
43
  multiline (bool): Whether the text field is multiline. Defaults to None.
53
44
  max_length (int): The maximum length of the text field. Defaults to None.
54
45
  """
46
+ self.SET_ATTR_TRIGGER_HOOK_MAP.update(
47
+ {
48
+ "font": "update_text_field_font",
49
+ "font_size": "update_text_field_font_size",
50
+ "font_color": "update_text_field_font_color",
51
+ "comb": "update_text_field_comb",
52
+ "alignment": "update_text_field_alignment",
53
+ "multiline": "update_text_field_multiline",
54
+ }
55
+ )
55
56
  super().__init__(name, value)
56
57
 
57
58
  self.font = None
PyPDFForm/patterns.py CHANGED
@@ -5,15 +5,14 @@ This module defines patterns and utility functions for interacting with PDF form
5
5
  It includes patterns for identifying different types of widgets (e.g., text fields,
6
6
  checkboxes, radio buttons, dropdowns, images, and signatures) based on their
7
7
  properties in the PDF's annotation dictionary. It also provides utility functions
8
- for updating and flattening these widgets.
8
+ for updating these widgets.
9
9
  """
10
10
 
11
11
  from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
12
12
  NumberObject, TextStringObject)
13
13
 
14
- from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, READ_ONLY,
15
- TU, A, Btn, Ch, Ff, I, N, Off, Opt, Parent, Sig, T, Tx,
16
- V, Yes)
14
+ from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, TU, A, Btn,
15
+ Ch, I, N, Off, Opt, Parent, Sig, T, Tx, V, Yes)
17
16
  from .middleware.checkbox import Checkbox
18
17
  from .middleware.dropdown import Dropdown
19
18
  from .middleware.image import Image
@@ -177,42 +176,6 @@ def update_text_value(annot: DictionaryObject, widget: Text) -> None:
177
176
  annot[NameObject(AP)] = TextStringObject(widget.value)
178
177
 
179
178
 
180
- def flatten_radio(annot: DictionaryObject) -> None:
181
- """
182
- Flattens a radio button annotation by setting the ReadOnly flag, making it non-editable.
183
-
184
- This function modifies the Ff (flags) entry in the radio button's parent
185
- dictionary to set the ReadOnly flag, preventing the user from changing the
186
- selected option.
187
-
188
- Args:
189
- annot (DictionaryObject): The radio button annotation dictionary.
190
- """
191
- annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
192
- int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
193
- )
194
-
195
-
196
- def flatten_generic(annot: DictionaryObject) -> None:
197
- """
198
- Flattens a generic annotation by setting the ReadOnly flag, making it non-editable.
199
-
200
- This function modifies the Ff (flags) entry in the annotation dictionary to
201
- set the ReadOnly flag, preventing the user from interacting with the form field.
202
-
203
- Args:
204
- annot (DictionaryObject): The annotation dictionary.
205
- """
206
- if Parent in annot and Ff not in annot:
207
- annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
208
- int(annot.get(NameObject(Ff), 0)) | READ_ONLY
209
- )
210
- else:
211
- annot[NameObject(Ff)] = NumberObject(
212
- int(annot.get(NameObject(Ff), 0)) | READ_ONLY
213
- )
214
-
215
-
216
179
  def update_annotation_name(annot: DictionaryObject, val: str) -> None:
217
180
  """
218
181
  Updates the name of an annotation, setting the T (title) entry.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 3.0.1
3
+ Version: 3.1.0
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -1,24 +1,24 @@
1
- PyPDFForm/__init__.py,sha256=fU6FXBvP7HiJDQK5BgFx4eTbgpGsOH9hZ6Xwf02-L_I,925
1
+ PyPDFForm/__init__.py,sha256=R4BorFo4mdXpjdpfUiO6kvJpowukDOHSiRpfHBV2jYs,925
2
2
  PyPDFForm/adapter.py,sha256=8E_PZlXU1ALWez_pWF_U52cynzowK_NQFYzMJoH9VUk,2428
3
3
  PyPDFForm/constants.py,sha256=WQjBvYTryj5gxxeXECPgHplXXXmqHNeVbgmhvlLDCpA,2443
4
4
  PyPDFForm/coordinate.py,sha256=VMVkqa-VAGJSGVvetZwOxeMzIgQtQdvtn_DI_qSecCE,3876
5
- PyPDFForm/filler.py,sha256=YgYYUKyG4n6ADmE7vjlorbqDVbhU3LEJn1H3Ptl26CA,7233
5
+ PyPDFForm/filler.py,sha256=KwStL6YzrNBcDd919ig83MnAxopi8Vnz3QNJzN_CjNM,7272
6
6
  PyPDFForm/font.py,sha256=EZSAHnkzaBo96p9XJrQDMcEhjh5BZ8p7WwFC3SbKRMM,8828
7
- PyPDFForm/hooks.py,sha256=myL6RS82uz4oM3mufOgFuyfMWkhhUwNNgWYLkMUuUtk,9016
7
+ PyPDFForm/hooks.py,sha256=A8p67ubWvCvzRt346Q7BjOvbi4_NXBcynXmq6fJTadY,11679
8
8
  PyPDFForm/image.py,sha256=CAC69jEfSbWbyNJcjLhjWVSNJuFh7frMI70eaiFayHw,3823
9
- PyPDFForm/patterns.py,sha256=pv2a5aJD3xv9pJddtOu_Ol7A6p0VWlDcnHyW1diqeIM,7151
9
+ PyPDFForm/patterns.py,sha256=xuKAqGf07f3WFXwASnrmcS073pSEcR9lQMqLppjkQ2E,5829
10
10
  PyPDFForm/template.py,sha256=aGhwezcynmwCEck1SUNlQvgfupn-plV9mV2FF2RNn_M,9188
11
11
  PyPDFForm/utils.py,sha256=RX2mOP2uCIcN_JcTalCdYKhnYtyYc8dUIqg1wP_7MJA,10867
12
12
  PyPDFForm/watermark.py,sha256=9p1tjaIqicXngTNai_iOEkCoXRYnR66azB4s7wNsZUw,9349
13
13
  PyPDFForm/wrapper.py,sha256=Ysd1mkvE5OfDkjUI6mNFIt16-JUKwj2ifbp1MioWPUo,25257
14
14
  PyPDFForm/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- PyPDFForm/middleware/base.py,sha256=67ZRxAs5wFLoIZ8JxviINswBIIanh_5IsiX1p3nWZC8,3001
16
- PyPDFForm/middleware/checkbox.py,sha256=cxcfi0Vm9ZPJJQAbMWn2fUinLaGpiUD47QkzC-t2kVQ,1811
17
- PyPDFForm/middleware/dropdown.py,sha256=wfVx_O94yTJA0ww65kbgGocH0zXtCZTlBR2Ak-qwYls,2301
15
+ PyPDFForm/middleware/base.py,sha256=J8mlVIzC0QrljNAjRjGm0ns6w1MJOVp5cRSyqN1Bv_Q,3074
16
+ PyPDFForm/middleware/checkbox.py,sha256=GVYVXRDFQ_nj720Vsol2kkyBf3UqTtKOXDxY0O_2moM,1863
17
+ PyPDFForm/middleware/dropdown.py,sha256=hzXTLwvHob8EyI1ePJgqMoxePfPiE4FpPehvWD6pdvc,2361
18
18
  PyPDFForm/middleware/image.py,sha256=oeXaThV9hEpHsTwH7VT4qbreh_5tsS1dwA1E_eHe61o,579
19
- PyPDFForm/middleware/radio.py,sha256=L-D669dQ-j5y867WZLjtglyqyDFpL84TcwlKAp_cJhE,2076
19
+ PyPDFForm/middleware/radio.py,sha256=4XQU8zjPzZoEx0v_ukKpHPuUhLHyAKFrAwoMVy3nC8I,2206
20
20
  PyPDFForm/middleware/signature.py,sha256=I0ygzfgodREUAEfEA2AzIszAVFg4In_K-l4bAKZiImE,2143
21
- PyPDFForm/middleware/text.py,sha256=VJ5MCw8Lx_U8eZJcxAjTvttW2qEoyybIvtlrCReP3bE,3803
21
+ PyPDFForm/middleware/text.py,sha256=HAMsLiuX0iQZnsrenlc_QJdJ2R46sxQ0Fn5VTHla9_k,3895
22
22
  PyPDFForm/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  PyPDFForm/widgets/base.py,sha256=kOfxV8HSmwXoy0vFYPgJKKDQ7RUNMACWfX6T4HeJeOU,5177
24
24
  PyPDFForm/widgets/bedrock.py,sha256=j6beU04kaQzpAIFZHI5VJLaDT5RVAAa6LzkU1luJpN8,137660
@@ -28,8 +28,8 @@ PyPDFForm/widgets/image.py,sha256=aSD-3MEZFIRL7HYVuO6Os8irfSUOLHA_rHGkqcEIPPA,85
28
28
  PyPDFForm/widgets/radio.py,sha256=nWSQQp06kRISO7Q7FVFeB3PXYvMOSc0SMhRs1bHTxeQ,2261
29
29
  PyPDFForm/widgets/signature.py,sha256=EqIRIuKSQEg8LJZ_Mu859eEvs0dwO-mzkMNuhHG1Vsg,4034
30
30
  PyPDFForm/widgets/text.py,sha256=gtheE6_w0vQPRJJ9oj_l9FaMDEGnPtvVR6_axsrmxKI,1540
31
- pypdfform-3.0.1.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
32
- pypdfform-3.0.1.dist-info/METADATA,sha256=AU8iGNQzMZynQLF-7jeMio5xJg4jjHLXYWqsaxuJ59I,4587
33
- pypdfform-3.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- pypdfform-3.0.1.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
35
- pypdfform-3.0.1.dist-info/RECORD,,
31
+ pypdfform-3.1.0.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
32
+ pypdfform-3.1.0.dist-info/METADATA,sha256=-vHzFtOdPxAwCjPm98xvD424mC3Yc0KttyMir2HvPjE,4587
33
+ pypdfform-3.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ pypdfform-3.1.0.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
35
+ pypdfform-3.1.0.dist-info/RECORD,,