Search code examples
javascriptreactjsflaskpython-3.6python-pdfkit

PDF images blurry when download as PDF in production with pdfkit python


I'm using pdfkit library to convert Html to pdf and after convert pdf then converted it in base64(String) and send it to as API response. In front-end (React) received base64(String) and create an element with base64(String) for download as pdf. But after download pdf, all images are going to blurry.

Html to Pdf converter ApiClass:

class BasicTutorCVPDF(Resource):
@staticmethod
@is_user_authenticate()
def get(_id):
    try:
        context = TutorModel.profile_info(_id)
        html = render_template("tutorCVPDF.html", context=context)

        options = {
            'page-size': 'A4',
            'margin-top': '0.75in',
            'margin-right': '0.75in',
            'margin-bottom': '0.75in',
            'margin-left': '0.75in',
        }
        pdfkit.from_string(html, 'public/pdf/tutor_cv.pdf', options=options)
        with open("public/pdf/tutor_cv.pdf", "rb") as file:
            encode_string = base64.b64encode(file.read())

        data = str(encode_string).split("'")[1]

        return (ResService.success(None, data), ResService.success(None, data)['status']) if data else \
            (ResService.not_acceptable(), ResService.not_acceptable()['status'])
    except Exception as err:
        LOG.report(err)
        return ResService.bad_request(), ResService.bad_request()['status']

Html Template:

<tr>
    <td style="text-align: left; width: 280px;">Tutor ID : </td>
    <td>{{ context['user_info']['id'] }}</td>
    <td rowspan="5" style="text-align: right;"><img src="{{ context['user_info']['photo'] }}" style="height: 160px; width: 160px;" alt=""></td>
</tr>

Receive Base64(String) in front-end:

export const fetchTutorCVPDF = (tutorId) => dispatch => {
    req.getRequest({
        url: Constants.STATIC + 'tutor-cv-pdf/' + tutorId, auth: 'bearer', }, (cb) => {
        const linkSource = `data:application/pdf;base64,${cb}`;
        const downloadLink = document.createElement("a");
        const fileName = "cv_" + tutorId + ".pdf";

        downloadLink.href = linkSource;
        downloadLink.download = fileName;
        downloadLink.click();
    })
};

Downloaded PDF:

enter image description here


Solution

  • I used the code snippets to recreate the same issue.

    It actually worked well, without any blur

    Controller:

    @app.route('/')
    def hello_world():
        pdffile_content = render_template('template.html')
        options = {
            'page-size': 'A4',
            'margin-top': '0.75in',
            'margin-right': '0.75in',
            'margin-bottom': '0.75in',
            'margin-left': '0.75in',
        }
        pdfkit.from_string(pdffile_content, 'tutor_cv.pdf', options=options)
        with open("tutor_cv.pdf", 'rb') as file:
            encoded = base64.b64encode(file.read())
        data = str(encoded).split("'")[1]
        return data, 200
    

    Template:

    <tr>
        <td style="text-align: left; width: 280px;">Tutor ID : </td>
        <td>123123123123</td>
        <td rowspan="5" style="text-align: right;"><img src="https://cdn130.picsart.com/286240699000211.png?r1024x1024" style="height: 160px; width: 160px;" alt=""></td>
    </tr>
    

    JS code:

    fetch('/').then((result) => result.text()).then(function(result){
        const linkSource = `data:application/pdf;base64,${result}`;
        const downloadLink = document.createElement("a");
        const fileName = "cv.pdf";
    
        downloadLink.href = linkSource;
        downloadLink.download = fileName;
        downloadLink.click();
    })
    

    Result Image

    I think the main problem is not with pdfkit at all, I think the original CV template (not the one in the question) has some css styling that are causing this to happen.