import puppeteer, { Browser } from "puppeteer"; import { TemplateHelper } from "./templateHelper"; import { PermissionModule } from "../type/permissionTypes"; import { FileSystemHelper } from "./fileSystemHelper"; import { PDFDocument } from "pdf-lib"; import { StringHelper } from "./stringHelper"; export abstract class PdfExport { private static browserInstance: undefined | Browser = undefined; private static timeout: undefined | NodeJS.Timeout = undefined; private static printing = new Map(); private static async renderTemplate( template: `${PermissionModule}` | `${PermissionModule}.${string}`, title: string, data: any, customTemplate?: { headerId?: number; footerId?: number; bodyId?: string | number; headerHeight: number; footerHeight: number; } ): Promise<{ header: string; footer: string; body: string; headerMargin?: number; footerMargin?: number }> { if (!customTemplate) { return await TemplateHelper.renderFileForModule({ module: template, headerData: data, bodyData: data, footerData: data, title: title, }); } else { return await TemplateHelper.renderFileForCustom({ module: template, customTemplate, headerData: data, bodyData: data, footerData: data, title: title, }); } } static async renderFile({ template, title = "pdf-export FF Admin", filename = null, data = {}, saveToDisk = true, folder = "", customTemplate = undefined, }: { template: `${PermissionModule}` | `${PermissionModule}.${string}`; title?: string; filename?: string; data?: any; saveToDisk?: boolean; folder?: string; customTemplate?: { headerId?: number; footerId?: number; bodyId?: string | number; headerHeight: number; footerHeight: number; }; }) { try { clearTimeout(this.timeout); } catch (err) {} let id = StringHelper.random(32); this.printing.set(id, "printing"); if (folder != "") FileSystemHelper.createFolder(folder); const renderedTemplate = await this.renderTemplate(template, title, data, customTemplate); let { header, footer, body, headerMargin, footerMargin } = renderedTemplate; if (!this.browserInstance || !this.browserInstance.connected) { this.browserInstance = await puppeteer.launch({ headless: true, args: ["--no-sandbox", "--disable-gpu", "--disable-setuid-sandbox"], }); } const page = await this.browserInstance.newPage(); await page.setContent(body, { waitUntil: "domcontentloaded" }); const exportPath = FileSystemHelper.formatPath(folder, `${filename}.pdf`); let pdf = await page.pdf({ ...(saveToDisk ? { path: exportPath } : {}), format: "A4", printBackground: false, margin: { top: (headerMargin ?? 15) + "mm", bottom: (footerMargin ?? 15) + "mm", left: "10mm", right: "10mm", }, displayHeaderFooter: true, headerTemplate: header, footerTemplate: footer, }); await page.close(); this.printing.delete(id); if (this.printing.size == 0) { this.timeout = setTimeout(() => { this.browserInstance.close(); this.browserInstance = undefined; }, 5000); } return pdf; } static async sqashToSingleFile(inputFolder: string, outputFile: string, outputFolder: string = "") { if (outputFolder != "") FileSystemHelper.createFolder(outputFolder); let pdfFilePaths = FileSystemHelper.getFilesInDirectory(inputFolder, ".pdf"); if (pdfFilePaths.length == 0) return; const mergedPdf = await PDFDocument.create(); for (const pdfPath of pdfFilePaths) { const pdfBytes = FileSystemHelper.readFileasBase64(inputFolder, pdfPath); const pdf = await PDFDocument.load(pdfBytes); const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices()); copiedPages.forEach((page) => mergedPdf.addPage(page)); } const mergedPdfBytes = await mergedPdf.save(); FileSystemHelper.writeFile(outputFolder, `${outputFile}.pdf`, mergedPdfBytes); } }