145 lines
4.6 KiB
JavaScript
145 lines
4.6 KiB
JavaScript
async function generateA4PDF(htmlContent, outputPDF) {
|
|
let browser = null;
|
|
|
|
try {
|
|
console.log("🚀 Starting PDF generation...");
|
|
|
|
// Launch browser
|
|
browser = await puppeteer.launch({
|
|
headless: true,
|
|
args: [
|
|
'--no-sandbox',
|
|
'--disable-setuid-sandbox',
|
|
'--disable-dev-shm-usage',
|
|
'--disable-accelerated-2d-canvas',
|
|
'--no-first-run',
|
|
'--no-zygote',
|
|
'--disable-gpu'
|
|
]
|
|
});
|
|
|
|
const page = await browser.newPage();
|
|
|
|
// Set viewport to A4 dimensions (210mm x 297mm = 794px x 1123px at 96 DPI)
|
|
await page.setViewport({ width: 794, height: 1123 });
|
|
page.setDefaultTimeout(0); // Infinite timeout
|
|
|
|
// Inject CSS to fix white spaces and page breaks
|
|
const improvedHTML = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
line-height: 1.4;
|
|
color: #333;
|
|
background: white;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
@page {
|
|
size: A4;
|
|
margin: 0.25in;
|
|
}
|
|
.page-break {
|
|
page-break-before: always;
|
|
}
|
|
.no-break {
|
|
page-break-inside: avoid;
|
|
}
|
|
img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
display: block;
|
|
}
|
|
table {
|
|
page-break-inside: avoid;
|
|
width: 100%;
|
|
}
|
|
h1, h2, h3, h4, h5, h6 {
|
|
page-break-after: avoid;
|
|
margin-top: 0.5em;
|
|
margin-bottom: 0.3em;
|
|
}
|
|
p {
|
|
margin-bottom: 0.5em;
|
|
orphans: 2;
|
|
widows: 2;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
${htmlContent.replace(/<body[^>]*>|<\/body>/gi, '')}
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
// Set content with improved HTML
|
|
await page.setContent(improvedHTML, {
|
|
waitUntil: 'networkidle0',
|
|
timeout: 0 // Infinite timeout
|
|
});
|
|
|
|
// Wait for content to load completely
|
|
await page.waitForTimeout(2000); // Wait 2 seconds for content to settle
|
|
|
|
// Wait for all resources to load
|
|
try {
|
|
await page.waitForNetworkIdle({ timeout: 0 });
|
|
} catch (error) {
|
|
// Ignore timeout errors for networkidle
|
|
}
|
|
|
|
console.log("📄 Generating A4 PDF...");
|
|
|
|
const pdfOptions = {
|
|
path: outputPDF,
|
|
printBackground: true,
|
|
margin: {
|
|
top: '0.25in',
|
|
right: '0.25in',
|
|
bottom: '0.25in',
|
|
left: '0.25in'
|
|
},
|
|
scale: 1.0,
|
|
format: 'A4',
|
|
preferCSSPageSize: false,
|
|
displayHeaderFooter: false,
|
|
omitBackground: false
|
|
};
|
|
|
|
// Generate PDF
|
|
await page.pdf(pdfOptions);
|
|
await browser.close();
|
|
|
|
// Get PDF file size for logging (no size restriction for download links)
|
|
const pdfStats = fs.statSync(outputPDF);
|
|
const pdfSizeMB = pdfStats.size / (1024 * 1024);
|
|
|
|
console.log(`✅ A4 PDF generated: ${outputPDF}`);
|
|
console.log(`📐 Format: A4 (210mm x 297mm)`);
|
|
console.log(`📏 Margins: 0.25in all sides`);
|
|
console.log(`🔍 Scale: 1.0`);
|
|
console.log(`📊 File size: ${pdfSizeMB.toFixed(2)} MB`);
|
|
|
|
} catch (error) {
|
|
if (error.name === 'TimeoutError') {
|
|
throw new Error("Timeout: Page took too long to load.");
|
|
}
|
|
console.error(`❌ PDF generation error: ${error.message}`);
|
|
throw error;
|
|
} finally {
|
|
// Cleanup
|
|
if (browser) {
|
|
try {
|
|
await browser.close();
|
|
} catch (error) {
|
|
console.error('Error closing browser:', error);
|
|
}
|
|
}
|
|
}
|
|
}
|