fpdf2 icon indicating copy to clipboard operation
fpdf2 copied to clipboard

pdf.write_html() doesn't support custom fonts

Open tur-ium opened this issue 8 months ago • 4 comments

Describe the bug I am trying to write some markdown text containing characters that are not supported by the core font. I have followed the instructions from the docs (which are great by the way, thank you for this!). When writing to html, an error is raised which seems to be a relatively soluble case-issue in the self.fonts of the HTML2FPDF class.

Error details

Minimal code Please include some minimal Python code reproducing your issue:

from fpdf import FPDF

html = markdown.markdown(md_text)

  # Create a PDF object
  pdf = FPDF()
  try:
      # Add the HTML to the PDF
      pdf.add_page()
      pdf.add_font("dejavusans", fname=r"...\media\fonts\dejavu-sans\DejaVuSans.ttf")
      pdf.add_font("dejavusansB",
                   fname=r"...\media\fonts\dejavu-sans\DejaVuSans-Bold.ttf")
      pdf.add_font("dejavusansBO",
                   fname=r"...\media\fonts\dejavu-sans\DejaVuSans-BoldOblique.ttf")
      pdf.set_font("dejavusans", style='', size=font_size)
      pdf.set_text_color(0,0,0)
      pdf.write_html(html,font_family=font_family) # <--- Error is raised here. It tries to get dejavusansB, but can't find it because the key for the font is "dejavusansb" (lowercase b)
  except FPDFUnicodeEncodingException as e:
      raise e
  # Save the PDF to a bytes buffer
  pdf_buffer = pdf.output(dest='S')
  pdf.output(f'output_path.pdf')...

Environment Please provide the following information:

  • Operating System: Windows 11
  • Python version: 3.10.11
  • fpdf2 version used: fpdf2==2.8.2

tur-ium avatar Apr 14 '25 17:04 tur-ium

Found a potential fix for this issue, please see pull request here: https://github.com/py-pdf/fpdf2/pull/1408

tur-ium avatar Apr 14 '25 17:04 tur-ium

Hi @tur-ium You need to add the bold version of the font with the same name, and the correct style. Like this:

pdf.add_font("dejavusans", style="", fname=r"...\media\fonts\dejavu-sans\DejaVuSans.ttf")
pdf.add_font("dejavusans", style="B",  fname=r"...\media\fonts\dejavu-sans\DejaVuSans-Bold.ttf")
pdf.add_font("dejavusans", style="BI", fname=r"...\media\fonts\dejavu-sans\DejaVuSans-BoldOblique.ttf")

andersonhc avatar Apr 14 '25 17:04 andersonhc

Hi @andersonhc , that worked, but it would be good to document or have a better error message. How about asking in the error if the user has correctly added the font, something like below?

[referring to lines 2116-2119]
        if fontkey not in self.fonts:
            if fontkey not in CORE_FONTS:
                raise FPDFException(
                    f"Undefined font: {fontkey} - "
                    f"Use built-in fonts or FPDF.add_font() beforehand. Ensure that if you have also added bold or italic fonts where necessary, using the style parameter e.g. pdf.add_font('MyFont', style='B', '\path\to\MyFont-Bold.ttf')"
                )

tur-ium avatar Apr 14 '25 18:04 tur-ium

Hi @tur-ium

Thank you for reaching out, and even submitting a PR! 👍 It's great to have helpful contributors like you.

You did not provide an autonomous minimal reproducible example, as suggested in our bug report issue template: https://github.com/py-pdf/fpdf2/blob/master/.github/ISSUE_TEMPLATE/bug_report.md md_text / font_size / font_family were not provided.

There is a shorter autonomous code snippet that I think reproduce your issue:

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.add_font(fname="test/fonts/DejaVuSans.ttf")  # add font DejaVuSans
pdf.add_font("DejaVuSansB", fname="test/fonts/DejaVuSans-Bold.ttf")  # reproduce the issue you reported
# pdf.add_font("DejaVuSans", style="B", fname="test/fonts/DejaVuSans-Bold.ttf")  # fix
pdf.set_font("DejaVuSans", size=10)
pdf.write_html("<b>BOLD</b>", font_family="DejaVuSans")
pdf.output("issue_1407.pdf")

This exception is then raised: fpdf.errors.FPDFException: Undefined font: dejavusansB - Use built-in fonts or FPDF.add_font() beforehand

Is it the error you got @tur-ium?

it would be good to document or have a better error message.

I agree that we should try to improve our error messages, especially if you did not understand what was required there.

First, could you please explain to use why you try to pass "dejavusansB" to pdf.add_font()?

Second, the error message currently already suggests to call FPDF.add_font() beforehand. Could you tell us why/how this was a clear enough indication?

Lucas-C avatar Apr 16 '25 07:04 Lucas-C

Given the lack of answer, I'm closing this for now.

Lucas-C avatar Jun 06 '25 09:06 Lucas-C