Reputation: 927
xhtml2pdf works fine to generate a simple PDF on App Engine.
But now I need to add a custom font in the generated PDF, and I don't seem to find an easy solution to do this.
I added this CSS to the HTML to convert to PDF:
@font-face {
font-family: OpenSans;
src: url("http://mydomain/fonts/Open-Sans-regular.ttf");
}
body {
font-family: OpenSans;
}
Which yields this error:
File "[..]/xhtml2pdf/util.py", line 613, in getNamedFile
self.tmp_file = tempfile.NamedTemporaryFile()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/dist/tempfile.py", line 61, in PlaceHolder
raise NotImplementedError("Only tempfile.TemporaryFile is available for use")
NotImplementedError: Only tempfile.TemporaryFile is available for use
tempfile
is not supported by GAE, so I have tried to replace tempfile.NamedTemporaryFile()
by creating a temporary file in GCS like this:
self.tmp_file = gcs.open('/gcs_bucket_temp/temp_file',
'w',
retry_params=gcs.RetryParams(backoff_factor=1.1))
but that creates breaking changes that are difficult to fix: xhtml2pdf makes a lot of read accesses to the tempfile in ttfonts.py
(e.g. ttfonts.py:321 unpack('>L',self._ttf_data[self._pos - 4:self._pos])[0]
), which seems difficult to migrate over to work with a GCS file.
Has anyone been able to generate PDFs using xhtml2pdf on App Engine, with custom fonts?
Upvotes: 0
Views: 1946
Reputation: 927
Here are the changes to xhtml2pdf library I had to make to allow custom @font-face support on App Engine. Basically using GCS to store the tempfile instead of the file system.
In ttfonts.py:239
, replace:
self.filename, f = TTFOpenFile(f)
self._ttf_data = f.read()
by:
self.filename = f
gcs_file = gcs.open(f) #, 'w', retry_params=gcs.RetryParams(backoff_factor=1.1))
self._ttf_data = gcs_file.read()
gcs_file.close()
In util.py:608
, replace:
self.tmp_file = tempfile.NamedTemporaryFile()
if self.file:
shutil.copyfileobj(self.file, self.tmp_file)
else:
self.tmp_file.write(self.getData())
self.tmp_file.flush()
return self.tmp_file
by:
filename = '/%s/temp_file'%gcs_bucket
self.tmp_file = gcs.open(filename, 'w', retry_params=gcs.RetryParams(backoff_factor=1.1))
if self.file:
self.tmp_file.write(self.file._fetch_response.content)
else:
self.tmp_file.write(self.getData())
self.tmp_file.close()
return filename
This seems to do the trick. Custom fonts appear well in the generated PDFs now.
Upvotes: 3