PyPDFForm 2.0.1__py3-none-any.whl → 2.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/font.py CHANGED
@@ -1,5 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains helpers for font."""
2
+ """Provides font handling utilities for PDF forms.
3
+
4
+ This module contains functions for:
5
+ - Registering custom fonts from TTF files
6
+ - Extracting font information from PDF text appearances
7
+ - Calculating font sizes based on widget dimensions
8
+ - Adjusting font sizes to fit text within fields
9
+ - Managing font colors and properties
10
+ """
3
11
 
4
12
  from io import BytesIO
5
13
  from math import sqrt
@@ -20,7 +28,15 @@ from .utils import extract_widget_property
20
28
 
21
29
 
22
30
  def register_font(font_name: str, ttf_stream: bytes) -> bool:
23
- """Registers a font from a ttf file stream."""
31
+ """Registers a TrueType font for use in PDF generation.
32
+
33
+ Args:
34
+ font_name: Name to register the font under
35
+ ttf_stream: TTF font data as bytes
36
+
37
+ Returns:
38
+ bool: True if registration succeeded, False if failed
39
+ """
24
40
 
25
41
  buff = BytesIO()
26
42
  buff.write(ttf_stream)
@@ -37,9 +53,15 @@ def register_font(font_name: str, ttf_stream: bytes) -> bool:
37
53
 
38
54
 
39
55
  def extract_font_from_text_appearance(text_appearance: str) -> Union[str, None]:
40
- """
41
- Uses regex to pattern match out the font from the text
42
- appearance string of a text field widget.
56
+ """Extracts font name from PDF text appearance string.
57
+
58
+ Parses the font information embedded in PDF text field appearance strings.
59
+
60
+ Args:
61
+ text_appearance: PDF text appearance string (/DA field)
62
+
63
+ Returns:
64
+ Union[str, None]: Font name if found, None if not found
43
65
  """
44
66
 
45
67
  text_appearances = text_appearance.split(" ")
@@ -70,7 +92,16 @@ def extract_font_from_text_appearance(text_appearance: str) -> Union[str, None]:
70
92
 
71
93
 
72
94
  def auto_detect_font(widget: dict) -> str:
73
- """Returns the font of the text field if it is one of the standard fonts."""
95
+ """Attempts to detect the font used in a PDF text field widget.
96
+
97
+ Falls back to DEFAULT_FONT if detection fails.
98
+
99
+ Args:
100
+ widget: PDF form widget dictionary
101
+
102
+ Returns:
103
+ str: Detected font name or DEFAULT_FONT
104
+ """
74
105
 
