mattstuehler
mattstuehler

Reputation: 9292

Is it possible to use custom Google web fonts with jsPDF

I'm using jsPDF (https://parall.ax/products/jspdf, https://github.com/MrRio/jsPDF) to produce dynamic PDFs in a web application.

It works well, but I'd like to figure out whether it's possible to use Google web fonts in the resulting PDF.

I've found a variety of links that are related to this question (including other questions on SO), but most are out of date, and nothing looks definitive, so I'm hoping someone clarify whether/how this would work.

Here's what I've tried so far, with no success:

First, load the font, and cache it as a base64-encoded string:

var arimoBase64;
var request = new XMLHttpRequest()
request.open('GET', './fonts/Arimo-Regular.ttf');
request.responseType = 'blob';
request.onload = function() {
    var reader = new FileReader();
    reader.onloadend = function() {
        arimoBase64 = this.result.split(',')[1];
    }
    reader.readAsDataURL(this.response);
};
request.send()

Next, create the pdf doc:

doc = new jsPDF({
    orientation: "landscape",
    unit: "pt", 
    format: "letter"
});

doc.addFileToVFS("Arimo-Regular.ttf", arimoBase64);
doc.addFont("Arimo-Regular.ttf", "Arimo Regular", "normal");

doc.setFont("Arimo Regular", "normal");

doc.text("Hello, World!", 100, 100);
doc.save("customFontTest");

When the PDF is saved - if I view it in my browser - I can see the custom font. However - if I view it using Adobe Reader or the Mac Preview app - the fonts are not visible.

I assume that's because the font is rendered in the browser using the browser's font cache, but the font is not actually embedded in the PDF, which is why it's not visible using Adobe Reader.

So - is there a way to accomplish what I'm trying to do?

Upvotes: 8

Views: 12902

Answers (3)

buzz
buzz

Reputation: 302

Just wanted to add an updated answer - for version 1.5.3:

Convert the font file to base64 = https://www.giftofspeed.com/base64-encoder/

const yanone = "AAWW...DSES"; // base64 string
doc.addFileToVFS('YanoneKaffeesatz-Medium.ttf', yanone);
doc.addFont('YanoneKaffeesatz-Medium.ttf', 'YanoneKaffeesatz', 'normal');
doc.setFont('YanoneKaffeesatz');      

Upvotes: 4

Tom Mertz
Tom Mertz

Reputation: 696

I recently ran into this same issue, but it looks like the jsPDF-CustomFonts-support repo was rolled into MrRio's jsPDF repository, so you no longer need it to get this working.

I happen to be using it in a React App and did the following:

  1. npm install jspdf
  2. Create a new file fonts/index.js (Note: You can download the Google Font as a .ttf and turn it into the Base64 encoded string using the tool in mattstuehler's answer)
export const PlexFont = "[BASE64 Encoded String here]";
  1. Import that file where you need it:
import jsPDF from 'jspdf';
import { PlexFont } from '../fonts';

// Other Reacty things...

exportPDF = () => {

  const doc = new jsPDF();
  doc.addFileToVFS('IBMPlexSans-Bold.ttf', PlexBold);
  doc.addFont('IBMPlexSans-Bold.ttf', 'PlexBold', 'normal')
  doc.setFont('PlexBold');
  doc.text("Some Text with Google Fonts", 0, 0);

  // Save PDF...
}

// ...

Upvotes: 12

mattstuehler
mattstuehler

Reputation: 9292

OK - I finally figured it out, and have gotten it to work. In case this is useful for anyone else - here is the solution I'm using...

First - you need two libraries:

  1. jsPDF: https://github.com/MrRio/jsPDF
  2. jsPDF-CustomFonts-support: https://github.com/sphilee/jsPDF-CustomFonts-support

Next - the second library requires that you provide it with at least one custom font in a file named default_vfs.js.

That file should look like this:

(function (jsPDFAPI) { 
    "use strict";
    jsPDFAPI.addFileToVFS("[Your font's name]","[Base64-encoded string of your font]");
})(jsPDF.API);

I'm using two custom fonts - Arimo-Regular.ttf and Arimo-Bold.ttf - both from Google Fonts. So, my default_vfs.js file looks like this:

(function (jsPDFAPI) { 
    "use strict";
    jsPDFAPI.addFileToVFS("Arimo-Regular.ttf","[Base64-encoded string of your font]");
    jsPDFAPI.addFileToVFS("Arimo-Bold.ttf","[Base64-encoded string of your font]");
})(jsPDF.API);

There's a bunch of ways to get the Base64-encoded string for your font, but I used this: https://www.giftofspeed.com/base64-encoder/.

It lets you upload a font .ttf file, and it'll give you the Base64 string that you can paste into default_vfs.js.

You can see what the actual file looks like, with my fonts, here: https://cdn.rawgit.com/stuehler/jsPDF-CustomFonts-support/master/dist/default_vfs.js

So, once your fonts are stored in that file, your HTML should look like this:

    <script src="js/jspdf.min.js"></script>
    <script src="js/jspdf.customfonts.min.js"></script>
    <script src="js/default_vfs.js"></script>

Finally, your JavaScript code looks something like this:

const doc = new jsPDF({
      unit: 'pt'
    });

doc.addFont("Arimo-Regular.ttf", "Arimo", "normal");
doc.addFont("Arimo-Bold.ttf", "Arimo", "bold");

doc.setFont("Arimo");
doc.setFontType("normal");
doc.setFontSize(28);

doc.text("Hello, World!", 100, 100);

doc.setFontType("bold");

doc.text("Hello, BOLD World!", 100, 150);

doc.save("customFonts.pdf");

This is probably obvious to most, but in that addFont() method, the three parameters are:

  1. The font's name you used in the addFileToVFS() function in the default_vfs.js file
  2. The font's name you use in the setFont() function in your JavaScript
  3. The font's style you use in the setFontType() function in your JavaScript

You can see this working here: https://codepen.io/stuehler/pen/pZMdKo

Hope this works as well for you as it did for me.

Upvotes: 11

Related Questions