Problem registering custom font in reportlab

Hi everyone

I have problem in registering a custom font for using in reportlab
here is my code snipit for doing so in views.py

import io
from django.http import FileResponse
import reportlab
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.units import cm
from reportlab.lib.pagesizes import letter

 def pdf_view(request, **kwargs):

        # registering custom font
        reportlab_directory = os.path.dirname(reportlab.__file__)
        print(f"reportlab _directory is:{reportlab_directory}")
        font_folder = os.path.join(reportlab_directory, "fonts")
        print(f"font folder is :{font_folder}")
        custom_font_folder = os.path.join(font_folder, "Yekan.ttf")
        print(f"custom font folder is:{custom_font_folder}")
        custom_font = TTFont("yekan", custom_font_folder)
        pdfmetrics.registerFont(custom_font)

        # Create a file-like buffer to receive PDF data.
        buffer = io.BytesIO()

        # Create the PDF object, using the buffer as its "file."
        p = canvas.Canvas(buffer, letter, bottomup=0)

        # Draw things on the PDF. Here's where the PDF generation happens.
        # See the ReportLab documentation for the full list of functionality.
        textob = p.beginText()
        textob.setTextOrigin(cm, cm)
        textob.setFont("yekan-pesian", 14)
        lines = ['جمع کل' + '    ' + 'قیمت واحد' + '    ' + 'تعداد' + '    ' + 'نام کالا',
                 'good name',
                 '---------------------------------------------------------------------']
        bb_items = BuyBasket.objects.filter(customer=kwargs['c_id'])
        for item in bb_items:
            lines.append(str(item.good)+'    '+str(item.quantity)+'    '+str(item.price)+'    '+str(item.total_price))
        for line in lines:
            textob.textLine(line)
        # Close the PDF object cleanly, and we're done.
        p.drawText(textob)
        p.showPage()
        p.save()
        buffer.seek(0)
        # FileResponse sets the Content-Disposition header so that browsers
        # present the option to save the file.
        return FileResponse(buffer, as_attachment=True, filename="bill.pdf")

all things looks to be set properly(when i print pathes to fonts directory its shows correct path) but
i got this error

TTFError at /orders/2/buy_basket/pdf/

Can't open file "/usr/local/lib/python3.10/site-packages/reportlab/fonts/Yekan.ttf"

any help would be appriciated
Thanks

Does this file exist ? If so, what are the permissions on this file ? Does the user running the application as access to it ?

yes the file exists and i i granted permission for accessing fonts folder to current user

There does not sem to be such font file embedded in reportlab package: reportlab: files

It is not in reportlab package i manually add it to fonts folder of reportlab because reportlab default fonts could not display persian fonts

Well, can you provide the full traceback of the error ?

Does the error occur when using font outside of Django view context ? Can you try registering the font in a python shell and tell whether the same error occur or not ? If so, and reportlab does not provide more information about the problem, i’m afraid there is little we can do ! Maybe .ttf file is somewhat corrupted.

I don’t know if registering the same font several time in reportlab can lead to errors, but I’d move the code corresponding to font registration outside of view (at module level) so that it is registered only once.

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/reportlab/lib/utils.py", line 523, in open_for_read
    return open_for_read_by_name(name,mode)
  File "/usr/local/lib/python3.10/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 2] No such file or directory: '/usr/local/lib/python3.10/site-packages/reportlab/fonts/Yekan.ttf'), another exception occurred:
  File "/usr/local/lib/python3.10/site-packages/reportlab/lib/utils.py", line 530, in open_for_read
    return BytesIO((datareader if name[:5].lower()=='data:' else rlUrlRead)(name))
  File "/usr/local/lib/python3.10/site-packages/reportlab/lib/utils.py", line 476, in rlUrlRead
    return urlopen(name).read()
  File "/usr/local/lib/python3.10/urllib/request.py", line 216, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/local/lib/python3.10/urllib/request.py", line 503, in open
    req = Request(fullurl, data)
  File "/usr/local/lib/python3.10/urllib/request.py", line 322, in __init__
    self.full_url = url
  File "/usr/local/lib/python3.10/urllib/request.py", line 348, in full_url
    self._parse()
  File "/usr/local/lib/python3.10/urllib/request.py", line 377, in _parse
    raise ValueError("unknown url type: %r" % self.full_url)

During handling of the above exception (unknown url type: '/usr/local/lib/python3.10/site-packages/reportlab/fonts/Yekan.ttf'), another exception occurred:
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 151, in TTFOpenFile
    f = open_for_read(fn,'rb')
  File "/usr/local/lib/python3.10/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 "/usr/local/lib/python3.10/site-packages/reportlab/fonts/Yekan.ttf"), another exception occurred:
  File "/usr/local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/code/orders/views.py", line 69, in pdf_view
    custom_font = TTFont("yekan", custom_font_folder)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 1185, in __init__
    self.face = TTFontFace(filename, validate=validate, subfontIndex=subfontIndex)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 1073, in __init__
    TTFontFile.__init__(self, filename, validate=validate, subfontIndex=subfontIndex)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 439, in __init__
    TTFontParser.__init__(self, file, validate=validate,subfontIndex=subfontIndex)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 175, in __init__
    self.readFile(file)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 251, in readFile
    self.filename, f = TTFOpenFile(f)
  File "/usr/local/lib/python3.10/site-packages/reportlab/pdfbase/ttfonts.py", line 161, in TTFOpenFile
    raise TTFError('Can\'t open file "%s"' % fn)

Exception Type: TTFError at /orders/2/buy_basket/pdf/
Exception Value: Can't open file "/usr/local/lib/python3.10/site-packages/reportlab/fonts/Yekan.ttf"

this is full trackback
actually i did not use this font outside Django view but good point to mention it. I will give it a try

Message is pretty clear

Yes i undrestand what it is saying
but i am 100% sure that the font exist in fonts folder

Can you provide the result of following command ?

ls /usr/local/lib/python3.10/site-packages/reportlab/fonts

see this

This is not the same path: mind the dist-packages vs site-packages

Oh my God
you are right man
Thanks a lot

So why does not this path exist?

How did you install reportlab ?

Installed packages files are in site-packages so this is where reportlab.__file__ lead.

The path does not exist because reportlab does not natively contain this file. You told that you copied the file there (in dist-packages) but this is obviously not the right place. You should have copied it in site-packages.

Whatever, in my mind, you shouldn’t manually copy file in dist-packages nor site-packages. I’d suggest you put your custom fonts in a specific directory (e.g. under /opt/fonts or any other directory that suits you) and target this folder in your code

Thanks a lot for your help
This misleading piece of code i used for registering custom fonts comes from a Youtube video
now I am going to use you method
Thanks again