File

src/module/pdf/subservices/PDFGenerator.core.ts

Index

Properties
Methods

Properties

Private Readonly logger
Default value : new Logger(PDFGenerator.name)

Methods

Public Abstract generatePDF
generatePDF(options: T)

Generates a PDF from the given options.

Parameters :
Name Type Optional Description
options T No

Options from which the PDF gets generated.

Returns : Promise<Buffer>

Generated PDF as Buffer.

Protected Async generatePDFFromBodyContent
generatePDFFromBodyContent(body: string)

Generates a PDF from the given body. The body gets put in an HTML wrapper first.

Parameters :
Name Type Optional Description
body string No

Body content to be put in the PDF as HTML body.

Returns : Promise<Buffer>

Buffer containing the generated PDF.

Private Static getCustomCSS
getCustomCSS()
Returns : string

Some small customizations to the GitHub markdown CSS.

Private Async getGithubMarkdownCSS
getGithubMarkdownCSS()
Returns : Promise<string>

The GitHub markdown CSS.

Private Async getHighlightCSS
getHighlightCSS()
Returns : Promise<string>

The HighlightJS CSS.

Private Async loadCSSFile
loadCSSFile(moduleName: string)
Parameters :
Name Type Optional
moduleName string No
Returns : Promise<string>
Private Async putBodyInHTML
putBodyInHTML(body: string)

Puts the given body in corresponding a <body> element. The returned string is a complete HTML "file" with slightly customized GitHub Markdown CSS.

Parameters :
Name Type Optional Description
body string No

Body to embed in HTML.

Returns : Promise<string>

Complete HTML "file" which contains the given body as body.

import { Logger } from '@nestjs/common';
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
import { StaticSettings } from 'module/settings/settings.static';

/**
 * @param T Type of the options passed to `generatePDF`.
 */
export abstract class PDFGenerator<T = Record<string, unknown>> {
    private readonly logger = new Logger(PDFGenerator.name);

    /**
     * Generates a PDF from the given options.
     *
     * @param options Options from which the PDF gets generated.
     *
     * @returns Generated PDF as Buffer.
     */
    public abstract generatePDF(options: T): Promise<Buffer>;

    /**
     * Generates a PDF from the given body. The body gets put in an HTML wrapper first.
     *
     * @param body Body content to be put in the PDF as HTML body.
     *
     * @returns Buffer containing the generated PDF.
     */
    protected async generatePDFFromBodyContent(body: string): Promise<Buffer> {
        const html = await this.putBodyInHTML(body);
        const gotenbergConfig = StaticSettings.getService().getGotenbergConfiguration();

        try {
            const form = new FormData();
            form.append('files', html, { filename: 'index.html', contentType: 'text/html' });

            this.logger.debug('Sending request to Gotenberg for PDF generation...');

            const response = await axios.post(
                `http://${gotenbergConfig?.host}:${gotenbergConfig?.port}/forms/chromium/convert/html`,
                form,
                {
                    headers: {
                        ...form.getHeaders(),
                    },
                    timeout: gotenbergConfig?.timeout,
                    responseType: 'arraybuffer',
                }
            );

            this.logger.debug('PDF generated successfully from Gotenberg.');

            return Buffer.from(response.data);
        } catch (err) {
            this.logger.error('Failed to generate PDF:', err);
            throw err;
        }
    }

    /**
     * Puts the given body in corresponding a `<body>` element. The returned string is a complete HTML "file" with slightly customized GitHub Markdown CSS.
     *
     * @param body Body to embed in HTML.
     *
     * @returns Complete HTML "file" which contains the given `body` as body.
     */
    private async putBodyInHTML(body: string): Promise<string> {
        const githubCSS = await this.getGithubMarkdownCSS();
        const highlightCSS = await this.getHighlightCSS();

        return `
    <html>
    <head>
    <style>${githubCSS}</style>
    <style>${highlightCSS}</style>
    <style>${PDFGenerator.getCustomCSS()}</style>
    </head>
    <body class='markdown-body'>${body}</body>
    </html>
    `;
    }

    /**
     * @returns The GitHub markdown CSS.
     */
    private async getGithubMarkdownCSS(): Promise<string> {
        return this.loadCSSFile('github-markdown-css/github-markdown.css');
    }

    /**
     * @returns The HighlightJS CSS.
     */
    private async getHighlightCSS(): Promise<string> {
        return this.loadCSSFile('highlight.js/styles/googlecode.css');
    }

    private async loadCSSFile(moduleName: string): Promise<string> {
        try {
            const pathToFile = require.resolve(moduleName);
            const css = fs.readFileSync(pathToFile);

            return css.toString();
        } catch (err) {
            this.logger.error(`Could not load CSS file '${moduleName}'`);
            return '';
        }
    }

    /**
     * @returns Some small customizations to the GitHub markdown CSS.
     */
    private static getCustomCSS(): string {
        return '.markdown-body table { display: table; width: 100%; }';
    }
}

results matching ""

    No results matching ""