PyPDFForm 2.4.0__py3-none-any.whl → 3.0.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
@@ -1,12 +1,28 @@
1
1
  # -*- coding: utf-8 -*-
2
- """PyPDFForm package for PDF form filling and manipulation.
2
+ """
3
+ PyPDFForm is a pure Python library designed to streamline the process of filling PDF forms programmatically.
4
+
5
+ It provides a simple and intuitive API for interacting with PDF forms, allowing users to:
6
+
7
+ - Fill text fields with custom data.
8
+ - Check or uncheck checkboxes.
9
+ - Select radio button options.
10
+ - Add images to image fields.
11
+ - Flatten the filled form to prevent further modifications.
12
+
13
+ The library supports various PDF form features, including:
14
+
15
+ - Text field alignment (left, center, right).
16
+ - Font customization (size, color, family).
17
+ - Image field resizing and positioning.
18
+ - Handling of complex form structures.
3
19
 
4
- This package provides tools for filling PDF forms, drawing text and images,
5
- and manipulating PDF form elements programmatically.
20
+ PyPDFForm aims to simplify PDF form manipulation, making it accessible to developers of all skill levels.
6
21
  """
7
22
 
8
- __version__ = "2.4.0"
23
+ __version__ = "3.0.0"
9
24
 
10
- from .wrapper import FormWrapper, PdfWrapper
25
+ from .middleware.text import Text # exposing for setting global font attrs
26
+ from .wrapper import PdfWrapper
11
27
 
12
- __all__ = ["FormWrapper", "PdfWrapper"]
28
+ __all__ = ["PdfWrapper", "Text"]
PyPDFForm/adapter.py CHANGED
@@ -1,13 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Provides adapters for handling different types of file inputs.
3
-
4
- This module contains utility functions for working with various file input types:
5
- - Raw bytes
6
- - File paths
7
- - File-like objects
8
-
9
- The adapters normalize these different input types into consistent byte streams
10
- that can be processed by the PDF manipulation functions.
2
+ """
3
+ Module for adapting different types of input to a consistent byte stream.
4
+
5
+ This module provides utility functions to adapt various types of input,
6
+ such as file paths, file-like objects, and byte streams, into a consistent
7
+ byte stream format. This is particularly useful when dealing with PDF form
8
+ filling operations, where the input PDF template can be provided in different
9
+ forms. The module ensures that the input is properly converted into a byte
10
+ stream before further processing.
11
11
  """
12
12
 
13
13
  from os.path import isfile
@@ -15,41 +15,43 @@ from typing import Any, BinaryIO, Union
15
15
 
16
16
 
17
17
  def readable(obj: Any) -> bool:
18
- """Determines if an object is file-like and readable.
18
+ """
19
+ Check if an object has a readable "read" attribute.
19
20
 
20
- Checks if the object has a callable read() method, indicating it can be
21
- treated as a file-like object for reading operations.
21
+ This function determines whether the provided object has a "read" attribute that is callable.
22
+ It is used to identify file-like objects or streams that can be read from.
22
23
 
23
24
  Args:
24
- obj: The object to check for read capability
25
+ obj (Any): The object to check for a readable "read" attribute.
25
26
 
26
27
  Returns:
27
- bool: True if the object has a callable read() method, False otherwise
28
+ bool: True if the object has a callable "read" attribute, indicating it is readable.
29
+ Returns False otherwise.
28
30
  """
29
-
30
31
  return callable(getattr(obj, "read", None))
31
32
 
32
33
 
33
34
  def fp_or_f_obj_or_stream_to_stream(
34
35
  fp_or_f_obj_or_stream: Union[bytes, str, BinaryIO],
35
36
  ) -> bytes:
36
- """Converts various file input types to a byte stream.
37
+ """
38
+ Adapt a file path, file object, or stream to a byte stream.
37
39
 
38
- Handles conversion of:
39
- - Raw bytes (passed through unchanged)
40
- - File paths (reads file contents)
41
- - File-like objects (reads using read() method)
40
+ This function takes a file path, a file object, or a byte stream and adapts it to a consistent byte stream.
41
+ It handles different input types, including:
42
+ - byte streams (bytes)
43
+ - file paths (str)
44
+ - file-like objects with a read() method (BinaryIO)
42
45
 
43
46
  Args:
