繁体   English   中英

如何使用Chrome DevTools Protocol的printToPDF修改first pageNumber或执行header或footer模板中的JS

[英]How to modify the first pageNumber or execute JS in header or footer template with Chrome DevTools Protocol's printToPDF

我正在使用Headless Chrome通过printToPDF CDP 方法打印出 PDF 个文件。 如果我们将displayHeaderFooter参数设置为true ,那么我们可以使用参数headerTemplatefooterTemplate设置特定页面 header 和页脚。 该协议提供了一些 HTML 类来显示一些信息,它们是: datetitleurlpageNumbertotalPages

例如,我们可以将footerTemplate设置为<span class="pageNumber"></span>以在页脚中显示当前页码。 我们还需要添加一些样式来正确显示它。 默认的 header 和页脚设置可以在这里找到,渲染器 C++ 组件在这里

我想修改显示的 pageNumber 值。 我的目标是从给定的数字开始计算页数。

Puppeteer API 文档指出headerTemplatefooterTemplate标记具有以下限制:

  1. 不评估模板内的脚本标签。
  2. 页面 styles 在模板中不可见。

GitHub 评论提供以下内容:

<div style="font-size: 10px;">
  <div id="test">header test</div>
  <img src='http://www.chromium.org/_/rsrc/1438879449147/config/customLogo.gif?revision=3' onload='document.getElementById("test").style.color = "green";this.parentNode.removeChild(this);'/>
</div>

它说,如果我们在img标签上使用onload属性,那么我们可以在模板中运行 JavaScript。 但是,我无法重现结果,即片段下方屏幕截图中显示的内容。

例如,以下 JavaScript 可以从 10 开始计算页数:

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="tmpimg" 
onload="var x = document.getElementById('pn').innerHTML; var y = 10; document.getElementById('pn').innerHTML = parseInt(x) + y; this.parentNode.removeChild(this);"/>
<span id="pn" class="pageNumber"></span>

但不幸的是这个脚本没有修改页码,我不知道如何解决这个问题。 我也尝试过使用纯 CSS 解决方案,但没有成功。

欢迎任何想法来解决这个问题。

您是否尝试过跨越 img 标签?

您可以尝试的一种方法是在调用 printToPDF 方法之前使用 JavaScript 修改 DOM 中的 pageNumber 元素。 您可以通过将脚本注入到在生成 PDF 之前运行的页面中来执行此操作。

以下是如何使用 Puppeteer 执行此操作的示例:

const page = await browser.newPage();
// Navigate to the page you want to generate a PDF for
await page.goto('https://www.example.com');
// Inject a script into the page to modify the page numbering
await page.evaluate(() => {
  // Get the pageNumber element
  const pageNumberElement = document.querySelector('.pageNumber');
  // Modify the innerHTML of the element to start counting from 10
pageNumberElement.innerHTML = parseInt(pageNumberElement.innerHTML) + 10;
});
// Generate the PDF using the modified page numbering
const pdf = await page.pdf({ displayHeaderFooter: true });
// Save the PDF to a file
fs.writeFileSync('output.pdf', pdf);
await page.close();

我尝试了直接的方法来解决这个问题,但没有奏效。 即使像 CSS 表达式和计数器这样晦涩的 API 也无法解决这个问题。 幸运的是,似乎有一个足够简单的解决方法。

我们使用pageRange参数分别打印每个页面,然后组合所有页面以生成所需的 pdf。这使我们能够打印每个页眉/页脚,如果它是 pageNumber 的pageNumber 例如:

const footerTemplate = function (pageNumber) {
    return `<div>Page number: ${pageNumber + 24}</div>`;
};

我们需要遍历每一页并打印它。

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

没有简单的方法来确定要打印的总页数。 所以我们不知道什么时候停止。 幸运的是,当我们尝试打印超出范围的页面时, Chrome 会发送错误 所以我们可以用它来停止打印。

下面附上了一个工作示例,页码偏移了 24。使用依赖项运行: fspdf-merger-jspuppeteer

 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 printPage = 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(printPage(pageNumber)); pageNumber += 1; } } catch (e) { await mergePdfs(pageNumber, 'html-page.pdf'); cleanup(pageNumber); } await browser.close(); })();

使用Chrome DevTools Protocol的printToPDF方法时,可以通过headerTemplate和footerTemplate选项修改页码或执行header或页脚模板中的JavaScript。 这些选项允许您指定一个字符串,该字符串将用作 header 的 HTML 模板和 PDF 的页脚。

要设置第一个页码,您可以使用 pageNumber 选项并将其设置为所需的页码。

这是一个示例,说明如何使用这些选项修改首页页码并在 header 和页脚模板中执行 JavaScript:

const { CDP } = require('chrome-remote-interface');

(async function() {
    const client = await CDP();

    const { Page } = client;

    await Page.enable();

    // Define the header and footer templates
    const headerTemplate = `
        <div>
            <p>My custom header</p>
            <script>
                document.querySelector('p').innerHTML += ' - Page ' + document.querySelector('#pageNumber').textContent;
            </script>
        </div>
    `;

    const footerTemplate = `
        <div>
            <p>My custom footer</p>
            <script>
                document.querySelector('p').innerHTML += ' - Page ' + document.querySelector('#pageNumber').textContent;
            </script>
        </div>
    `;

    // Print the PDF
    const pdf = await Page.printToPDF({
        displayHeaderFooter: true,
        headerTemplate: headerTemplate,
        footerTemplate: footerTemplate,
        pageNumber: 1,
    });

    // Close the connection
    client.close();
})();

注意:这只是一个示例,您应该将 url 和其他选项替换为您需要的选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM