Skip to content

Commit cf2b174

Browse files
committed
ENH: _appearance_stream: Use kwargs instead of long argument lists
1 parent bada5da commit cf2b174

File tree

1 file changed

+62
-66
lines changed

1 file changed

+62
-66
lines changed

pypdf/generic/_appearance_stream.py

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,7 @@ def _generate_appearance_stream_data(
139139
text: str = "",
140140
selection: Optional[list[str]] = None,
141141
rectangle: Union[RectangleObject, tuple[float, float, float, float]] = (0.0, 0.0, 0.0, 0.0),
142-
font_descriptor: Optional[FontDescriptor] = None,
143-
font_glyph_byte_map: Optional[dict[str, bytes]] = None,
144-
font_name: str = "/Helv",
145-
font_size: float = 0.0,
146-
font_color: str = "0 g",
147-
is_multiline: bool = False,
148-
alignment: TextAlignment = TextAlignment.LEFT,
149-
is_comb: bool = False,
150-
max_length: Optional[int] = None
142+
**formatting_kwargs: Any
151143
) -> bytes:
152144
"""
153145
Generates the raw bytes of the PDF appearance stream for a text field.
@@ -159,30 +151,38 @@ def _generate_appearance_stream_data(
159151
Args:
160152
text: The text to be rendered in the form field.
161153
selection: An optional list of strings that should be highlighted as selected.
162-
font_glyph_byte_map: An optional dictionary mapping characters to their
163-
byte representation for glyph encoding.
164154
rect: The bounding box of the form field. Can be a `RectangleObject`
165155
or a tuple of four floats (x1, y1, x2, y2).
166-
font_name: The name of the font resource to use (e.g., "/Helv").
167-
font_size: The font size. If 0, it is automatically calculated
168-
based on whether the field is multiline or not.
169-
font_color: The color to apply to the font, represented as a PDF
170-
graphics state string (e.g., "0 g" for black).
171-
is_multiline: A boolean indicating if the text field is multiline.
172-
alignment: Text alignment, can be TextAlignment.LEFT, .RIGHT, or .CENTER.
173-
is_comb: Boolean that designates fixed-length fields, where every character
174-
fills one "cell", such as in a postcode.
175-
max_length: Used if is_comb is set. The maximum number of characters for a fixed-
176-
length field.
156+
**formatting_kwargs: A series of keyword arguments that describe how the
157+
appearance stream should be formatted. Can include the following:
158+
font_descriptor: The font descriptor associated with the font resource.
159+
font_glyph_byte_map: An optional dictionary mapping characters to their
160+
byte representation for glyph encoding.
161+
font_name: The name of the font resource, e.g., "/Helv".
162+
font_size: The font size. If 0, it's auto-calculated.
163+
font_color: The font color string.
164+
is_multiline: A boolean indicating if the text field is multiline.
165+
alignment: Text alignment, can be TextAlignment.LEFT, .RIGHT, or .CENTER.
166+
is_comb: Boolean that designates fixed-length fields, where every character
167+
fills one "cell", such as in a postcode.
168+
max_length: Used if is_comb is set. The maximum number of characters for a fixed-
169+
length field.
177170
178171
Returns:
179172
A byte string containing the PDF content stream data.
180173
181174
"""
182-
font_glyph_byte_map = font_glyph_byte_map or {}
183175
if isinstance(rectangle, tuple):
184176
rectangle = RectangleObject(rectangle)
185-
font_descriptor = cast(FontDescriptor, font_descriptor)
177+
font_descriptor = cast(FontDescriptor, formatting_kwargs.get("font_descriptor"))
178+
font_glyph_byte_map = formatting_kwargs.get("font_glyph_byte_map", {})
179+
font_name = formatting_kwargs.get("font_name")
180+
font_size = formatting_kwargs.get("font_size", 0.0)
181+
font_color = formatting_kwargs.get("font_color", "0 g")
182+
is_multiline = formatting_kwargs.get("is_multiline", False)
183+
alignment = formatting_kwargs.get("alignment", TextAlignment.LEFT)
184+
is_comb = formatting_kwargs.get("is_comb", False)
185+
max_length = formatting_kwargs.get("max_length", len(text))
186186

