簡體   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