I tried straight forward approaches to solve this problem and they didn’t work. Even obscure apis like CSS expressions and counters don’t work to solve this. Fortunately there seems to be a simple enough work around.
We print each page separately using the pageRange parameter and then combine all the pages to generate the required pdf. This enables us to print each header/footer if it were a function of the pageNumber. For example:
const footerTemplate = function (pageNumber) {
return `<div>Page number: ${pageNumber + 24}</div>`;
};
We need to iterate over each page and print it.
const printPage = function (pageNumber) {
return {
...
path: `html-page-${pageNumber}.pdf`,
footerTemplate: footerTemplate(pageNumber),
pageRanges: String(pageNumber)
};
};
(async function () {
...
const page = await browser.newPage();
var pageNumber = 1;
try {
while (pageNumber > 0) {
await page.pdf(printPage(pageNumber));
pageNumber += 1;
}
} catch (e) {
} finally {
// Merge and clean up
}
})();
There is no trivial way to determine the total number of pages to print. So we don’t know when to stop. Fortunately, Chrome sends an error when we try to print a page that’s out of range. So we can use that to stop our printing.
Attached below is a working sample with page numbers offset by 24. Run with dependencies: fs, pdf-merger-js and puppeteer.
const puppeteer = require("puppeteer");
const PDFMerger = require('pdf-merger-js');
const fs = require("fs");
const footerTemplate = function (pageNumber) {
return `<div style="font-size: 10px; display: flex; flex-direction: row; justify-content: space-between; width: 100%" id='template'>
<div>Page number: ${pageNumber + 24}</div>
</div>`;
};
const mergePdfs = async function (totalPages, fileName) {
var merger = new PDFMerger();
for (var pageNumber = 1; pageNumber < totalPages; pageNumber++) {
await merger.add(`html-page-${pageNumber}.pdf`);
}
await merger.save(fileName);
};
const cleanup = function (totalPages) {
for (var pageNumber = 1; pageNumber < totalPages; pageNumber++) {
var path = `html-page-${pageNumber}.pdf`
fs.rmSync(path);
}
};
const pageSetup = function (pageNumber) {
return {
path: `html-page-${pageNumber}.pdf`,
format: 'Letter',
printBackground: true,
displayHeaderFooter: true,
footerTemplate: footerTemplate(pageNumber),
pageRanges: String(pageNumber),
margin: {
top: '1in',
right: '0in',
bottom: '1in',
left: '0in'
}
};
};
(async function () {
const browser = await puppeteer.launch({
ignoreHTTPSErrors: true,
dumpio: true,
headless: true
});
const page = await browser.newPage();
await page.goto('http://worrydream.com/KillMath/');
var pageNumber = 1;
try {
while (pageNumber > 0) {
await page.pdf(pageSetup(pageNumber));
pageNumber += 1;
}
} catch (e) {
await mergePdfs(pageNumber, 'html-page.pdf');
cleanup(pageNumber);
}
await browser.close();
})();