187187
# If font_size is 0, apply the logic for multiline or large-as-possible font
188188
if font_size == 0:
@@ -203,7 +203,7 @@ def _generate_appearance_stream_data(
203203
is_multiline,
204204
)
205205
elif is_comb:
206-
if max_length and len(text) > max_length:
206+
if len(text) > max_length:
207207
logger_warning (
208208
f"Length of text {text} exceeds maximum length ({max_length}) of field, input truncated.",
209209
__name__
@@ -212,7 +212,7 @@ def _generate_appearance_stream_data(
212212
lines = [(
213213
font_descriptor.text_width(char) * font_size / 1000,
214214
char
215-
) for index, char in enumerate(text) if index < (max_length or len(text))]
215+
) for index, char in enumerate(text) if index < max_length]
216216
else:
217217
lines = [(
218218
font_descriptor.text_width(line) * font_size / 1000,
@@ -288,14 +288,7 @@ def __init__(
288288
text: str = "",
289289
selection: Optional[list[str]] = None,
290290
rectangle: Union[RectangleObject, tuple[float, float, float, float]] = (0.0, 0.0, 0.0, 0.0),
291-
font_resource: Optional[DictionaryObject] = None,
292-
font_name: str = "/Helv",
293-
font_size: float = 0.0,
294-
font_color: str = "0 g",
295-
is_multiline: bool = False,
296-
alignment: TextAlignment = TextAlignment.LEFT,
297-
is_comb: bool = False,
298-
max_length: Optional[int] = None
291+
**formatting_kwargs: Any,
299292
) -> None:
300293
"""
301294
Initializes a TextStreamAppearance object.
@@ -307,28 +300,33 @@ def __init__(
307300
Args:
308301
text: The text to be rendered in the form field.
309302
selection: An optional list of strings that should be highlighted as selected.
310-
rect: The bounding box of the form field. Can be a `RectangleObject`
303+
rectangle: The bounding box of the form field. Can be a `RectangleObject`
311304
or a tuple of four floats (x1, y1, x2, y2).
312-
font_resource: An optional variable that represents a PDF font dictionary.
313-
font_name: The name of the font resource, e.g., "/Helv".
314-
font_size: The font size. If 0, it's auto-calculated.
315-
font_color: The font color string.
316-
is_multiline: A boolean indicating if the text field is multiline.
317-
alignment: Text alignment, can be TextAlignment.LEFT, .RIGHT, or .CENTER.
318-
is_comb: Boolean that designates fixed-length fields, where every character
319-
fills one "cell", such as in a postcode.
320-
max_length: Used if is_comb is set. The maximum number of characters for a fixed-
321-
length field.
322-
305+
**formatting_kwargs: A series of keyword arguments that describe how the
306+
appearance stream should be formatted. Can include the following:
307+
font_resource: An optional variable that represents a PDF font dictionary.
308+
font_name: The name of the font resource, e.g., "/Helv".
309+
font_size: The font size. If 0, it's auto-calculated.
310+
font_color: The font color string.
311+
is_multiline: A boolean indicating if the text field is multiline.
312+
alignment: Text alignment, can be TextAlignment.LEFT, .RIGHT, or .CENTER.
313+
is_comb: Boolean that designates fixed-length fields, where every character
314+
fills one "cell", such as in a postcode.
315+
max_length: Used if is_comb is set. The maximum number of characters for a fixed-
316+
length field.
323317
"""
324318
super().__init__()
325319

326320
# If a font resource was added, get the font character map
327-
if font_resource:
328-
font_resource = cast(DictionaryObject, font_resource.get_object())
321+
if formatting_kwargs.get("font_resource"):
322+
font_resource = cast(DictionaryObject, formatting_kwargs["font_resource"].get_object())
329323
font_descriptor = FontDescriptor.from_font_resource(font_resource)
324+
font_name = formatting_kwargs.get("font_name")
330325
else:
331-
logger_warning(f"Font dictionary for {font_name} not found; defaulting to Helvetica.", __name__)
326+
logger_warning(
327+
f'Font dictionary for {formatting_kwargs.get("font_name")} not found; '
328+
"defaulting to Helvetica.", __name__
329+
)
332330
font_name = "/Helv"
333331
font_resource = DictionaryObject({
334332
NameObject("/Subtype"): NameObject("/Type1"),
@@ -339,6 +337,9 @@ def __init__(
339337
})
340338
font_descriptor = CORE_FONT_METRICS["Helvetica"]
341339

340+
formatting_kwargs.pop("font_resource", None)
341+
formatting_kwargs.pop("font_name", None)
342+
342343
# Get the font glyph data
343344
_font_subtype, _, font_encoding, font_map = build_char_map_from_dict(
344345
200, font_resource
@@ -362,15 +363,10 @@ def __init__(
362363
text,
363364
selection,
364365
rectangle,
365-
font_descriptor,
366-
font_glyph_byte_map,
367-
font_name,
368-
font_size,
369-
font_color,
370-
is_multiline,
371-
alignment,
372-
is_comb,
373-
max_length
366+
font_descriptor=font_descriptor,
367+
font_glyph_byte_map=font_glyph_byte_map,
368+
font_name=font_name,
369+
**formatting_kwargs
374370
)
375371

376372
self[NameObject("/Type")] = NameObject("/XObject")
@@ -507,14 +503,14 @@ def from_text_annotation(
507503
text,
508504
selection,
509505
rectangle,
510-
font_resource,
511-
font_name,
512-
font_size,
513-
font_color,
514-
is_multiline,
515-
alignment,
516-
is_comb,
517-
max_length
506+
font_resource=font_resource,
507+
font_name=font_name,
508+
font_size=font_size,
509+
font_color=font_color,
510+
is_multiline=is_multiline,
511+
alignment=alignment,
512+
is_comb=is_comb,
513+
max_length=max_length
518514
)
519515
if AnnotationDictionaryAttributes.AP in annotation:
520516
for key, value in (

0 commit comments

Comments
 (0)