Skip to content

write_html: use the first available font of a <font face> list, like browsers - #2009

Merged
andersonhc merged 5 commits into
py-pdf:masterfrom
RavSinghChandan:html-font-face-list
Oct 14, 2026
Merged

andersonhc merged 5 commits into
py-pdf:masterfrom
RavSinghChandan:html-font-face-list

Conversation

@RavSinghChandan

@RavSinghChandan RavSinghChandan commented Oct 12, 2026 •

Copy link
Copy Markdown

<font face="Arial, Helvetica, sans-serif">, the usual way fonts are written in older HTML and email templates, raised FPDFException: Undefined font: arial, helvetica, sans-serif, because the whole list was used as one font name. Browsers use the first font in the list that is available. Now fpdf2 does too: a core font or one added with add_font(), with the generic serif, sans-serif and monospace families mapped to Times, Helvetica and Courier. If none of the names is available it uses the first one as before, so an unknown font still raises (test_html_bad_font is unchanged). Added tests.

e.g. Fixes #0

Checklist:

  • A unit test is covering the code added / modified by this PR

  • In case of a new feature, docstrings have been added, with also some documentation in the docs/ folder

  • A mention of the change is present in CHANGELOG.md

  • This PR is ready to be merged

By submitting this pull request, I confirm that my contribution is made under the terms of the GNU LGPL 3.0 license.

@RavSinghChandan RavSinghChandan changed the title write_html: use the first available font of a <font face> list, like … write_html: use the first available font of a <font face> list, like browsers Oct 12, 2026
Comment thread fpdf/html.py Resolved
@RavSinghChandan

Copy link
Copy Markdown
Author

Good idea, thanks! It now uses get_font_from_family(), so the extra mapping is gone and the change is just a few lines. If none of the fonts in the list is available, it falls back to the old behavior, so an unknown font still raises as before.

@andersonhc

Copy link
Copy Markdown
Collaborator

Hi, thank you for the PR! I’ll do a more thorough review later, but a few things come to mind:

  • PDF/A requires embedded fonts. Does HTML font resolution still raise PDFAComplianceError when a core font is selected?
  • Does the fallback list select the first available font, including fonts registered with add_font()?
  • Are bold and italic styles respected when resolving the font?

It would be helpful to add tests covering these cases.

@RavSinghChandan

Copy link
Copy Markdown
Author

Thanks, good questions. Two of them were real problems, now fixed:

  • PDF/A: get_font_from_family() added the core font to the registry, so set_font() then skipped its PDF/A check. I split the lookup into a new ResourceCatalog.resolve_font_family(), which only resolves the family without adding anything. get_font_from_family() uses it, and write_html() uses it too, so set_font() adds the font and still raises PDFAComplianceError for a core font.
  • add_font(): yes, the list is checked in order, so a registered font listed before a core font is used.
  • Bold and italic: the current B/I style is now passed to the lookup, so a font added only in bold is found for bold text.

Added tests for each, plus small unit tests for resolve_font_family().

@RavSinghChandan

Copy link
Copy Markdown
Author

Thanks for the review and for pointing out those cases. I’ve addressed them and added coverage for the PDF/A, registered font, and bold/italic behavior.

@andersonhc
andersonhc merged commit e14a388 into py-pdf:master Oct 14, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants