fdemmer / django-weasyprint

A Django class-based view generating PDF resposes using WeasyPrint
Other
344 stars 53 forks source link

Custom font not loaded/working using WeasyTemplateResponseMixin for PDF creation #61

Closed GitRon closed 2 years ago

GitRon commented 2 years ago

Hi there,

I am using the WeasyTemplateResponseMixin and trying to get a custom font to load. The font files are located in my django statics dir.

Here's my code:

SCSS:

$karla-font: MyFont, Arial, Helvetica, sans-serif;

@font-face {
  font-family: "MyFont";
  src: url('/static/fonts/MyFont-Regular.ttf') format("truetype"),
  url('/static/fonts/MyFont-Regular.otf') format("opentype");
}

body {
  font-family: $karla-font;
}

View:

class GeneratePdfView(WeasyTemplateResponseMixin, TemplateView):
    template_name = "my_template.html"
    pdf_filename = "my-export.pdf"
    valid_form = None

    def post(self, request, form, *args, **kwargs):
        self.valid_form = form
        return super().get(request, form, *args, **kwargs)

    def get_pdf_stylesheets(self):
        return [Path(Path(settings.APPS_DIR).as_posix() + '/static/scss/pdf/my-styles.css').as_posix()]

    ...

Hints:

Any ideas what I might be doing wrong? Unfortunately this feature is not covered in the docs AFAIK 😕

Thx! Ronny

fdemmer commented 2 years ago

Hi Ron, sorry for the late response, I hope you figured out a solution by now...

In any case, your first problem is "url resolver does not try to load the fonts". You should definitely see requests to fetch /static/fonts/MyFont-Regular.ttf from where your server is running. I can't say why not from what you posted.

I definitely recomment using the static template tag if those files are managed as static files with Django, for example:

@font-face {
  font-family: "Fira Sans";
  src: url({% static "fonts/fira/ttf/FiraSans-Regular.ttf" %}) format('truetype');
}

As for prefixing with file:; that would bypass fetching the files via HTTP and try to load them from the disk. I would not recommend doing that. It's harder to debug, there is no logging, you already have a HTTP server serving the PDF and CSS etc, why not use it for the fonts?

If you insist make sure to use all the required slashes, e.g.:

@font-face {
  font-family: "Fira Sans";
  src: url(file://{% static "fonts/fira/ttf/FiraSans-Regular.ttf" %}) format('truetype');
}

Or better yet, leave the HTML as is and set WEASYPRINT_BASEURL = '/'.

A file that would normally be served at /static/fonts/fira/ttf/FiraSans-Regular.ttf should then have this absolute path: file:///static/fonts/fira/ttf/FiraSans-Regular.ttf

Final important note on font files: While investigating this I tried WeasyPrint 52 and >= 53 with various formats, support varies due to the libraries WeasyPrint uses underneath:

Sidenote: >= 53 does not apply "faux styling" to achieve bold or italic. Make sure you define font-faces providing the styles/weights, e.g.:

@font-face {
  font-family: "Fira Sans";
  src: url({% static "fonts/fira/ttf/FiraSans-Regular.ttf" %}) format('truetype');
  font-weight: normal;
  font-style: normal;
}
@font-face {
  font-family: "Fira Sans";
  src: url({% static "fonts/fira/ttf/FiraSans-Bold.ttf" %}) format('truetype');
  font-weight: bold;
  font-style: normal;
}
GitRon commented 2 years ago

@fdemmer Thanks for the reply! I guess the path or the update did the trick. 👍 👍

Just being curious: I am using a CSS file for my styles, how did you integrate the static helper there?

fdemmer commented 2 years ago

Just being curious: I am using a CSS file for my styles, how did you integrate the static helper there?

I don't :(

My examples assume that CSS would be in a template's <style> tag. Haven't looked into it in detail, but you could generate CSS or at least one with CSS variables with a template, e.g. this stackoverflow.

GitRon commented 2 years ago

Nevertheless, your solution with the file:///static/... works 👍