1

I'm trying to render my html page to pdf using django with these functions while also using a Cyrillic font:

def fetch_resources(uri, rel):
    if settings.STATIC_URL and uri.startswith(settings.STATIC_URL):
        path = os.path.join(STATIC_ROOT, uri.replace(settings.STATIC_URL, ""))
    elif settings.MEDIA_URL and uri.startswith(settings.MEDIA_URL):
        path = os.path.join(STATIC_ROOT, uri.replace(settings.MEDIA_URL, ""))
    else:
        path = os.path.join(settings.STATIC_ROOT, uri)

    return path.replace("\\", "/")


def render_pdf(url_template, context={}):
    template = get_template(url_template)
    html = template.render(context)
    result = BytesIO()
    pdf = pisa.CreatePDF(html, result, link_callback=fetch_resources)
    if not pdf.err:
        return HttpResponse(result.getvalue(), content_type="application/pdf")
    return None

This is the view:

class DownloadPDF(View)

    def get(self, request, *args, **kwargs):
        pdf = render_pdf("tmp.html")
        return HttpResponse(pdf, content_type="application/pdf")

And this is the template:

{% block extra_style %}
    <style type="text/css">
        @font-face { font-family: Calibri; src: url("/static/fonts/Calibri.ttf"); }
        body { font-family: 'Calibri', sans-serif;}
    </style>
{% endblock %}

{% block content %}
    <body>
        <p>йоу</p>
    </body>
{% endblock %}

As you can see, I'm using Calibri font for cyrillic letters, however when I'm rendering the page I get the following error:

TTFError at /download-pdf/
Can't open file "C:\Users\user\AppData\Local\Temp\tmp6o9yikqk.ttf"

It seems like the interpreter is looking for the file in a wrong catalog, since my project is on D drive and my font path is in /static/fonts/Calibri.ttf

settings.py

STATIC_URL = "/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, "staticfiles")]
STATIC_ROOT = os.path.join(BASE_DIR, "static")

Full Traceback:

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/download/slug

Django Version: 4.1.7
Python Version: 3.11.0
Installed Applications:
['django.contrib.admin',
 'authentication',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 *apps*]
Installed Middleware:
[*basic middleware]



Traceback (most recent call last):
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 523, in open_for_read
    return open_for_read_by_name(name,mode)
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 463, in open_for_read_by_name
    return open(name,mode)

