bpampuch / pdfmake

Client/server side PDF printing in pure JavaScript
http://pdfmake.org
Other
11.7k stars 2.04k forks source link

How to add fonts dynamically? #1516

Closed manu-st closed 6 years ago

manu-st commented 6 years ago

Hi,

I'm looking into using pdfMake and one of the requirement is that I'll be able to use any fonts installed on my OS (currently Windows). Is this possible? What I've read seems to indicate we should be building the fonts into the vfs_fonts.js file before hand which is not what I'd like since each computer is most likely to have a different set of fonts.

Any advice? Thanks!

liborm85 commented 6 years ago

If you are using pdfmake on server-side, it is possible. See basic example, in variable fonts is defined font files available on computer, you can define any fonts from your computer.

If you are using pdfmake on client-side (in browser) it is not possible, because browser has no access to computer file system.

manu-st commented 6 years ago

I'm on the server-side using Electron. I've tried to create the fonts object that lists all the available fonts in my system, however at runtime it is still trying to find them in the virtual file system and it gives me this exception throw 'File \'' + filename + '\' not found in virtual file system';. Is there a way to bypass this so it uses the fonts I provided?

The code I have is the following in TypeScript:

import * as pdfBuilder from "pdfmake/build/pdfmake";
...
// Load the set of fonts we want to use:
const pdfBuilderLocal = pdfBuilder;
pdfBuilderLocal.fonts =  Fonts.PDF_FONTS;
...
// Build the PDF
const pdf = pdfBuilder.createPdf (dd);
pdf.print ();

It fails when calling pdf.print ().

Usually path to the fonts are like "C:\WINDOWS\FONTS\ARIALBD.TTF".

liborm85 commented 6 years ago

As I wrote above, this is supported only on server-side. See server-side example, here you can use fonts from system file.

But you are using client-side code and here is not supported loading fonts from files by browsers/javascript reasons.

manu-st commented 6 years ago

Could you clarify what you mean by I'm using client-side when I'm running the code on the server-side? Is it because of the way I'm including the library? I did it this way because of the TypeScript definition only knows about "pdmake/build/pdfmake".

liborm85 commented 6 years ago

Are two ways how to use pdfmake in javascript:

1. server-side code

Example:

var fonts = {
    Roboto: {
        normal: 'fonts/Roboto-Regular.ttf',
        bold: 'fonts/Roboto-Medium.ttf',
        italics: 'fonts/Roboto-Italic.ttf',
        bolditalics: 'fonts/Roboto-MediumItalic.ttf'
    }
};
var PdfPrinter = require('pdfmake');
var printer = new PdfPrinter(fonts);

var docDefinition = {
    content: [
        'First paragraph',
        'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
    ]
};

var pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.pipe(require('fs').createWriteStream('outputDocument.pdf')); // or something else with pdf stream
pdfDoc.end();

This method allows you to access the file system directly (to obtain font files). This can not be runned in the browser.

2. client-side code (/ in browser)

Example:

var pdfMake = require('pdfmake/build/pdfmake.js');
var pdfFonts = require('pdfmake/build/vfs_fonts.js');
pdfMake.vfs = pdfFonts.pdfMake.vfs;

var docDefinition = {
    content: [
        'First paragraph',
        'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
    ]
};
pdfMake.createPdf(docDefinition).getBase64((data) => {
   // ...
});

This method allow run pdfmake in browser, because is used "virtual file system" (from vfs_fonts.js file) and all files must by in this vfs file. Not possible access to computer file system. Of course, this "client-side" code can also be run on the server-side but only with this virtual file system (access to real computer file system is not possible).


Which method you use depends on you, everyone has its advantages and disadvantages. If you work on the server side (without browser), use first method and you can use computer file system. But if you have browser is needed use second method which used only virtual file system.

I don't know much about typescript. Pdfmake library allows works with this "two ways" and is writened in javascript and how to call in typescript i don't know. But typescript is ecmascript compatible so it should be possible (same as javascript/ecmascript).

manu-st commented 6 years ago

Thanks for the clarification. I managed to get the code to work. I was difficult to provide a type definition for the library so it would integrate nicely in the library, instead I build my own types (see https://gist.github.com/manu-st/fcf925e389f352162a931a1089e01918).