44
- fp_or_f_obj_or_stream: Input to convert, which can be:
45
- - bytes: Raw PDF data
46
- - str: Path to PDF file
47
- - BinaryIO: File-like object containing PDF data
47
+ fp_or_f_obj_or_stream (Union[bytes, str, BinaryIO]): The input to adapt.
48
+ It can be a byte stream, a file path (string), or a file object.
48
49
 
49
50
  Returns:
50
- bytes: The PDF data as a byte stream
51
+ bytes: The byte stream representation of the input.
52
+ Returns an empty byte string if the file path does not exist.
51
53
  """
52
-
54
+ # not cached to handle writing to the same disk file
53
55
  result = b""
54
56
  if isinstance(fp_or_f_obj_or_stream, bytes):
55
57
  result = fp_or_f_obj_or_stream
PyPDFForm/constants.py CHANGED
@@ -1,15 +1,18 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Centralized location for all PyPDFForm constants and default values.
2
+ """
3
+ Module containing constants used throughout the PyPDFForm library.
4
+
5
+ This module defines a collection of constants that are used across various
6
+ modules within the PyPDFForm library. These constants include:
3
7
 
4
- This module defines all the constants used throughout the package including:
5
- - PDF version identifiers and format strings
6
- - PDF field type and property constants
7
- - Default values for fonts, colors and sizes
8
- - Special identifiers and symbols
9
- - Field flag bitmasks
10
- - Button style definitions
8
+ - String identifiers for PDF syntax elements (e.g., /Annots, /Rect, /FT).
9
+ - Numerical values representing field flags (e.g., READ_ONLY, MULTILINE).
10
+ - Default values for fonts, font sizes, and font colors.
11
+ - Identifiers for image fields and coordinate grid calculations.
12
+ - Version identifiers for PDF versions.
11
13
 
12
- All constants are organized by category and used consistently across the package.
14
+ Using constants improves code readability and maintainability by providing
15
+ meaningful names for frequently used values and reducing the risk of typos.
13
16
  """
14
17
 
15
18
  from typing import Union
@@ -54,25 +57,33 @@ I = "/I" # noqa: E741
54
57
  N = "/N"
55
58
  Sig = "/Sig"
56
59
  DA = "/DA"
60
+ DR = "/DR"
57
61
  DV = "/DV"
58
62
  Btn = "/Btn"
59
63
  MaxLen = "/MaxLen"
60
64
  Q = "/Q"
61
65
  Ch = "/Ch"
62
66
  Opt = "/Opt"
63
- MK = "/MK"
64
- CA = "/CA"
65
- BC = "/BC"
66
- BG = "/BG"
67
- BS = "/BS"
68
- W = "/W"
69
- S = "/S"
70
- D = "/D"
71
- U = "/U"
72
67
  AS = "/AS"
73
68
  Yes = "/Yes"
74
69
  Off = "/Off"
75
70
 
71
+ # Font dict
72
+ Length1 = "/Length1"
73
+ Type = "/Type"
74
+ FontDescriptor = "/FontDescriptor"
75
+ FontName = "/FontName"
76
+ FontFile2 = "/FontFile2"
77
+ Font = "/Font"
78
+ Subtype = "/Subtype"
79
+ TrueType = "/TrueType"
80
+ BaseFont = "/BaseFont"
81
+ Encoding = "/Encoding"
82
+ WinAnsiEncoding = "/WinAnsiEncoding"
83
+
84
+ Resources = "/Resources"
85
+ FONT_NAME_PREFIX = "/F"
86
+
76
87
  # For Adobe Acrobat
77
88
  AcroForm = "/AcroForm"
78
89
  Root = "/Root"
@@ -86,27 +97,11 @@ COMB = 1 << 24
86
97
 
87
98
  FONT_SIZE_IDENTIFIER = "Tf"
88
99
  FONT_COLOR_IDENTIFIER = " rg"
89
- DEFAULT_BORDER_WIDTH = 1
90
100
  DEFAULT_FONT = "Helvetica"
91
101
  DEFAULT_FONT_SIZE = 12
92
102
  DEFAULT_FONT_COLOR = (0, 0, 0)
93
- PREVIEW_FONT_COLOR = (1, 0, 0)
94
-
95
- NEW_LINE_SYMBOL = "\n"
96
103
 
97
104
  IMAGE_FIELD_IDENTIFIER = "event.target.buttonImportIcon();"
98
105
 
99
- DEFAULT_CHECKBOX_STYLE = "\u2713"
100
- DEFAULT_RADIO_STYLE = "\u25cf"
101
- BUTTON_STYLES = {
102
- "4": "\u2713", # check
103
- "5": "\u00d7", # cross
104
- "l": "\u25cf", # circle
105
- }
106
-
107
106
  COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
108
107
  UNIQUE_SUFFIX_LENGTH = 20
109
-
110
- # Used for adjusting paragraph font size
111
- FONT_SIZE_REDUCE_STEP = 0.5
112
- MARGIN_BETWEEN_LINES = 2
PyPDFForm/coordinate.py CHANGED
@@ -1,412 +1,44 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Provides coordinate calculation utilities for PDF form elements.
3
-
4
- This module contains functions for calculating positions and dimensions
5
- for drawing various PDF form elements including:
6
- - Text fields and paragraphs
7
- - Checkboxes and radio buttons
8
- - Images and signatures
9
- - Borders and decorative elements
2
+ """
3
+ Module for generating coordinate grids on PDFs.
10
4
 
