Skip to content
Advertisement

Non-ASCII characters are not correctly displayed in PDF when served via HttpResponse and AJAX

I have generated a PDF file which contains Cyrillic characters (non-ASCII) with ReportLab. For this purpose I have used the “Montserrat” font, which support such characters. When I look in the generated PDF file inside the media folder of Django, the characters are correctly displayed:

enter image description here

I have embedded the font by using the following code in the function generating the PDF:

JavaScript

However, when I try to serve this PDF via HttpResponse, the Cyrillic characters are not properly displayed, despite being displayed in the Montserrat font:

enter image description here

The code that serves the PDF is the following:

JavaScript

I have tried nearly everything (using FileResponse, opening the PDF with with open(fs.location + "/" + filename, 'rb') as pdf…) without success. Actually, I do not understand why, if ReportLab embeddes correctly the font (local file inside media folder), the file provided to the browser is not embedding the font.

It is also interesting to note that I have used Foxit Reader via Chrome or Edge to read the PDF. When I use the default PDF viewer of Firefox, different erroneous characters are displayed. Actually the font seems to be also erroneous in that case:

enter image description here

Edit

Thanks to @Melvyn, I have realized that the error did not lay in the response directly sent from the Python view, but in the success code in the AJAX call, which I leave hereafter:

JavaScript

This is the part of the code that is changing somehow the encoding.

Solution with the ideas from comments

I finally come up with a solution thanks to all the comments I have received, specially from @Melvyn. Instead of creating a Blob object, I have just set the responseType of the AJAX to Blob type. This is possible since JQuery 3:

JavaScript

Handling an error when returning response

You can return an error from Python (i.e. catching an exception) as follows:

JavaScript

Then, you just have to use the native error handling from AJAX (after the success section):

JavaScript

See further details in this link.

I hope this post helps people with the same problem while generating PDFs in non-ASCII (Cyrillic) characters. It took me several days…

Advertisement

Answer

You are doing some encoding/recoding, because if you look at the diff between the files, it’s littered with unicode replacement characters:

JavaScript

You said you tried without setting the encoding and charset, but I don’t think that was tested properly – most likely you saw an aggressively browser-cached version.

The proper way to do this is to use FileResponse, pass in the filename and let Django figure out the right content type.

The following is a reproducible test of a working situation:

First of all, put Cyrillic_good.pdf (not wrong.pdf), in your media root.

Add the following to urls.py:

JavaScript

And views.py in the same directory:

JavaScript

Now start runserver and request http://localhost:8000/pdf/Cyrillic_good.pdf.

If this doesn’t reproduce a valid pdf, it is a local problem and you should look at middleware or your OS or little green men, but not the code. I have this working locally with your file and no mangling is happening.

In fact, the only way to get a mangled pdf now is browser cache or response being modified after Django sends it, since the content length check would prevent sending a file that has different size then the one on disk.

JS Part

I would expect the conversion to happen in the blob constructor as it’s possible to hand a blob a type. I’m not sure the default is binary-safe. It’s also weird your data has an error property and you pass the entire thing to the blob, but we can’t see what promise you’re reacting on.
JavaScript
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement