Skip to content

Commit ad26892

Browse files
committed
ROB: TextAppearanceStream: Add default font resource
Make sure that we always have Helvetica as a viable font resource, for which we surely have all necessary font metrics needed for text wrapping.
1 parent 683f479 commit ad26892

File tree

2 files changed

+35
-28
lines changed

2 files changed

+35
-28
lines changed

pypdf/generic/_appearance_stream.py

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -261,27 +261,35 @@ def __init__(
261261
if font_resource:
262262
font_resource = cast(DictionaryObject, font_resource.get_object())
263263
font_descriptor = FontDescriptor.from_font_resource(font_resource)
264-
_font_subtype, _, font_encoding, font_map = build_char_map_from_dict(
265-
200, font_resource
266-
)
267-
try: # remove width stored in -1 key
268-
del font_map[-1]
269-
except KeyError:
270-
pass
271-
font_glyph_byte_map: dict[str, bytes]
272-
if isinstance(font_encoding, str):
273-
font_glyph_byte_map = {
274-
v: k.encode(font_encoding) for k, v in font_map.items()
275-
}
276-
else:
277-
font_glyph_byte_map = {v: bytes((k,)) for k, v in font_encoding.items()}
278-
font_encoding_rev = {v: bytes((k,)) for k, v in font_encoding.items()}
279-
for key, value in font_map.items():
280-
font_glyph_byte_map[value] = font_encoding_rev.get(key, key)
281264
else:
282-
logger_warning(f"Font dictionary for {font_name} not found.", __name__)
283-
font_glyph_byte_map = {}
284-
font_descriptor = FontDescriptor()
265+
logger_warning(f"Font dictionary for {font_name} not found; defaulting to Helvetica.", __name__)
266+
font_name = "/Helv"
267+
font_resource = DictionaryObject()
268+
font_resource[NameObject("/Type")] = NameObject("/Font")
269+
font_resource[NameObject("/Subtype")] = NameObject("/Type1")
270+
font_resource[NameObject("/Name")] = NameObject("/Helv")
271+
font_resource[NameObject("/BaseFont")] = NameObject("/Helvetica")
272+
font_resource[NameObject("/Encoding")] = NameObject("/MacRomanEncoding")
273+
font_descriptor = CORE_FONT_METRICS["Helvetica"]
274+
275+
# Get the font glyph data
276+
_font_subtype, _, font_encoding, font_map = build_char_map_from_dict(
277+
200, font_resource
278+
)
279+
try: # remove width stored in -1 key
280+
del font_map[-1]
281+
except KeyError:
282+
pass
283+
font_glyph_byte_map: dict[str, bytes]
284+
if isinstance(font_encoding, str):
285+
font_glyph_byte_map = {
286+
v: k.encode(font_encoding) for k, v in font_map.items()
287+
}
288+
else:
289+
font_glyph_byte_map = {v: bytes((k,)) for k, v in font_encoding.items()}
290+
font_encoding_rev = {v: bytes((k,)) for k, v in font_encoding.items()}
291+
for key, value in font_map.items():
292+
font_glyph_byte_map[value] = font_encoding_rev.get(key, key)
285293

286294
ap_stream_data = self._generate_appearance_stream_data(
287295
text,
@@ -300,13 +308,12 @@ def __init__(
300308
self[NameObject("/BBox")] = RectangleObject(rectangle)
301309
self.set_data(ByteStringObject(ap_stream_data))
302310
self[NameObject("/Length")] = NumberObject(len(ap_stream_data))
303-
# Update Resources with font information if necessary
304-
if font_resource is not None:
305-
self[NameObject("/Resources")] = DictionaryObject({
306-
NameObject("/Font"): DictionaryObject({
307-
NameObject(font_name): getattr(font_resource, "indirect_reference", font_resource)
308-
})
311+
# Update Resources with font information
312+
self[NameObject("/Resources")] = DictionaryObject({
313+
NameObject("/Font"): DictionaryObject({
314+
NameObject(font_name): getattr(font_resource, "indirect_reference", font_resource)
309315
})
316+
})
310317

311318
@classmethod
312319
def from_text_annotation(

tests/test_writer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,7 +2427,7 @@ def test_no_resource_for_14_std_fonts(caplog):
24272427
writer.update_page_form_field_values(
24282428
p, {a["/T"]: "Brooks"}, auto_regenerate=False
24292429
)
2430-
assert "Font dictionary for /Helvetica not found." in caplog.text
2430+
assert "Font dictionary for /Helvetica not found; defaulting to Helvetica." in caplog.text
24312431

24322432

24332433
@pytest.mark.enable_socket
@@ -2439,7 +2439,7 @@ def test_field_box_upside_down():
24392439
writer.update_page_form_field_values(None, {"FreightTrainMiles": "0"})
24402440
assert writer.pages[0]["/Annots"][13].get_object()["/AP"]["/N"].get_data() == (
24412441
b"q\n/Tx BMC \nq\n1 1 105.29520000000001 10.835000000000036 re\n"
2442-
b"W\nBT\n/Arial 8.0 Tf 0 g\n2 2.8350000000000364 Td\n(0) Tj\nET\n"
2442+
b"W\nBT\n/Helv 8.0 Tf 0 g\n2 2.8350000000000364 Td\n(0) Tj\nET\n"
24432443
b"Q\nEMC\nQ\n"
24442444
)
24452445
box = writer.pages[0]["/Annots"][13].get_object()["/AP"]["/N"]["/BBox"]

0 commit comments

Comments
 (0)