11
- All calculations work in PDF coordinate space where:
12
- - Origin (0,0) is at bottom-left corner
13
- - Units are in PDF points (1/72 inch)
5
+ This module provides functionality to generate coordinate grids on existing PDF documents.
6
+ It allows developers to visualize the coordinate system of each page in a PDF, which can be helpful
7
+ for debugging and precisely positioning elements when filling or drawing on PDF forms.
14
8
  """
15
9
 
16
- from copy import deepcopy
17
- from typing import List, Tuple, Union
10
+ from typing import Tuple
18
11
 
19
12
  from pypdf import PdfReader
20
13
  from reportlab.pdfbase.pdfmetrics import stringWidth
21
14
 
22
- from .constants import (COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO, DEFAULT_FONT,
23
- Rect)
15
+ from .constants import COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO, DEFAULT_FONT
24
16
  from .middleware.text import Text
25
- from .patterns import WIDGET_ALIGNMENT_PATTERNS
26
- from .template import get_char_rect_width, is_text_multiline
27
- from .utils import extract_widget_property, handle_color, stream_to_io
17
+ from .utils import stream_to_io
28
18
  from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
29
19
 
30
20
 
31
- def get_draw_border_coordinates(widget: dict, shape: str) -> dict:
32
- """Calculates coordinates for drawing widget borders in PDF coordinate space.
33
-
34
- Args:
35
- widget: PDF form widget dictionary containing Rect coordinates (in PDF points)
36
- shape: Type of border to draw:
37
- - "rect": Standard rectangular border
38
- - "ellipse": Circular/oval border
39
- - "line": Straight line border
40
-
41
- Returns:
42
- dict: Coordinate dictionary with different keys depending on shape:
43
- - For "rect":
44
- {
45
- "x": bottom-left x,
46
- "y": bottom-left y,
47
- "width": total width,
48
- "height": total height
49
- }
50
- - For "ellipse":
51
- {
52
- "x1": left bound,
53
- "y1": bottom bound,
54
- "x2": right bound,
55
- "y2": top bound
56
- }
57
- - For "line":
58
- {
59
- "src_x": start x,
60
- "src_y": start y,
61
- "dest_x": end x,
62
- "dest_y": end y
63
- }
64
-
65
- Note:
66
- All coordinates are in PDF points (1/72 inch) with origin (0,0) at bottom-left.
67
- For ellipses, the bounds form a square that would contain the ellipse.
68
- """
69
-
70
- result = {
71
- "x": float(widget[Rect][0]),
72
- "y": float(widget[Rect][1]),
73
- "width": abs(float(widget[Rect][0]) - float(widget[Rect][2])),
74
- "height": abs(float(widget[Rect][1]) - float(widget[Rect][3])),
75
- }
76
-
77
- if shape == "ellipse":
78
- width = abs(float(widget[Rect][0]) - float(widget[Rect][2]))
79
- height = abs(float(widget[Rect][1]) - float(widget[Rect][3]))
80
-
81
- width_mid = (float(widget[Rect][0]) + float(widget[Rect][2])) / 2
82
- height_mid = (float(widget[Rect][1]) + float(widget[Rect][3])) / 2
83
-
84
- less = min(width, height)
85
-
86
- result = {
87
- "x1": width_mid - less / 2,
88
- "y1": height_mid - less / 2,
89
- "x2": width_mid + less / 2,
90
- "y2": height_mid + less / 2,
91
- }
92
- elif shape == "line":
93
- result = {
94
- "src_x": float(widget[Rect][0]),
95
- "src_y": float(widget[Rect][1]),
96
- "dest_x": float(widget[Rect][2]),
97
- "dest_y": float(widget[Rect][1]),
98
- }
99
-
100
- return result
101
-
102
-
103
- def get_draw_checkbox_radio_coordinates(
104
- widget: dict,
105
- widget_middleware: Text,
106
- border_width: int,
107
- ) -> Tuple[Union[float, int], Union[float, int]]:
108
- """Calculates drawing coordinates for checkbox/radio button symbols.
109
-
110
- Args:
111
- widget: PDF form widget dictionary containing Rect coordinates
112
- widget_middleware: Text middleware containing font properties
113
- border_width: Width of widget border in points
114
-
115
- Returns:
116
- Tuple[Union[float, int], Union[float, int]]: (x, y) coordinates
117
- for drawing the checkbox/radio symbol
118
- """
119
-
120
- string_height = widget_middleware.font_size * 72 / 96
121
- width_mid_point = (float(widget[Rect][0]) + float(widget[Rect][2])) / 2
122
- half_widget_height = abs(float(widget[Rect][1]) - float(widget[Rect][3])) / 2
123
-
124
- return (
125
- width_mid_point
126
- - stringWidth(
127
- widget_middleware.value,
128
- widget_middleware.font,
129
- widget_middleware.font_size,
130
- )
131
- / 2,
132
- float(widget[Rect][1])
133
- + (half_widget_height - string_height / 2)
134
- + border_width / 2,
135
- )
136
-
137
-
138
- def get_draw_image_coordinates_resolutions(
139
- widget: dict,
140
- preserve_aspect_ratio: bool,
141
- image_width: float,
142
- image_height: float,
143
- ) -> Tuple[float, float, float, float]:
144
- """Calculates image drawing coordinates and scaling factors.
145
-
146
- Args:
147
- widget: PDF form widget dictionary containing Rect coordinates
148
- preserve_aspect_ratio: Whether to maintain image proportions
149
- image_width: Original width of the image in points
150
- image_height: Original height of the image in points
151
-
152
- Returns:
153
- Tuple[float, float, float, float]: (x, y, width, height) where:
154
- x,y: Bottom-left corner coordinates
155
- width,height: Scaled dimensions for drawing
156
- """
157
-
158
- x = float(widget[Rect][0])
159
- y = float(widget[Rect][1])
160
- width = abs(float(widget[Rect][0]) - float(widget[Rect][2]))
161
- height = abs(float(widget[Rect][1]) - float(widget[Rect][3]))
162
-
163
- if preserve_aspect_ratio:
164
- ratio = max(image_width / width, image_height / height)
165
-
166
- new_width = image_width / ratio
167
- new_height = image_height / ratio
168
-
169
- x += abs(new_width - width) / 2
170
- y += abs(new_height - height) / 2
171
-
172
- width = new_width
173
- height = new_height
174
-
175
- return x, y, width, height
176
-
177
-
178
- def calculate_text_coord_x(
179
- widget: dict,
180
- widget_middleware: Text,
181
- text_value: str,
182
- length: int,
183
- character_paddings: List[float],
184
- ) -> float:
185
- """
186
- Calculate the horizontal (x) coordinate for text drawing within a PDF form field.
187
-
188
- This function determines the x-coordinate based on:
189
- - The widget's alignment setting (left, center, right)
190
- - Whether the field uses comb formatting
191
- - The width of the text string
192
- - Character paddings for comb fields
193
-
194
- Args:
195
- widget: PDF form widget dictionary containing Rect and alignment info.
196
- widget_middleware: Text middleware containing font and comb properties.
197
- text_value: The text string to be drawn (already trimmed).
198
- length: The length of the text string.
199
- character_paddings: List of cumulative paddings for comb characters.
200
-
201
- Returns:
202
- float: The calculated x-coordinate for the text baseline start.
203
- """
204
-
205
- alignment = (
206
- extract_widget_property(widget, WIDGET_ALIGNMENT_PATTERNS, None, int) or 0
207
- )
208
- # Default to left boundary
209
- x = float(widget[Rect][0])
210
-
211
- if int(alignment) == 0:
212
- return x
213
-
214
- # Calculate the horizontal midpoint of the widget rectangle
215
- width_mid_point = (float(widget[Rect][0]) + float(widget[Rect][2])) / 2
216
-
217
- # Calculate the width of the entire string in points
218
- string_width = stringWidth(
219
- text_value,
220
- widget_middleware.font,
221
- widget_middleware.font_size,
222
- )
223
-
224
- # If comb formatting, adjust string width to include last character's right padding
225
- if widget_middleware.comb is True and length:
226
- string_width = character_paddings[-1] + stringWidth(
227
- text_value[-1],
228
- widget_middleware.font,
229
- widget_middleware.font_size,
230
- )
231
-
232
- if int(alignment) == 1: # Center alignment
233
- # Center text by offsetting half the string width from the midpoint
234
- x = width_mid_point - string_width / 2
235
- elif int(alignment) == 2: # Right alignment
236
- # Align text to the right edge minus the string width
237
- x = float(widget[Rect][2]) - string_width
238
- if length > 0 and widget_middleware.comb is True:
239
- # For comb fields, adjust further by half the difference between comb box width and last character width
240
- x -= (
241
- get_char_rect_width(widget, widget_middleware)
242
- - stringWidth(
243
- text_value[-1],
244
- widget_middleware.font,
245
- widget_middleware.font_size,
246
- )
247
- ) / 2
248
-
249
- # Additional comb adjustment for center alignment
250
- if int(alignment) == 1 and widget_middleware.comb is True and length != 0:
251
- # Shift left by half the first character's padding
252
- x -= character_paddings[0] / 2
253
- if length % 2 == 0:
254
- # For even-length comb text, shift further left by half the first char width plus padding
255
- x -= (
256
- character_paddings[0]
257
- + stringWidth(
258
- text_value[:1],
259
- widget_middleware.font,
260
- widget_middleware.font_size,
261
- )
262
- / 2
263
- )
264
-
265
- return x
266
-
267
-
268
- def calculate_text_coord_y(widget: dict, widget_middleware: Text) -> float:
269
- """
270
- Calculate the vertical (y) coordinate for text drawing within a PDF form field.
271
-
272
- This function determines the y-coordinate based on:
273
- - The widget's rectangle height
274
- - The font size
275
- - Whether the field is multiline (which shifts text closer to the top)
276
-
277
- Args:
278
- widget: PDF form widget dictionary containing Rect info.
279
- widget_middleware: Text middleware containing font size and multiline info.
280
-
281
- Returns:
282
- float: The calculated y-coordinate for the text baseline.
283
- """
284
-
285
- # Convert font size to PDF points (font size is in pixels, 96 dpi to 72 dpi)
286
- string_height = widget_middleware.font_size * 96 / 72
287
-
288
- # Calculate vertical midpoint of the widget rectangle
289
- height_mid_point = (float(widget[Rect][1]) + float(widget[Rect][3])) / 2
290
-
291
- # Default y: vertically center the text baseline within the widget
292
- # This formula centers the text height around the vertical midpoint
293
- y = (height_mid_point - string_height / 2 + height_mid_point) / 2
294
-
295
- # If multiline, position baseline closer to the top edge for better appearance
296
- if is_text_multiline(widget):
297
- y = float(widget[Rect][3]) - string_height / 1.5
298
-
299
- return y
300
-
301
-
302
- def get_draw_text_coordinates(
303
- widget: dict, widget_middleware: Text
304
- ) -> Tuple[Union[float, int], Union[float, int]]:
305
- """
306
- Calculate the (x, y) coordinates for drawing text within a PDF form field.
307
-
308
- This function determines the starting position for rendering text,
309
- taking into account:
310
- - Preview mode (which offsets text above the field)
311
- - Text length and wrapping
312
- - Alignment (left, center, right)
313
- - Comb formatting and character paddings
314
- - Multiline adjustments for vertical position
315
-
316
- Args:
317
- widget: PDF form widget dictionary containing Rect and alignment info.
318
- widget_middleware: Text middleware containing font, comb, and text properties.
319
-
320
- Returns:
321
- Tuple[Union[float, int], Union[float, int]]: The (x, y) coordinates
322
- for the text baseline starting point.
323
- """
324
-
325
- # If preview mode, draw slightly above the top boundary for visibility
326
- if widget_middleware.preview:
327
- return (
328
- float(widget[Rect][0]),
329
- float(widget[Rect][3]) + 5,
330
- )
331
-
332
- # Prepare text value, respecting max length
333
- text_value = widget_middleware.value or ""
334
- length = (
335
- min(len(text_value), widget_middleware.max_length)
336
- if widget_middleware.max_length is not None
337
- else len(text_value)
338
- )
339
- text_value = text_value[:length]
340
-
341
- # Further trim text if wrapping is enabled
342
- if widget_middleware.text_wrap_length is not None:
343
- text_value = text_value[: widget_middleware.text_wrap_length]
344
-
345
- # Prepare character paddings for comb fields
346
- character_paddings = (
347
- widget_middleware.character_paddings[:length]
348
- if widget_middleware.character_paddings is not None
349
- else widget_middleware.character_paddings
350
- )
351
-
352
- # Calculate horizontal position based on alignment and comb settings
353
- x = calculate_text_coord_x(
354
- widget, widget_middleware, text_value, length, character_paddings
355
- )
356
-
357
- # Calculate vertical position based on font size and multiline
358
- y = calculate_text_coord_y(widget, widget_middleware)
359
-
360
- return x, y
361
-
362
-
363
- def get_text_line_x_coordinates(
364
- widget: dict, widget_middleware: Text
365
- ) -> Union[List[float], None]:
366
- """Calculates x-coordinates for each line in a multiline text field.
367
-
368
- Args:
369
- widget: PDF form widget dictionary
370
- widget_middleware: Text middleware with text_lines property
371
-
372
- Returns:
373
- Union[List[float], None]: List of x-coordinates for each text line,
374
- or None if not a multiline field
375
- """
376
-
377
- if (
378
- widget_middleware.text_wrap_length is not None
379
- and widget_middleware.text_lines is not None
380
- and len(widget_middleware.text_lines)
381
- and isinstance(widget_middleware.value, str)
382
- and len(widget_middleware.value) > widget_middleware.text_wrap_length
383
- ):
384
- result = []
385
- _widget = deepcopy(widget_middleware)
386
- for each in widget_middleware.text_lines:
387
- _widget.value = each
388
- _widget.text_wrap_length = None
389
- result.append(get_draw_text_coordinates(widget, _widget)[0])
390
-
391
- return result
392
-
393
- return None
394
-
395
-
396
21
  def generate_coordinate_grid(
397
22
  pdf: bytes, color: Tuple[float, float, float], margin: float
398
23
  ) -> bytes:
399
- """Generates a coordinate grid overlay for a PDF document.
24
+ """
25
+ Generates a coordinate grid overlay on a PDF document.
26
+
27
+ This function takes a PDF file as bytes, along with a color and margin, and generates
28
+ a coordinate grid on each page of the PDF. The grid consists of lines and text indicating
29
+ the X and Y coordinates. This can be useful for visualizing the layout and positioning
30
+ elements on the PDF.
400
31
 
401
32
  Args:
402
- pdf: Input PDF document as bytes
403
- color: RGB tuple (0-1 range) for grid line color
404
- margin: Spacing between grid lines in PDF points
33
+ pdf (bytes): The PDF file as bytes.
34
+ color (Tuple[float, float, float]): The color of the grid lines and text as a tuple of RGB values (0.0-1.0).
35
+ For example, (0.0, 0.0, 0.0) represents black.
36
+ margin (float): The margin between the grid lines and the edge of the page, in points.
37
+ This value determines the spacing of the grid.
405
38
 
406
39
  Returns:
407
- bytes: New PDF with grid overlay as byte stream
40
+ bytes: The PDF file with the coordinate grid overlay as bytes.
408
41
  """
