Refine non-dict resource guard: prefer isinstance, cover FontDescriptor
Follow-on to the non-dictionary /Font and /XObject guard. Replace the _dict_entries() helper with an isinstance(..., pikepdf.Dictionary) check at each resource lookup, which pikepdf's metaclass supports directly and which reads as exactly the invariant being enforced. Iterate via as_dict().values() so the values are typed and mypy stays clean once the Any from the untyped resources argument is narrowed away. Also guard _cid_font_is_embedded against a non-dictionary /FontDescriptor: `key in descriptor` raises ValueError on a non-dict, which the caller's except (AttributeError, TypeError, KeyError) does not catch. Such a font now counts as non-embedded and is reported, so PDF/A conversion is refused rather than risking Ghostscript corrupting a pre-existing CID text layer. Adds a regression test for the FontDescriptor case (issue #1713).
This commit is contained in:
@@ -110,6 +110,36 @@ class TestFindNonembeddedCidFonts:
|
||||
with pikepdf.open(path) as pdf:
|
||||
assert find_nonembedded_cid_fonts(pdf) == set()
|
||||
|
||||
def test_non_dictionary_font_descriptor_is_reported(self, tmp_path):
|
||||
# A Type0 font whose descendant carries a non-dictionary /FontDescriptor
|
||||
# has no embedded glyph data, so it must be reported -- not crash. This
|
||||
# is the same malformed-resource bug class as #1713, one level deeper:
|
||||
# `key in descriptor` raises ValueError on a non-dictionary.
|
||||
path = tmp_path / 'bad_descriptor.pdf'
|
||||
with pikepdf.new() as pdf:
|
||||
page = pdf.add_blank_page()
|
||||
cidfont = pdf.make_indirect(
|
||||
pikepdf.Dictionary(
|
||||
Type=Name.Font,
|
||||
Subtype=Name.CIDFontType2,
|
||||
BaseFont=Name('/BOGUS+CID'),
|
||||
FontDescriptor=Name.NotADictionary,
|
||||
)
|
||||
)
|
||||
type0 = pdf.make_indirect(
|
||||
pikepdf.Dictionary(
|
||||
Type=Name.Font,
|
||||
Subtype=Name.Type0,
|
||||
BaseFont=Name('/BOGUS+CID'),
|
||||
Encoding=Name.Identity_H,
|
||||
DescendantFonts=pikepdf.Array([cidfont]),
|
||||
)
|
||||
)
|
||||
page.Resources = pikepdf.Dictionary(Font=pikepdf.Dictionary(F0=type0))
|
||||
pdf.save(path)
|
||||
with pikepdf.open(path) as pdf:
|
||||
assert find_nonembedded_cid_fonts(pdf) == {'BOGUS+CID'}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nonembedded_cid_pdf(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user