Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fonts in PDF exported using WeasyPrint inside docker (FastAPI)

I have an application that runs inside a docker container. The service is written with the FastAPI framework and is used to produce reports. We first generate an HTML report, which is then converted to PDF using the Weasyprint library. When I execute it on my laptop (I am using Manjaro Linux) everything works perfectly. But, when I use the API from within the docker container, I noticed that the font is different in the produced PDF. In the CSS file, we use font-family Helvetica, sans-serif. So, when the report is produced inside the container, the sans-serif does not work.

Moreover, I have copied my fonts folder (from my laptop) inside the docker container to check if it has some font missing; however, sans-serif still does not work.

This is my Dockerfile:

FROM tiangolo/uvicorn-gunicorn-fastapi

RUN apt-get update && apt-get install -y build-essential unzip vim git curl locales orca
RUN apt install -y python3-cffi libcairo2 libcairo2-dev libpango-1.0-0 libpango1.0-dev libpangocairo-1.0-0 libgdk-pixbuf2.0-0 \
                   libgdk-pixbuf2.0-dev libffi-dev shared-mime-info libffi-dev fonts-font-awesome

RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

ARG RELEASE=main
RUN git clone <my_repo>
RUN cd ./<repo> && pip install -r requirements.txt

EXPOSE 80
WORKDIR /app/<repo>/app

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4"]

And the python libraries which I install (in the requirements.txt):

numpy==1.20.3
pandas==1.2.4
plotly==4.14.3
kaleido==0.2.1
weasyprint==52.5
Jinja2==3.0.1
fastapi==0.65.2
uvicorn==0.14.0
pydantic==1.8.2
psutil==5.8.0
python-multipart==0.0.5
aiofiles==0.7.0
SQLAlchemy==1.4.22
async-exit-stack==1.0.1
async-generator==1.10
mysqlclient==2.0.3

Since I can produce it just fine on my laptop, I assume that either some library is missing (I have tried to install fonts-open-sans and libglib2.0-dev as well, but nothing changed) or that there is a problem with some version. For example, I checked the WeasyPrint documentation, that pango should be 1.44.0 version or higher, while in Debian 10 (which is the OS in the docker) the package libpango-1.0-0 uses pango 1.42.0 version. Could this be the problem with why sans-serif does not work or any ideas on what am I missing?

like image 865
sthemeli Avatar asked Oct 24 '25 04:10

sthemeli


1 Answers

Ok, I did some work for you ;)

I built image and start docker container by using:

FROM tiangolo/uvicorn-gunicorn-fastapi

RUN apt-get update && apt-get install -y build-essential unzip vim git curl locales orca
RUN apt install -y python3-cffi libcairo2 libcairo2-dev libpango-1.0-0 libpango1.0-dev libpangocairo-1.0-0 libgdk-pixbuf2.0-0 \
                   libgdk-pixbuf2.0-dev libffi-dev shared-mime-info libffi-dev fonts-font-awesome

RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
    locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

COPY app.py .
COPY template .
COPY requirements.txt .
RUN pip install -r requirements.txt

EXPOSE 80

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4"]

where requirements.txt same as yours, template is directly copied from here.

And app.py is

from fastapi import FastAPI
from fastapi.responses import HTMLResponse, Response
from weasyprint import HTML


app = FastAPI(title="name")

@app.get("/", response_class=HTMLResponse)
async def read_root():
    with open('template', 'r') as f:
       contents = f.read()

    return contents

@app.get("/pdf")
async def read_root_pdf():
    with open('template', 'r') as f:
       contents = f.read()
    
    pdf_content = HTML(string=contents).write_pdf()

    return Response(content=pdf_content, media_type="application/pdf")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('app:app', host="0.0.0.0", port=80)

As you can see below (I renamed pdf into png to be able attach) all fonts are different. Here is no problem in your container.

enter image description here

like image 92
rzlvmp Avatar answered Oct 26 '25 19:10

rzlvmp