blikblum/pdfmake-utils

Dynamical load of standard fonts for pdf creation?

Rotzbua opened this issue · 5 comments

Hi,

is it possible to add standard fonts dynamically for pdf creation? (Browser)

I tested following script but it does not work:

assetsLoader.registerFont({
    name: 'Courier',
    fileName: 'Courier',
    URL: 'assets/font/data/Courier.afm',
    styles: ['normal']
});

Error:

ERROR Error: "File '../font/data/Courier.afm' not found in virtual file system"

It seems that the standard font are only stored in pdfMake.rawFiles and not processed further on.

Sorry for late response.
Standard fonts are working fine. See this project. Times is a standard font.

Are you using pdfmake-lite?

Can you share a small example that shows the fail?

Probably you should be doing the following:

assetsLoader.load().then(() => {
        pdfMake.vfs = assetsLoader.vfs;
        pdfMake.fonts = assetsLoader.fonts;
        if (pdfMake.fs) {
          assetsLoader.rawFiles.forEach(file => {
            pdfMake.fs.writeFileSync(file.name, file.data);
          });
       }
})

You may be asking why:

  • pdfmake expects that the vfs property be a buffer or a base64 encoded that is converted to a buffer, but pdfkit expects the standard font data to not be encoded
  • by using pdfMake.fs.writeFileSync we bypass this conversion

I released a new version and updated docs. Reopen if still having problems

Standard fonts are working fine. See this project. Times is a standard font.

Sorry I did not get your example project working.

Are you using pdfmake-lite?

I used normal pdfmake but also tested with lite version. No difference.

pdfmake expects that the vfs property be a buffer or a base64 encoded that is converted to a buffer, but pdfkit expects the standard font data to not be encoded

I am sorry, I made a mistake 😿 . I forgot that I also made some (debugging style) changes in the pdfmake so my pr is wrong.

Thanks for your support. Nice to have a simple assetsLoader.configurePdfMake 👍 .


After some research I figured out that the main problem is that the virtual file system adapter for the browser does not implement all required functionalities.

pdfmake load the standard font by following code:

   STANDARD_FONTS = {
      "Courier": function() {
        return fs.readFileSync(__dirname + "/../font/data/Courier.afm", 'utf8');
      },

fs.readFileSync("path") returns a buffer while fs.readFileSync("path", 'utf8') returns a string.
But the browser adapter only implements fs.readFileSync("path") so it returns a buffer and the AFMFont.parse fails.

So a solution with only using vfs would be:

pdfmake-lite/src/browser-extensions/virtual-fs.js

VirtualFileSystem.prototype.readFileSync = function (filename, option) {
  filename = fixFilename(filename);
  var dataContent = this.dataSystem[filename];

  var dataContent = this.dataSystem[filename];
  if (typeof dataContent === 'string' && option === 'utf8')
    return dataContent;
    
  if (dataContent) {
     return new Buffer(dataContent, typeof dataContent === 'string' ? 'base64' : undefined);
  }
[...]
}

pdf-utils.js

  storeFileData(fileName, data, raw) {
    if (raw) {
      this.rawFiles.push({
        name: fileName,
        data: data
      });
      this.vfs[fileName] = data;
    } else {
      this.vfs[fileName] = data;
    }
  }

Best

You can create a PR to pdfMake