Search code examples
javascripttitaniumjspdf

How to get custom ttf font working with jsPDF.output()


I've added the jsPDF library to my Titanium project to generate PDFs client side, which has been working great. But now I want to localize the app for Arabic countries, which means that I have the add a custom font. This works perfectly if you use doc.save('file.pdf'), but it doesn't seem to work correctly for doc.output(). I have to use output because I'm using jsPDF outside of a browser.

To make the library work in Titanium I've had to strip all of the references to window, because it's not running in a browser or webview.

I've tried writing the file from different sources, but nothing seems to yield any results.

My current implementation:

doc = new jsPDF();

var f = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'fonts/markazi-text.regular.ttf');
var contents = f.read();
var base64font = Ti.Utils.base64encode(contents).toString();

doc.addFileToVFS("MarkaziText-Regular", base64font);
doc.addFont('MarkaziText-Regular', 'markazi-text', 'normal');

doc.setFontSize(20);

doc.setFont('markazi-text', 'normal');
doc.text('The quick brown fox jumps over the lazy dog', 20, 20);

var tempFile = Ti.Filesystem.getFile(Ti.Filesystem.getTempDirectory(), 'report.pdf');

if (tempFile.exists()) {
  tempFile.deleteFile();
}

tempFile.write(doc.output());

I've also tried to write the file from a blob:

var reader = new FileReader();
reader.onloadend = function () {
  tempFile.write(reader.result);
};
reader.readAsText(getBlob(buildDocument()));

But the pdf is empty if I use this. I've also tried the library in a webview within a titanium application, which does work but I don't really want to go that road. It would require too many changes to the code.

Expected:

1

Actual: 1


Solution

  • I've finally resolved it by creating a local HTML file. In this HTML file I've loaded jsPDF and my own JavaScript to generate a PDF file. I've loaded this HTML file in a WebView.

    I'm generating all the data needed for the PDF in an Alloy controller. I'm sending this data to my WebView JavaScript by firing an app event and catching it in the WebView.

    After the PDF is created I trigger an app event in the WebView that contains the base64 data of the jsPDF doc:

    Ti.App.fireEvent('app:pdfdone', {
      output: doc.output('dataurlstring').replace("data:application/pdf;filename=generated.pdf;base64,", "")
    });
    

    I finally save this as a file in the Alloy controller:

    var f = Ti.Filesystem.getFile(Ti.Filesystem.getTempDirectory(), 'doc.pdf');
    f.write(Ti.Utils.base64decode(e.output));