ff-admin-server/src/helpers/pdfExport.ts

140 lines
4.1 KiB
TypeScript

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<string, string>();
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);
}
}