409
-
410
42
  pdf_file = PdfReader(stream_to_io(pdf))
411
43
  lines_by_page = {}
412
44
  texts_by_page = {}
@@ -418,8 +50,6 @@ def generate_coordinate_grid(
418
50
  width = float(page.mediabox[2])
419
51
  height = float(page.mediabox[3])
420
52
 
421
- r, g, b = color
422
-
423
53
  current = margin
424
54
  while current < width:
425
55
  lines_by_page[i + 1].append(
@@ -428,10 +58,7 @@ def generate_coordinate_grid(
428
58
  "src_y": 0,
429
59
  "dest_x": current,
430
60
  "dest_y": height,
431
- "border_color": handle_color([r, g, b]),
432
- "background_color": None,
433
- "border_width": 1,
434
- "dash_array": None,
61
+ "color": color,
435
62
  }
436
63
  )
437
64
  current += margin
@@ -444,10 +71,7 @@ def generate_coordinate_grid(
444
71
  "src_y": current,
445
72
  "dest_x": width,
446
73
  "dest_y": current,
447
- "border_color": handle_color([r, g, b]),
448
- "background_color": None,
449
- "border_width": 1,
450
- "dash_array": None,
74
+ "color": color,
451
75
  }
452
76
  )
453
77
  current += margin