During handling of the above exception ([Errno 13] Permission denied: 'C:\\Users\\slavk\\AppData\\Local\\Temp\\tmp6uw9470p.ttf'), another exception occurred:
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 530, in open_for_read
    return BytesIO((datareader if name[:5].lower()=='data:' else rlUrlRead)(name))
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 476, in rlUrlRead
    return urlopen(name).read()
  File "C:\Users\slavk\AppData\Local\Programs\Python\Python311\Lib\urllib\request.py", line 216, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Users\slavk\AppData\Local\Programs\Python\Python311\Lib\urllib\request.py", line 519, in open
    response = self._open(req, data)
  File "C:\Users\slavk\AppData\Local\Programs\Python\Python311\Lib\urllib\request.py", line 541, in _open
    return self._call_chain(self.handle_open, 'unknown',
  File "C:\Users\slavk\AppData\Local\Programs\Python\Python311\Lib\urllib\request.py", line 496, in _call_chain
    result = func(*args)
  File "C:\Users\slavk\AppData\Local\Programs\Python\Python311\Lib\urllib\request.py", line 1419, in unknown_open
    raise URLError('unknown url type: %s' % type)

During handling of the above exception (<urlopen error unknown url type: c>), another exception occurred:
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 151, in TTFOpenFile
    f = open_for_read(fn,'rb')
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 534, in open_for_read
    return open_for_read(name,mode)
  File "D:\*\venv\Lib\site-packages\reportlab\lib\utils.py", line 532, in open_for_read
    raise IOError('Cannot open resource "%s"' % name)

During handling of the above exception (Cannot open resource "C:\Users\slavk\AppData\Local\Temp\tmp6uw9470p.ttf"), another exception occurred:
  File "D:\*\venv\Lib\site-packages\django\core\handlers\exception.py", line 56, in inner
    response = get_response(request)
  File "D:\*\venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "D:\*\venv\Lib\site-packages\django\views\generic\base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "D:\*\venv\Lib\site-packages\django\views\generic\base.py", line 142, in dispatch
    return handler(request, *args, **kwargs)
  File "D:\*\views.py", line 78, in get
    pdf = render_to_pdf("tmp.html", {'object': object})
  File "D:\*\utils\render_to_pdf.py", line 25, in render_to_pdf
    pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\document.py", line 116, in pisaDocument
    context = pisaStory(src, path, link_callback, debug, default_css, xhtml,
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\document.py", line 68, in pisaStory
    pisaParser(src, context, default_css, xhtml, encoding, xml_output)
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\parser.py", line 793, in pisaParser
    context.parseCSS()
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\context.py", line 539, in parseCSS
    self.css = self.cssParser.parse(self.cssText)
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\w3c\cssParser.py", line 443, in parse
    src, stylesheet = self._parseStylesheet(src)
  File "D:\Work\gofriends\TrojanCRM\venv\Lib\site-packages\xhtml2pdf\w3c\cssParser.py", line 545, in _parseStylesheet
    src, atResults = self._parseAtKeyword(src)
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\w3c\cssParser.py", line 667, in _parseAtKeyword
    src, result = self._parseAtFontFace(src)
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\w3c\cssParser.py", line 845, in _parseAtFontFace
    result = [self.cssBuilder.atFontFace(properties)]
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\context.py", line 176, in atFontFace
    self.c.loadFont(names, src,
  File "D:\*\venv\Lib\site-packages\xhtml2pdf\context.py", line 926, in loadFont
    file = TTFont(fullFontName, filename)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 1178, in __init__
    self.face = TTFontFace(filename, validate=validate, subfontIndex=subfontIndex)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 1072, in __init__
    TTFontFile.__init__(self, filename, validate=validate, subfontIndex=subfontIndex)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 439, in __init__
    TTFontParser.__init__(self, file, validate=validate,subfontIndex=subfontIndex)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 175, in __init__
    self.readFile(file)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 251, in readFile
    self.filename, f = TTFOpenFile(f)
  File "D:\*\venv\Lib\site-packages\reportlab\pdfbase\ttfonts.py", line 161, in TTFOpenFile
    raise TTFError('Can\'t open file "%s"' % fn)

Exception Type: TTFError at /download/item
Exception Value: Can't open file "C:\Users\slavk\AppData\Local\Temp\tmp6uw9470p.ttf"
SLDem
  • 2,065
  • 1
  • 8
  • 28
  • https://stackoverflow.com/a/17738606/4151233 – Marco May 03 '23 at 12:17
  • ok, I used the code from the answer in `render_pdf` method and used the url in `custom_css` argument of the pisa.CreatePDF class, but it still shows me the black squares on utf-16 or weird symbols on utf-8 encodings, maybe you have any more advice on how I can use the code from the answer? – SLDem May 03 '23 at 12:26
  • Can you make sure (debugging) the static function picked up the font? – Marco May 03 '23 at 12:55
  • It has a path to it I think, how can I make sure? – SLDem May 03 '23 at 14:48
  • Have you tried to generate the path from the source (not from generated static folder) like `font_path = os.path.join(settings.BASE_DIR, "templates/staticfiles/fonts/Calibri.ttf")`. change the path accordingly. – Marco May 04 '23 at 13:18
  • Just tried it, still got the TTFError Can`t open file, looking for the font in the C drive – SLDem May 04 '23 at 15:38
  • also note: when I have a wrong path in the css in my html file it loads but renders black squares or weird symbols instead, when I add the css with the correct path I get the above error – SLDem May 04 '23 at 16:25
  • How did you define `BASE_DIR`? Your Django settings should have something like this: `BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))`. – Marco May 04 '23 at 16:28
  • mine was `BASE_DIR = Path(__file__).resolve().parent.parent`, changing it to your variant didn't help :( – SLDem May 04 '23 at 16:30
  • `TTFError at /download-pdf/` Can you provide the full stack trace here? I wonder if it's trying to make a temporary file, rather than trying to load the font. – Nick ODell May 13 '23 at 18:21
  • Added full traceback with * for sensitive information but it usually just path to the project venv – SLDem May 13 '23 at 19:47

0 Answers0