font.js

const fs = require('fs');
const path = require('path');
/**
 * Register a custom font
 * @name registerFont
 * @function
 * @memberof Recipe
 * @param {string} fontName - The font name will be used in text
 * @param {string} fontSrcPath - The path to the font file.
 * @param {string} [type='regular'] - The font type, one of 'bold', 'bold-italic', 'italic'
 */
exports.registerFont = function registerFont(fontName = '', fontSrcPath = '', type = 'regular') {
    return this._registerFont(fontName, fontSrcPath, type);
};

exports._loadFonts = function _loadFonts(fontSrcPath) {
    const fontTypes = ['.ttf', '.ttc', '.otf'];
    const fontPaths = (typeof fontSrcPath === 'string') ? [fontSrcPath] : fontSrcPath;

    for (let fpath of fontPaths) {
        if (fs.existsSync(fpath)) {  // only process when directory exists
            fs
                .readdirSync(fpath)
                .filter((file) => {
                    return fontTypes.includes(path.extname(file).toLowerCase());
                })
                .forEach((file) => {
                    let fontName = path.basename(file, path.extname(file)).toLowerCase();
                    // simple heuristics to make sure library fonts behave as expected
                    const hasBold   = (fontName.indexOf('bold')   !== -1);
                    const hasItalic = (fontName.indexOf('italic') !== -1);
                    let type = 'r';
                    if (hasBold&&hasItalic) {
                        fontName = fontName.replace(/-*bold/,'');
                        fontName = fontName.replace(/-*italic/,'');
                        type = 'bi';
                    } else if (hasBold) {
                        fontName = fontName.replace(/-*bold/,'');
                        type = 'b';
                    } else if (hasItalic) {
                        fontName = fontName.replace(/-*italic/,'');
                        type = 'i';
                    }
                    return this._registerFont(fontName, path.join(fpath, file), type);
                });
        }
    }
};

exports._registerFont = function _registerFont(fontName, fontSrcPath, type = 'regular') {
    this.fonts = this.fonts || {};
    let family = fontName.toLowerCase();
    let font = this.fonts[family] || {};

    switch (type) {
        default:
            font.r = fontSrcPath;
            break;
        case 'bold':
        case 'b':
            font.b = fontSrcPath;
            break;
        case 'italic':
        case 'i':
            font.i = fontSrcPath;
            break;
        case 'bold-italic':
        case 'bi':
            font.bi = fontSrcPath;
            break;

    }
    this.fonts[family] = font;
};

function _getFontFile(self, options = {}) {
    let fontFile;
    // Need to choose appropriate file based on bold/italic considerations
    // Note, if this is not done explicitly, the font dimensions will be incorrect.
    let type =
           ((options.bold   || options.isBold) && (options.italic || options.isItalic)) ? 'bi' :
               (options.italic || options.isItalic) ? 'i' :
                   (options.bold   || options.isBold)   ? 'b' : 'r';

    if (options.font) {
        const fontFamily = self.fonts[options.font.toLowerCase()];
        if (fontFamily) {
            fontFile = fontFamily[type];
        }
    }

    // when file inaccessible ...
    if (!fontFile || !fs.existsSync(fontFile)) {
        fontFile = self.fonts['helvetica'][type];  // use default font when otherwise unavailable.
    }

    if (!fontFile) {
        fontFile = self.fonts['helvetica']['r'];  // use default font when otherwise unavailable.
    }

    return fontFile;
}

exports._getFont = function _getFont(options) {
    this.current = this.current || {};

    const fontFile = _getFontFile(this, options);

    if ( !this.current[fontFile] ) {
        this.current[fontFile] = this.writer.getFontForFile(fontFile);
    }

    return this.current[fontFile];
};