PyPDFForm 1.4.22__tar.gz → 1.4.24__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.

Potentially problematic release.


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

Files changed (46) hide show
  1. {pypdfform-1.4.22 → pypdfform-1.4.24}/PKG-INFO +1 -1
  2. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/__init__.py +1 -1
  3. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/constants.py +5 -0
  4. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/filler.py +90 -62
  5. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/font.py +24 -16
  6. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/patterns.py +10 -3
  7. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/template.py +69 -24
  8. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/utils.py +4 -1
  9. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/widgets/dropdown.py +6 -16
  10. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm.egg-info/PKG-INFO +1 -1
  11. {pypdfform-1.4.22 → pypdfform-1.4.24}/LICENSE +0 -0
  12. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/adapter.py +0 -0
  13. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/coordinate.py +0 -0
  14. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/image.py +0 -0
  15. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/__init__.py +0 -0
  16. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/base.py +0 -0
  17. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/checkbox.py +0 -0
  18. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/dropdown.py +0 -0
  19. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/image.py +0 -0
  20. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/radio.py +0 -0
  21. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/signature.py +0 -0
  22. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/middleware/text.py +0 -0
  23. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/watermark.py +0 -0
  24. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/widgets/__init__.py +0 -0
  25. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/widgets/base.py +0 -0
  26. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/widgets/checkbox.py +0 -0
  27. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/widgets/text.py +1 -1
  28. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm/wrapper.py +0 -0
  29. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm.egg-info/SOURCES.txt +0 -0
  30. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  31. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm.egg-info/requires.txt +0 -0
  32. {pypdfform-1.4.22 → pypdfform-1.4.24}/PyPDFForm.egg-info/top_level.txt +0 -0
  33. {pypdfform-1.4.22 → pypdfform-1.4.24}/README.md +0 -0
  34. {pypdfform-1.4.22 → pypdfform-1.4.24}/setup.cfg +0 -0
  35. {pypdfform-1.4.22 → pypdfform-1.4.24}/setup.py +0 -0
  36. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_create_widget.py +0 -0
  37. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_dropdown.py +0 -0
  38. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_dropdown_simple.py +0 -0
  39. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_fill_max_length_text_field.py +0 -0
  40. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_fill_max_length_text_field_simple.py +0 -0
  41. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_functional.py +0 -0
  42. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_functional_simple.py +0 -0
  43. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_paragraph.py +0 -0
  44. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_paragraph_simple.py +0 -0
  45. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_preview.py +0 -0
  46. {pypdfform-1.4.22 → pypdfform-1.4.24}/tests/test_signature.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyPDFForm
3
- Version: 1.4.22
3
+ Version: 1.4.24
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains any object users might need."""
3
3
 
4
- __version__ = "1.4.22"
4
+ __version__ = "1.4.24"
5
5
 
6
6
  from .wrapper import FormWrapper, PdfWrapper, PyPDFForm
@@ -51,6 +51,7 @@ Opt = "/Opt"
51
51
  MK = "/MK"
52
52
  CA = "/CA"
53
53
  AS = "/AS"
54
+ Yes = "/Yes"
54
55
  Off = "/Off"
55
56
 
56
57
  # Field flag bits
@@ -78,3 +79,7 @@ BUTTON_STYLES = {
78
79
  }
79
80
 
80
81
  COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
82
+
83
+ # Used for adjusting paragraph font size
84
+ FONT_SIZE_REDUCE_STEP = 0.5
85
+ MARGIN_BETWEEN_LINES = 2
@@ -2,7 +2,7 @@
2
2
  """Contains helpers for filling a PDF form."""
3
3
 
4
4
  from io import BytesIO
5
- from typing import Dict, cast
5
+ from typing import Dict, Tuple, Union, cast
6
6
 
7
7
  from pypdf import PdfReader, PdfWriter
8
8
  from pypdf.generic import DictionaryObject
@@ -29,105 +29,133 @@ from .utils import checkbox_radio_to_draw, stream_to_io
29
29
  from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
30
30
 
31
31
 
32
+ def check_radio_handler(
33
+ widget: dict, middleware: Union[Checkbox, Radio], radio_button_tracker: dict
34
+ ) -> Tuple[Text, Union[float, int], Union[float, int], bool]:
35
+ """Handles draw parameters for checkbox and radio button widgets."""
36
+
37
+ font_size = (
38
+ checkbox_radio_font_size(widget) if middleware.size is None else middleware.size
39
+ )
40
+ to_draw = checkbox_radio_to_draw(middleware, font_size)
41
+ x, y = get_draw_checkbox_radio_coordinates(widget, to_draw)
42
+ text_needs_to_be_drawn = False
43
+ if type(middleware) is Checkbox and middleware.value:
44
+ text_needs_to_be_drawn = True
45
+ elif isinstance(middleware, Radio):
46
+ if middleware.name not in radio_button_tracker:
47
+ radio_button_tracker[middleware.name] = 0
48
+ radio_button_tracker[middleware.name] += 1
49
+ if middleware.value == radio_button_tracker[middleware.name] - 1:
50
+ text_needs_to_be_drawn = True
51
+
52
+ return to_draw, x, y, text_needs_to_be_drawn
53
+
54
+
55
+ def signature_image_handler(
56
+ widget: dict, middleware: Union[Signature, Image], images_to_draw: list
57
+ ) -> bool:
58
+ """Handles draw parameters for signature and image widgets."""
59
+
60
+ stream = middleware.stream
61
+ any_image_to_draw = False
62
+ if stream is not None:
63
+ any_image_to_draw = True
64
+ stream = any_image_to_jpg(stream)
65
+ x, y, width, height = get_draw_image_coordinates_resolutions(widget)
66
+ images_to_draw.append(
67
+ [
68
+ stream,
69
+ x,
70
+ y,
71
+ width,
72
+ height,
73
+ ]
74
+ )
75
+
76
+ return any_image_to_draw
77
+
78
+
79
+ def text_handler(
80
+ widget: dict, middleware: Text
81
+ ) -> Tuple[Text, Union[float, int], Union[float, int], bool]:
82
+ """Handles draw parameters for text field widgets."""
83
+
84
+ middleware.text_line_x_coordinates = get_text_line_x_coordinates(widget, middleware)
85
+ x, y = get_draw_text_coordinates(widget, middleware)
86
+ to_draw = middleware
87
+ text_needs_to_be_drawn = True
88
+
89
+ return to_draw, x, y, text_needs_to_be_drawn
90
+
91
+
92
+ def get_drawn_stream(to_draw: dict, stream: bytes, action: str) -> bytes:
93
+ """Generates a stream of an input PDF stream with stuff drawn on it."""
94
+
95
+ watermark_list = []
96
+ for page, stuffs in to_draw.items():
97
+ watermark_list.append(b"")
98
+ watermarks = create_watermarks_and_draw(stream, page, action, stuffs)
99
+ for i, watermark in enumerate(watermarks):
100
+ if watermark:
101
+ watermark_list[i] = watermark
102
+
103
+ return merge_watermarks_with_pdf(stream, watermark_list)
104
+
105
+
32
106
  def fill(
33
107
  template_stream: bytes,
34
108
  widgets: Dict[str, WIDGET_TYPES],
35
109
  ) -> bytes:
36
110
  """Fills a PDF using watermarks."""
37
111
 
38
- # pylint: disable=too-many-branches
39
112
  texts_to_draw = {}
40
113
  images_to_draw = {}
41
114
  any_image_to_draw = False
42
- text_watermarks = []
43
- image_watermarks = []
44
115
 
45
116
  radio_button_tracker = {}
46
117
 
47
- for page, _widgets in get_widgets_by_page(template_stream).items():
118
+ for page, widget_dicts in get_widgets_by_page(template_stream).items():
48
119
  texts_to_draw[page] = []
49
120
  images_to_draw[page] = []
50
- text_watermarks.append(b"")
51
- image_watermarks.append(b"")
52
- for _widget in _widgets:
53
- key = get_widget_key(_widget)
121
+ for widget_dict in widget_dicts:
122
+ key = get_widget_key(widget_dict)
54
123
  text_needs_to_be_drawn = False
55
- _to_draw = x = y = None
124
+ to_draw = x = y = None
56
125
 
57
126
  if isinstance(widgets[key], (Checkbox, Radio)):
58
- font_size = (
59
- checkbox_radio_font_size(_widget)
60
- if widgets[key].size is None
61
- else widgets[key].size
127
+ to_draw, x, y, text_needs_to_be_drawn = check_radio_handler(
128
+ widget_dict, widgets[key], radio_button_tracker
62
129
  )
63
- _to_draw = checkbox_radio_to_draw(widgets[key], font_size)
64
- x, y = get_draw_checkbox_radio_coordinates(_widget, _to_draw)
65
- if type(widgets[key]) is Checkbox and widgets[key].value:
66
- text_needs_to_be_drawn = True
67
- elif isinstance(widgets[key], Radio):
68
- if key not in radio_button_tracker:
69
- radio_button_tracker[key] = 0
70
- radio_button_tracker[key] += 1
71
- if widgets[key].value == radio_button_tracker[key] - 1:
72
- text_needs_to_be_drawn = True
73
130
  elif isinstance(widgets[key], (Signature, Image)):
74
- stream = widgets[key].stream
75
- if stream is not None:
76
- any_image_to_draw = True
77
- stream = any_image_to_jpg(stream)
78
- x, y, width, height = get_draw_image_coordinates_resolutions(
79
- _widget
80
- )
81
- images_to_draw[page].append(
82
- [
83
- stream,
84
- x,
85
- y,
86
- width,
87
- height,
88
- ]
89
- )
131
+ any_image_to_draw = signature_image_handler(
132
+ widget_dict, widgets[key], images_to_draw[page]
133
+ )
90
134
  else:
91
- widgets[key].text_line_x_coordinates = get_text_line_x_coordinates(
92
- _widget, widgets[key]
135
+ to_draw, x, y, text_needs_to_be_drawn = text_handler(
136
+ widget_dict, widgets[key]
93
137
  )
94
- x, y = get_draw_text_coordinates(_widget, widgets[key])
95
- _to_draw = widgets[key]
96
- text_needs_to_be_drawn = True
97
138
 
98
139
  if all(
99
140
  [
100
141
  text_needs_to_be_drawn,
101
- _to_draw is not None,
142
+ to_draw is not None,
102
143
  x is not None,
103
144
  y is not None,
104
145
  ]
105
146
  ):
106
147
  texts_to_draw[page].append(
107
148
  [
108
- _to_draw,
149
+ to_draw,
109
150
  x,
110
151
  y,
111
152
  ]
112
153
  )
113
154
 
114
- for page, texts in texts_to_draw.items():
115
- _watermarks = create_watermarks_and_draw(template_stream, page, "text", texts)
116
- for i, watermark in enumerate(_watermarks):
117
- if watermark:
118
- text_watermarks[i] = watermark
119
-
120
- result = merge_watermarks_with_pdf(template_stream, text_watermarks)
155
+ result = get_drawn_stream(texts_to_draw, template_stream, "text")
121
156
 
122
157
  if any_image_to_draw:
123
- for page, images in images_to_draw.items():
124
- _watermarks = create_watermarks_and_draw(
125
- template_stream, page, "image", images
126
- )
127
- for i, watermark in enumerate(_watermarks):
128
- if watermark:
129
- image_watermarks[i] = watermark
130
- result = merge_watermarks_with_pdf(result, image_watermarks)
158
+ result = get_drawn_stream(images_to_draw, result, "image")
131
159
 
132
160
  return result
133
161
 
@@ -33,21 +33,11 @@ def register_font(font_name: str, ttf_stream: bytes) -> bool:
33
33
  return result
34
34
 
35
35
 
36
- def auto_detect_font(widget: dict) -> str:
37
- """Returns the font of the text field if it is one of the standard fonts."""
38
-
39
- # pylint: disable=R0912
40
- result = DEFAULT_FONT
41
-
42
- text_appearance = None
43
- for pattern in TEXT_FIELD_APPEARANCE_PATTERNS:
44
- text_appearance = traverse_pattern(pattern, widget)
45
-
46
- if text_appearance:
47
- break
48
-
49
- if not text_appearance:
50
- return result
36
+ def extract_font_from_text_appearance(text_appearance: str) -> Union[str, None]:
37
+ """
38
+ Uses regex to pattern match out the font from the text
39
+ appearance string of a text field widget.
40
+ """
51
41
 
52
42
  text_appearance = text_appearance.split(" ")
53
43
 
@@ -73,7 +63,25 @@ def auto_detect_font(widget: dict) -> str:
73
63
  if found:
74
64
  return font
75
65
 
76
- return result
66
+ return None
67
+
68
+
69
+ def auto_detect_font(widget: dict) -> str:
70
+ """Returns the font of the text field if it is one of the standard fonts."""
71
+
72
+ result = DEFAULT_FONT
73
+
74
+ text_appearance = None
75
+ for pattern in TEXT_FIELD_APPEARANCE_PATTERNS:
76
+ text_appearance = traverse_pattern(pattern, widget)
77
+
78
+ if text_appearance:
79
+ break
80
+
81
+ if not text_appearance:
82
+ return result
83
+
84
+ return extract_font_from_text_appearance(text_appearance) or result
77
85
 
78
86
 
79
87
  def text_field_font_size(widget: dict) -> Union[float, int]:
@@ -6,7 +6,7 @@ from pypdf.generic import (DictionaryObject, NameObject, NumberObject,
6
6
 
7
7
  from .constants import (AP, AS, CA, DA, FT, IMAGE_FIELD_IDENTIFIER, JS, MK,
8
8
  READ_ONLY, A, Btn, Ch, D, Ff, Off, Opt, Parent, Q, Sig,
9
- Subtype, T, Tx, V, Widget)
9
+ Subtype, T, Tx, V, Widget, Yes)
10
10
  from .middleware.checkbox import Checkbox
11
11
  from .middleware.dropdown import Dropdown
12
12
  from .middleware.image import Image
@@ -28,7 +28,10 @@ WIDGET_TYPE_PATTERNS = [
28
28
  Text,
29
29
  ),
30
30
  (
31
- ({FT: Btn},),
31
+ (
32
+ {FT: Btn},
33
+ {AS: (Yes, Off)},
34
+ ),
32
35
  Checkbox,
33
36
  ),
34
37
  (
@@ -47,11 +50,15 @@ WIDGET_TYPE_PATTERNS = [
47
50
  (
48
51
  {Parent: {FT: Btn}},
49
52
  {Parent: {Subtype: Widget}},
53
+ {AS: (Yes, Off)},
50
54
  ),
51
55
  Checkbox,
52
56
  ),
53
57
  (
54
- ({Parent: {FT: Btn}},),
58
+ (
59
+ {Parent: {FT: Btn}},
60
+ {AS: (Yes, Off)},
61
+ ),
55
62
  Radio,
56
63
  ),
57
64
  ]
@@ -1,13 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains helpers for generic template related processing."""
3
3
 
