djangodjango-templatesxhtml2pdf

xhtml2pdf works great with an Image located at project's root on windows but breaks when deployed to Ubuntu


I have a very strange problem and tried everything for about 5 hours to solve this odd issue but no luck.

I was able to generate a PDF file with images successfully using xhtml2pdf on my machine which is running windows 10, but when I deployed to Ubuntu my image just got broken for no reason!

I think the problem is that, on Ubuntu, it doesn't build the path to this image correctly, but, ironically, it does on windows perfectly!

here is the section which is working just fine on windows but not on Ubuntu:

<table>
        <tr>
            <td> <img src="test_logo.png" alt="logo"></td>
        </tr>
</table>

And test_logo.png is located at the root of my project just like this:

my_project/
   app1/
   app2/
   requirements.txt
   test_logo.png

And my link_callback()

def link_callback(uri, rel):
    """
    Convert HTML URIs to absolute system paths so xhtml2pdf can access those
    resources
    """

    sUrl = settings.STATIC_URL        # Typically /static/
    sRoot = settings.STATIC_ROOT      # Typically /home/userX/project_static/
    mUrl = settings.MEDIA_URL         # Typically /media/
    mRoot = settings.MEDIA_ROOT       # Typically /home/userX/project_static/media/

    if uri.startswith(mUrl):
        path = os.path.join(mRoot, uri.replace(mUrl, ""))
    elif uri.startswith(sUrl):
        path = os.path.join(sRoot, uri.replace(sUrl, ""))
    else:
        return uri

    # make sure that file exists
    if not os.path.isfile(path):
        raise Exception(
            'media URI must start with %s or %s' % (sUrl, mUrl)
        )
    return path

I'm using Django 2.2.18 and the latest xhtml2pdf version with python 3.8

This is just strange, it should work on all platforms or not at all.

Thanks


Solution

  • I finally found the issue!

    After taking a look at how xhtml2pdf gets the file here, it turns out that for files with no path it gets the current working directory and use it, this worked for me at windows because my environment was at the project's root so the file was there, but broke at ubuntu because my environment was at a totally different location than where the project is located.

    After knowing this, the fix was simple, just return the BASE_DIR path, here is my lick_callback() after the fix

    def link_callback(uri, rel):
        """
        Convert HTML URIs to absolute system paths so xhtml2pdf can access those
        resources
        """
    
        sUrl = settings.STATIC_URL            # Typically /static/
        sRoot = settings.STATIC_ROOT          # Typically /home/userX/project_static/
        mUrl = settings.MEDIA_URL             # Typically /media/
        mRoot = settings.MEDIA_ROOT           # Typically /home/userX/project_static/media/
        bRoot = settings.BASE_DIR             # Project's base directory
    
        if uri.startswith(mUrl):
            path = os.path.join(mRoot, uri.replace(mUrl, ""))
        elif uri.startswith(sUrl):
            path = os.path.join(sRoot, uri.replace(sUrl, ""))
        else:
            return os.path.join(bRoot, '../', uri)
    
        # make sure that file exists
        if not os.path.isfile(path):
            raise Exception(
                'media URI must start with %s or %s' % (sUrl, mUrl)
            )
        return path