Skip to content

Commit 2fea98c

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 ffa433d commit 2fea98c

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

285293
ap_stream_data = self._generate_appearance_stream_data(
286294
text,
@@ -299,13 +307,12 @@ def __init__(
299307
self[NameObject("/BBox")] = RectangleObject(rectangle)
300308
self.set_data(ByteStringObject(ap_stream_data))
301309
self[NameObject("/Length")] = NumberObject(len(ap_stream_data))
302-
# Update Resources with font information if necessary
303-
if font_resource is not None:
304-
self[NameObject("/Resources")] = DictionaryObject({
305-
NameObject("/Font"): DictionaryObject({
306-
NameObject(font_name): getattr(font_resource, "indirect_reference", font_resource)
307-
})
310+
# Update Resources with font information
311+
self[NameObject("/Resources")] = DictionaryObject({
312+
NameObject("/Font"): DictionaryObject({
313+
NameObject(font_name): getattr(font_resource, "indirect_reference", font_resource)
308314
})
315+
})
309316

310317
@classmethod
311318
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)