75
106
  text_appearance = extract_widget_property(
76
107
  widget, TEXT_FIELD_APPEARANCE_PATTERNS, None, None
@@ -83,9 +114,13 @@ def auto_detect_font(widget: dict) -> str:
83
114
 
84
115
 
85
116
  def text_field_font_size(widget: dict) -> Union[float, int]:
86
- """
87
- Calculates the font size it should be drawn with
88
- given a text field widget.
117
+ """Calculates an appropriate font size based on text field dimensions.
118
+
119
+ Args:
120
+ widget: PDF form widget dictionary containing Rect coordinates
121
+
122
+ Returns:
123
+ Union[float, int]: Suggested font size in points
89
124
  """
90
125
 
91
126
  height = abs(float(widget[Rect][1]) - float(widget[Rect][3]))
@@ -94,9 +129,13 @@ def text_field_font_size(widget: dict) -> Union[float, int]:
94
129
 
95
130
 
96
131
  def checkbox_radio_font_size(widget: dict) -> Union[float, int]:
97
- """
98
- Calculates the font size it should be drawn with
99
- given a checkbox/radio button widget.
132
+ """Calculates appropriate symbol size for checkbox/radio widgets.
133
+
134
+ Args:
135
+ widget: PDF form widget dictionary containing Rect coordinates
136
+
137
+ Returns:
138
+ Union[float, int]: Suggested symbol size in points
100
139
  """
101
140
 
102
141
  area = abs(float(widget[Rect][0]) - float(widget[Rect][2])) * abs(
@@ -107,7 +146,14 @@ def checkbox_radio_font_size(widget: dict) -> Union[float, int]:
107
146
 
108
147
 
109
148
  def get_text_field_font_size(widget: dict) -> Union[float, int]:
110
- """Returns the font size of the text field if presented or zero."""
149
+ """Extracts font size from PDF text field appearance properties.
150
+
151
+ Args:
152
+ widget: PDF form widget dictionary
153
+
154
+ Returns:
155
+ Union[float, int]: Font size in points if found, otherwise 0
156
+ """
111
157
 
112
158
  result = 0
113
159
  text_appearance = extract_widget_property(
@@ -125,7 +171,15 @@ def get_text_field_font_size(widget: dict) -> Union[float, int]:
125
171
  def get_text_field_font_color(
126
172
  widget: dict,
127
173
  ) -> Union[Tuple[float, float, float], None]:
128
- """Returns the font color tuple of the text field if presented or black."""
174
+ """Extracts font color from PDF text field appearance properties.
175
+
176
+ Args:
177
+ widget: PDF form widget dictionary
178
+
179
+ Returns:
180
+ Union[Tuple[float, float, float], None]: RGB color tuple (0-1 range)
181
+ or black by default if not specified
182
+ """
129
183
 
130
184
  result = (0, 0, 0)
131
185
  text_appearance = extract_widget_property(
@@ -149,7 +203,12 @@ def get_text_field_font_color(
149
203
 
150
204
 
151
205
  def adjust_paragraph_font_size(widget: dict, widget_middleware: Text) -> None:
152
- """Reduces the font size of a paragraph field until texts fits."""
206
+ """Dynamically reduces font size until text fits in paragraph field.
207
+
208
+ Args:
209
+ widget: PDF form widget dictionary
210
+ widget_middleware: Text middleware instance containing text properties
211
+ """
153
212
 
154
213
  # pylint: disable=C0415, R0401
155
214
  from .template import get_paragraph_lines
@@ -167,7 +226,12 @@ def adjust_paragraph_font_size(widget: dict, widget_middleware: Text) -> None:
167
226
 
168
227
 
169
228
  def adjust_text_field_font_size(widget: dict, widget_middleware: Text) -> None:
170
- """Reduces the font size of a text field until texts fits."""
229
+ """Dynamically reduces font size until text fits in text field.
230
+
231
+ Args:
232
+ widget: PDF form widget dictionary
233
+ widget_middleware: Text middleware instance containing text properties
234
+ """
171
235
 
172
236
  width = abs(float(widget[Rect][0]) - float(widget[Rect][2]))
173
237
 
PyPDFForm/image.py CHANGED
@@ -1,5 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains helpers for image."""
2
+ """Provides image processing utilities for PDF forms.
3
+
4
+ This module contains functions for:
5
+ - Rotating images while maintaining quality
6
+ - Extracting image dimensions
7
+ - Handling image streams and formats
8
+
9
+ Supports common image formats including JPEG, PNG, and others supported by PIL.
10
+ """
3
11
 
4
12
  from io import BytesIO
5
13
  from typing import Tuple, Union
@@ -8,7 +16,18 @@ from PIL import Image
8
16
 
9
17
 
10
18
  def rotate_image(image_stream: bytes, rotation: Union[float, int]) -> bytes:
11
- """Rotates an image by a rotation angle."""
19
+ """Rotates an image while maintaining original quality and format.
20
+
21
+ Args:
22
+ image_stream: Input image as bytes
23
+ rotation: Rotation angle in degrees (can be a float for precise angles)
24
+
25
+ Returns:
26
+ bytes: Rotated image as bytes in the original format
27
+
28
+ Note:
29
+ Automatically expands the canvas to prevent cropping during rotation.
30
+ """
12
31
 
13
32
  buff = BytesIO()
14
33
  buff.write(image_stream)
@@ -29,7 +48,17 @@ def rotate_image(image_stream: bytes, rotation: Union[float, int]) -> bytes:
29
48
 
30
49
 
31
50
  def get_image_dimensions(image_stream: bytes) -> Tuple[float, float]:
32
- """Gets the width and height of an image."""
51
+ """Extracts width and height from an image stream.
52
+
53
+ Args:
54
+ image_stream: Input image as bytes
55
+
56
+ Returns:
57
+ Tuple[float, float]: (width, height) in pixels
58
+
59
+ Note:
60
+ Works with any image format supported by PIL (Pillow)
61
+ """
33
62
 
34
63
  buff = BytesIO()
35
64
  buff.write(image_stream)
@@ -1,18 +1,42 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains widget middleware."""
2
+ """Provides base widget middleware for PDF form elements.
3
+
4
+ This module contains the Widget base class that defines common functionality
5
+ and properties for all PDF form widgets, including:
6
+ - Name and value management
7
+ - Styling properties (borders, colors)
8
+ - Schema generation
9
+ - Basic validation
10
+ """
3
11
 
4
12
  from typing import Any
5
13
 
6
14
 
7
15
  class Widget:
8
- """Base class for all PDF form widgets."""
16
+ """Abstract base class for all PDF form widget middleware.
17
+
18
+ Provides common interface and functionality for:
19
+ - Managing widget names and values
20
+ - Handling visual properties (borders, colors)
21
+ - Generating JSON schema definitions
22
+ - Providing sample values
23
+
24
+ Subclasses must implement:
25
+ - sample_value property
26
+ - Any widget-specific functionality
27
+ """
9
28
 
10
29
  def __init__(
11
30
  self,
12
31
  name: str,
13
32
  value: Any = None,
14
33
  ) -> None:
15
- """Constructs basic attributes for the object."""
34
+ """Initializes a new widget with basic properties.
35
+
36
+ Args:
37
+ name: Field name/key for the widget
38
+ value: Initial value for the widget (default: None)
39
+ """
16
40
 
17
41
  super().__init__()
18
42
  self._name = name
@@ -28,25 +52,44 @@ class Widget:
28
52
 
29
53
  @property
30
54
  def name(self) -> str:
31
- """Name of the widget."""
55
+ """Gets the widget's field name/key.
56
+
57
+ Returns:
58
+ str: The widget's name as it appears in the PDF form
59
+ """
32
60
 
33
61
  return self._name
34
62
 
35
63
  @property
36
64
  def value(self) -> Any:
37
- """Value to fill for the widget."""
65
+ """Gets the widget's current value.
66
+
67
+ Returns:
68
+ Any: The widget's current value (type depends on widget type)
69
+ """
38
70
 
39
71
  return self._value
40
72
 
41
73
  @value.setter
42
74
  def value(self, value: Any) -> None:
43
- """Sets value to fill for the widget."""
75
+ """Sets the widget's value.
76
+
77
+ Args:
78
+ value: New value for the widget (type depends on widget type)
79
+ """
44
80
 
45
81
  self._value = value
46
82
 
47
83
  @property
48
84
  def schema_definition(self) -> dict:
49
- """Json schema definition of the widget."""
85
+ """Generates a JSON schema definition for the widget.
86
+
87
+ Returns:
88
+ dict: Schema properties including:
89
+ - description (if available)
90
+ - type constraints
91
+ - other widget-specific properties
92
+ """
50
93
 
51
94
  result = {}
52
95
 
@@ -57,6 +100,12 @@ class Widget:
57
100
 
58
101
  @property
59
102
  def sample_value(self) -> Any:
60
- """Sample value of the widget."""
103
+ """Generates a sample value appropriate for the widget type.
104
+
105
+ Returns:
106
+ Any: A representative value demonstrating the widget's expected input
61
107
 
108
+ Raises:
109
+ NotImplementedError: Must be implemented by subclasses
110
+ """
62
111
  raise NotImplementedError
@@ -1,5 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains checkbox middleware."""
2
+ """Provides middleware for PDF checkbox widgets.
3
+
4
+ This module contains the Checkbox class which handles:
5
+ - Checkbox state management (checked/unchecked)
6
+ - Button style customization
7
+ - Value validation and conversion
8
+ - Schema generation for form validation
9
+ """
3
10
 
4
11
  from typing import Union
5
12
 
@@ -7,7 +14,16 @@ from .base import Widget
7
14
 
8
15
 
9
16
  class Checkbox(Widget):
10
- """A class to represent a checkbox widget."""
17
+ """Middleware for PDF checkbox widgets.
18
+
19
+ Handles all aspects of checkbox processing including:
20
+ - State management (checked/unchecked)
21
+ - Button style customization (check, cross, circle)
22
+ - Value validation
23
+ - PDF form field integration
24
+
25
+ Inherits from Widget base class and extends it with checkbox-specific features.
26
+ """
11
27
 
12
28
  BUTTON_STYLE_MAPPING = {
13
29
  "check": "4",
@@ -20,7 +36,12 @@ class Checkbox(Widget):
20
36
  name: str,
21
37
  value: bool = None,
22
38
  ) -> None:
23
- """Constructs all attributes for the checkbox."""
39
+ """Initializes a new checkbox widget.
40
+
41
+ Args:
42
+ name: Field name/key for the checkbox
43
+ value: Initial checked state (default: None)
44
+ """
24
45
 
25
46
  super().__init__(name, value)
26
47
 
@@ -29,25 +50,46 @@ class Checkbox(Widget):
29
50
 
30
51
  @property
31
52
  def schema_definition(self) -> dict:
32
- """Json schema definition of the checkbox."""
53
+ """Generates a JSON schema definition for the checkbox.
54
+
55
+ Returns:
56
+ dict: Schema properties including:
57
+ - type: boolean
58
+ - description (if available from base class)
59
+ """
33
60
 
34
61
  return {"type": "boolean", **super().schema_definition}
35
62
 
36
63
  @property
37
64
  def sample_value(self) -> Union[bool, int]:
38
- """Sample value of the checkbox."""
65
+ """Generates a sample value for the checkbox.
66
+
67
+ Returns:
68
+ Union[bool, int]: Always returns True as the sample checked state
69
+ """
39
70
 
40
71
  return True
41
72
 
42
73
  @property
43
74
  def button_style(self) -> Union[str, None]:
44
- """Shape of the tick for the checkbox."""
75
+ """Gets the current button style identifier.
76
+
77
+ Returns:
78
+ Union[str, None]: The button style code used in PDF form fields
79
+ """
45
80
 
46
81
  return self._button_style
47
82
 
48
83
  @button_style.setter
49
84
  def button_style(self, value) -> None:
50
- """Converts user specified button styles to acroform values."""
85
+ """Sets the button style for the checkbox.
86
+
87
+ Accepts either style names ('check', 'cross', 'circle') or
88
+ direct PDF button style codes ('4', '5', 'l').
89
+
90
+ Args:
91
+ value: Button style name or code to set
92
+ """
51
93
 
52
94
  if value in self.BUTTON_STYLE_MAPPING:
53
95
  self._button_style = self.BUTTON_STYLE_MAPPING[value]
@@ -1,18 +1,39 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains dropdown middleware."""
2
+ """Provides middleware for PDF dropdown/combobox widgets.
3
+
4
+ This module contains the Dropdown class which handles:
5
+ - Dropdown option management
6
+ - Selection index tracking
7
+ - Value validation
8
+ - Schema generation for form validation
9
+ """
3
10
 
4
11
  from .base import Widget
5
12
 
6
13
 
7
14
  class Dropdown(Widget):
8
- """A class to represent a dropdown widget."""
15
+ """Middleware for PDF dropdown/combobox widgets.
16
+
17
+ Handles all aspects of dropdown processing including:
18
+ - Option list management
19
+ - Selection index validation
20
+ - Value conversion
21
+ - PDF form field integration
22
+
23
+ Inherits from Widget base class and extends it with dropdown-specific features.
24
+ """
9
25
 
10
26
  def __init__(
11
27
  self,
12
28
  name: str,
13
29
  value: int = None,
14
30
  ) -> None:
15
- """Constructs all attributes for the dropdown."""
31
+ """Initializes a new dropdown widget.
32
+
33
+ Args:
34
+ name: Field name/key for the dropdown
35
+ value: Initial selected option index (default: None)
36
+ """
16
37
 
17
38
  super().__init__(name, value)
18
39
 
@@ -21,7 +42,16 @@ class Dropdown(Widget):
21
42
 
22
43
  @property
23
44
  def schema_definition(self) -> dict:
24
- """Json schema definition of the dropdown."""
45
+ """Generates a JSON schema definition for the dropdown.
46
+
47
+ Includes:
48
+ - Type constraint (integer)
49
+ - Maximum valid option index
50
+ - Any inherited schema properties
51
+
52
+ Returns:
53
+ dict: Complete JSON schema definition
54
+ """
25
55
 
26
56
  return {
27
57
  "type": "integer",
@@ -31,6 +61,12 @@ class Dropdown(Widget):
31
61
 
32
62
  @property
33
63
  def sample_value(self) -> int:
34
- """Sample value of the dropdown."""
64
+ """Generates a sample value for the dropdown.
65
+
66
+ Returns the index of the last option by default.
67
+
68
+ Returns:
69
+ int: Index of the last option in the dropdown
70
+ """
35
71
 
36
72
  return len(self.choices) - 1
@@ -1,10 +1,34 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains image field middleware."""
2
+ """Provides middleware for PDF image field widgets.
3
+
4
+ This module contains the Image class which handles:
5
+ - Image field processing for common formats (JPEG, PNG)
6
+ - Aspect ratio preservation when scaling
7
+ - PDF form field integration
8
+ - Image rotation and positioning
9
+
10
+ Supports image data from:
11
+ - Raw bytes
12
+ - File paths
13
+ - File-like objects
14
+
15
+ Note: Inherits core functionality from Signature middleware since
16
+ PDF image fields are technically signature fields with images.
17
+ """
3
18
 
4
19
  from .signature import Signature
5
20
 
6
21
 
7
22
  class Image(Signature):
8
- """A class to represent an image field widget."""
23
+ """Middleware for PDF image field widgets.
24
+
25
+ Handles all aspects of image field processing including:
26
+ - Image data handling
27
+ - Aspect ratio control
28
+ - PDF form field integration
29
+
30
+ Inherits from Signature class and extends it with image-specific features.
31
+ """
9
32
 
10
33
  preserve_aspect_ratio = False
34
+ """Whether to preserve the original image's aspect ratio when scaling."""
@@ -1,18 +1,39 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains radio middleware."""
2
+ """Provides middleware for PDF radio button widgets.
3
+
4
+ This module contains the Radio class which handles:
5
+ - Radio button group state management
6
+ - Option selection tracking
7
+ - Value validation and conversion
8
+ - Schema generation for form validation
9
+ """
3
10
 
4
11
  from .checkbox import Checkbox
5
12
 
6
13
 
7
14
  class Radio(Checkbox):
8
- """A class to represent a radiobutton widget."""
15
+ """Middleware for PDF radio button widgets.
16
+
17
+ Handles all aspects of radio button processing including:
18
+ - Group selection management
19
+ - Option counting and validation
20
+ - Button style customization
21
+ - PDF form field integration
22
+
23
+ Inherits from Checkbox class and extends it with radio-specific features.
24
+ """
9
25
 
10
26
  def __init__(
11
27
  self,
12
28
  name: str,
13
29
  value: int = None,
14
30
  ) -> None:
15
- """Constructs all attributes for the radiobutton."""
31
+ """Initializes a new radio button widget.
32
+
33
+ Args:
34
+ name: Field name/key for the radio button group
35
+ value: Initial selected option index (default: None)
36
+ """
16
37
 
17
38
  super().__init__(name, value)
18
39
 
@@ -22,7 +43,16 @@ class Radio(Checkbox):
22
43
 
23
44
  @property
24
45
  def schema_definition(self) -> dict:
25
- """Json schema definition of the radiobutton."""
46
+ """Generates a JSON schema definition for the radio button group.
47
+
48
+ Includes:
49
+ - Type constraint (integer)
50
+ - Maximum valid option index
51
+ - Any inherited schema properties
52
+
53
+ Returns:
54
+ dict: Complete JSON schema definition
55
+ """
26
56
 
27
57
  return {
28
58
  "maximum": self.number_of_options - 1,
@@ -32,6 +62,12 @@ class Radio(Checkbox):
32
62
 
33
63
  @property
34
64
  def sample_value(self) -> int:
35
- """Sample value of the radiobutton."""
65
+ """Generates a sample value for the radio button group.
66
+
67
+ Returns the index of the last option by default.
68
+
69
+ Returns:
70
+ int: Index of the last option in the group
71
+ """
36
72
 
37
73
  return self.number_of_options - 1