4
+ from functools import lru_cache
4
5
  from sys import maxsize
5
6
  from typing import Dict, List, Tuple, Union
6
7
 
7
8
  from pypdf import PdfReader
8
9
  from reportlab.pdfbase.pdfmetrics import stringWidth
9
10
 
10
- from .constants import (COMB, DEFAULT_FONT_SIZE, MULTILINE, NEW_LINE_SYMBOL,
11
+ from .constants import (COMB, DEFAULT_FONT_SIZE, FONT_SIZE_REDUCE_STEP,
12
+ MARGIN_BETWEEN_LINES, MULTILINE, NEW_LINE_SYMBOL,
11
13
  WIDGET_TYPES, MaxLen, Rect)
12
14
  from .font import (auto_detect_font, get_text_field_font_color,
13
15
  get_text_field_font_size, text_field_font_size)
@@ -121,23 +123,30 @@ def update_text_field_attributes(
121
123
  key = get_widget_key(_widget)
122
124
 
123
125
  if isinstance(widgets[key], Text):
126
+ should_adjust_font_size = False
127
+ is_paragraph = is_text_multiline(_widget)
124
128
  if widgets[key].font is None:
125
129
  widgets[key].font = auto_detect_font(_widget)
126
130
  if widgets[key].font_size is None:
127
- widgets[key].font_size = get_text_field_font_size(_widget) or (
131
+ template_font_size = get_text_field_font_size(_widget)
132
+ widgets[key].font_size = template_font_size or (
128
133
  text_field_font_size(_widget)
129
- if not is_text_multiline(_widget)
134
+ if not is_paragraph
130
135
  else DEFAULT_FONT_SIZE
131
136
  )
137
+ should_adjust_font_size = is_paragraph and not template_font_size
132
138
  if widgets[key].font_color is None:
133
139
  widgets[key].font_color = get_text_field_font_color(_widget)
134
- if is_text_multiline(_widget) and widgets[key].text_wrap_length is None:
140
+ if is_paragraph and widgets[key].text_wrap_length is None:
135
141
  widgets[key].text_lines = get_paragraph_lines(_widget, widgets[key])
136
142
  widgets[key].text_wrap_length = get_paragraph_auto_wrap_length(
137
143
  widgets[key]
138
144
  )
145
+ if widgets[key].value and should_adjust_font_size:
146
+ adjust_paragraph_font_size(_widget, widgets[key])
139
147
 
140
148
 
149
+ @lru_cache()
141
150
  def get_widgets_by_page(pdf: bytes) -> Dict[int, List[dict]]:
142
151
  """Iterates through a PDF and returns all widgets found grouped by page."""
143
152
 
@@ -288,28 +297,23 @@ def get_character_x_paddings(widget: dict, widget_middleware: Text) -> List[floa
288
297
  return result
289
298
 
290
299
 
291
- def get_paragraph_lines(widget: dict, widget_middleware: Text) -> List[str]:
292
- """Splits the paragraph field's text to a list of lines."""
300
+ def split_characters_into_lines(
301
+ split_by_new_line_symbol: List[str], middleware: Text, width: float
302
+ ) -> List[str]:
303
+ """
304
+ Given a long string meant to be filled for a paragraph widget
305
+ split by the new line symbol already, splits it further into lines
306
+ where each line would fit into the widget's width.
307
+ """
293
308
 
294
- # pylint: disable=R0912
295
309
  lines = []
296
- result = []
297
- value = widget_middleware.value or ""
298
- if widget_middleware.max_length is not None:
299
- value = value[: widget_middleware.max_length]
300
-
301
- width = abs(float(widget[Rect][0]) - float(widget[Rect][2]))
302
-
303
- split_by_new_line_symbol = value.split(NEW_LINE_SYMBOL)
304
310
  for line in split_by_new_line_symbol:
305
311
  characters = line.split(" ")
306
312
  current_line = ""
307
313
  for each in characters:
308
314
  line_extended = f"{current_line} {each}" if current_line else each
309
315
  if (
310
- stringWidth(
311
- line_extended, widget_middleware.font, widget_middleware.font_size
312
- )
316
+ stringWidth(line_extended, middleware.font, middleware.font_size)
313
317
  <= width
314
318
  ):
315
319
  current_line = line_extended
@@ -322,14 +326,23 @@ def get_paragraph_lines(widget: dict, widget_middleware: Text) -> List[str]:
322
326
  else current_line
323
327
  )
324
328
 
329
+ return lines
330
+
331
+
332
+ def adjust_each_line(lines: List[str], middleware: Text, width: float) -> List[str]:
333
+ """
334
+ Given a list of strings which is the return value of
335
+ `split_characters_into_lines`, further adjusts each line
336
+ so that there is neither overflow nor over-splitting into
337
+ unnecessary lines.
338
+ """
339
+
340
+ result = []
325
341
  for each in lines:
326
342
  tracker = ""
327
343
  for char in each:
328
344
  check = tracker + char
329
- if (
330
- stringWidth(check, widget_middleware.font, widget_middleware.font_size)
331
- > width
332
- ):
345
+ if stringWidth(check, middleware.font, middleware.font_size) > width:
333
346
  result.append(tracker)
334
347
  tracker = char
335
348
  else:
@@ -341,8 +354,8 @@ def get_paragraph_lines(widget: dict, widget_middleware: Text) -> List[str]:
341
354
  result
342
355
  and stringWidth(
343
356
  f"{each} {result[-1]}",
344
- widget_middleware.font,
345
- widget_middleware.font_size,
357
+ middleware.font,
358
+ middleware.font_size,
346
359
  )
347
360
  <= width
348
361
  and NEW_LINE_SYMBOL not in result[-1]
@@ -360,6 +373,23 @@ def get_paragraph_lines(widget: dict, widget_middleware: Text) -> List[str]:
360
373
  return result
361
374
 
362
375
 
376
+ def get_paragraph_lines(widget: dict, widget_middleware: Text) -> List[str]:
377
+ """Splits the paragraph field's text to a list of lines."""
378
+
379
+ value = widget_middleware.value or ""
380
+ if widget_middleware.max_length is not None:
381
+ value = value[: widget_middleware.max_length]
382
+
383
+ width = abs(float(widget[Rect][0]) - float(widget[Rect][2]))
384
+
385
+ split_by_new_line_symbol = value.split(NEW_LINE_SYMBOL)
386
+ lines = split_characters_into_lines(
387
+ split_by_new_line_symbol, widget_middleware, width
388
+ )
389
+
390
+ return adjust_each_line(lines, widget_middleware, width)
391
+
392
+
363
393
  def get_paragraph_auto_wrap_length(widget_middleware: Text) -> int:
364
394
  """Calculates the text wrap length of a paragraph field."""
365
395
 
@@ -368,3 +398,18 @@ def get_paragraph_auto_wrap_length(widget_middleware: Text) -> int:
368
398
  result = min(result, len(line))
369
399
 
370
400
  return result
401
+
402
+
403
+ def adjust_paragraph_font_size(widget: dict, widget_middleware: Text) -> None:
404
+ """Reduces the font size of a paragraph field until texts fits."""
405
+
406
+ height = abs(float(widget[Rect][1]) - float(widget[Rect][3]))
407
+
408
+ while (
409
+ widget_middleware.font_size > FONT_SIZE_REDUCE_STEP
410
+ and len(widget_middleware.text_lines)
411
+ * (widget_middleware.font_size + MARGIN_BETWEEN_LINES)
412
+ > height
413
+ ):
414
+ widget_middleware.font_size -= FONT_SIZE_REDUCE_STEP
415
+ widget_middleware.text_lines = get_paragraph_lines(widget, widget_middleware)
@@ -122,7 +122,10 @@ def find_pattern_match(pattern: dict, widget: Union[dict, DictionaryObject]) ->
122
122
  ):
123
123
  result = find_pattern_match(pattern[key], value)
124
124
  else:
125
- result = pattern[key] == value
125
+ if isinstance(pattern[key], tuple):
126
+ result = value in pattern[key]
127
+ else:
128
+ result = pattern[key] == value
126
129
  if result:
127
130
  return result
128
131
  return False
@@ -1,26 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains dropdown widget to create."""
3
3
 
4
- from .base import Widget
4
+ from .text import TextWidget
5
5
 
6
6
 
7
- class DropdownWidget(Widget):
7
+ class DropdownWidget(TextWidget):
8
8
  """Dropdown widget to create."""
9
9
 
10
- # pylint: disable=R0801
11
-
12
- USER_PARAMS = [
13
- ("width", "width"),
14
- ("height", "height"),
15
- ("options", "options"),
16
- ("font", "fontName"),
17
- ("font_size", "fontSize"),
18
- ("font_color", "textColor"),
19
- ("bg_color", "fillColor"),
20
- ("border_color", "borderColor"),
21
- ("border_width", "borderWidth"),
22
- ]
23
- COLOR_PARAMS = ["font_color", "bg_color", "border_color"]
10
+ NONE_DEFAULTS = []
24
11
  ACRO_FORM_FUNC = "_textfield"
25
12
 
26
13
  def __init__(
@@ -33,6 +20,9 @@ class DropdownWidget(Widget):
33
20
  ) -> None:
34
21
  """Sets acro form parameters."""
35
22
 
23
+ self.USER_PARAMS = super().USER_PARAMS[:-1] + [
24
+ ("options", "options"),
25
+ ]
36
26
  super().__init__(name, page_number, x, y, **kwargs)
37
27
  self.acro_form_params["wkind"] = "choice"
38
28
  self.acro_form_params["value"] = self.acro_form_params["options"][0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyPDFForm
3
- Version: 1.4.22
3
+ Version: 1.4.24
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
File without changes
@@ -10,13 +10,13 @@ class TextWidget(Widget):
10
10
  USER_PARAMS = [
11
11
  ("width", "width"),
12
12
  ("height", "height"),
13
- ("max_length", "maxlen"),
14
13
  ("font", "fontName"),
15
14
  ("font_size", "fontSize"),
16
15
  ("font_color", "textColor"),
17
16
  ("bg_color", "fillColor"),
18
17
  ("border_color", "borderColor"),
19
18
  ("border_width", "borderWidth"),
19
+ ("max_length", "maxlen"),
20
20
  ]
21
21
  COLOR_PARAMS = ["font_color", "bg_color", "border_color"]
22
22
  NONE_DEFAULTS = ["max_length"]
File without changes
File without changes
File without changes