JazzCore / python-pdfkit

Wkhtmltopdf python wrapper to convert html to pdf
MIT License
1.99k stars 329 forks source link

Font-faces issue. Fonts work in HTML but not in PDF File #262

Open paframar opened 3 months ago

paframar commented 3 months ago

Fonts work in HTML but not in PDF File

I'm trying to apply some fonts into my PDF document, which is been generated from from_string method.

I wrote string content into an HTML file before PDF is generated, opened it, and results look expected (fonts are read), but in the PDF case, I can't made pdfkit reach the fonts.

I'm getting or ContentNotFound and ProtocolUnknownError errors which refer to paths of the font-faces in the style tag of my html.

Even seems html it's not the problem, I've tried so far expressing the fonts path in many ways: absolute, relative, base64, hardcoded. Made a proxy to serve font files as well (which tested and works). Nothing of this makes pdfkit use my fonts.

I'm trying to use Montserrat font.

Tried also to add font-style and font-weight attributes into @font-faces but either of these seems to be working.

Here I provide my app.route code, bit long, but to see what I mean.


@app.route("/pdfkit-test")
def pdfkit_test():

    html_str = """
        <!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8' />
            <title>PDF Test</title>
            <style>
            @font-face {
                font-family: 'Montserrat';
                src: url('/Users/paframar/documentBuilder/assets/fonts/Montserrat/Montserrat.ttf') format('truetype');
            }
            @font-face {
                font-family: 'Montserrat-Bold';
                src: url('/Users/paframar/documentBuilder/assets/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype');
            }
            @font-face {
                font-family: 'Montserrat-Italic';
                src: url('/Users/paframar/documentBuilder/assets/fonts/Montserrat/Montserrat-Italic.ttf') format('truetype');
            }
            p {
                font-size: 18pt;
                line-height: 1;
            }
            </style>
        </head>
        <body>

            <p style='font-family: Montserrat;'>
                This font is: Montserrat
            </p>

            <p style='font-family: Montserrat-Bold;'>
                This font is: Montserrat-Bold
            </p>

            <p style='font-family: Montserrat-Italic;'>
                This font is: Montserrat-Italic
            </p>

        </body>
        </html>
    """

    # ------------- options -------------
    options = {
        "page-width": "586.5pt",
        "page-height": "832.5pt",
        "margin-top": "0mm",
        "margin-right": "0mm",
        "margin-bottom": "0mm",
        "margin-left": "0mm",
        "encoding": "UTF-8",
        "no-outline": None,
        "disable-smart-shrinking": "",
        "zoom": "1",
        "enable-local-file-access": None,
    }

    # ------------- pdfkit_config -------------
    wkhtmltopdf_path = shutil.which("wkhtmltopdf")
    if wkhtmltopdf_path is None:
        # Sets up wkhtmltopdf path for use in Heroku
        pdfkit_config = pdfkit.configuration(wkhtmltopdf="/app/bin/wkhtmltopdf")
    else:
        pdfkit_config = pdfkit.configuration(wkhtmltopdf=wkhtmltopdf_path)

    try:
        # ------------- html file write -------------
        current_dir = os.path.dirname(os.path.abspath(__file__))
        project_root = os.path.abspath(os.path.join(current_dir, '..'))
        html_file_path = os.path.join(project_root, 'src', 'html_str.html')
        if os.path.exists(html_file_path):
            os.remove(html_file_path)
        with open(html_file_path, 'w', encoding='utf-8') as file:
            file.write(html_str)

        # ------------- pdf response -------------
        pdf = pdfkit.from_string(
            html_str, 
            False, 
            options=options, 
            configuration=pdfkit_config,
        )
        response = make_response(pdf)
        response.headers['Content-Type'] = 'application/pdf'
        response.headers['Content-Disposition'] = 'inline; filename=output.pdf'

        return response

    except Exception as e:
        print(f"Error generating PDF: {e}")
        return f"Error generating PDF: {e}", 500

Results

HTML file opened in Chrome:

✅ Shows fonts as expected.

image

PDF File #1

❌ Shows only Montserrat font applied (because I've it installed locally, in my Font Book). but not other fonts.

image


PDF File #2

Removing al the @font-faces from <style> tag brings same result from previous test.

❌ Only Montserrat Font is recognized, proving that font-face aren't working.

image

Please let me know if you notice something wrong that I've didn't here and feel free to ask any questions about this to help you help me :).

Thanks in advance!

Pablo.