【问题标题】:Alter the default header/footer when printing to PDF打印到 PDF 时更改默认页眉/页脚
【发布时间】:2017-11-18 10:15:11
【问题描述】:

我正在尝试使用 Google Chrome 代替 PhantomJS 将 HTML 呈现为 PDF。到目前为止,它对我来说效果很好。我唯一的问题是我没有找到任何方法来翻译以下 PhantomJS 代码:

page.paperSize = {
  footer: {
    contents: phantom.callback(function(pageNum, numPages) {
      return "Power by MyWebsite. Created on "+formatDate(new Date())+"<span style='float:right'>" + pageNum + " / " + numPages + "</span>";
    })
  }
}

格式化日期与问题How to format a JavaScript date 的功能相同

但是我还没有找到一种方法可以在无头的情况下在 Google Chrome 中复制这种行为。 我正在使用来自 https://github.com/cyrus-and/chrome-remote-interface 的 Chrome 远程接口 (CDP)

这是我的chrome远程接口代码的大纲:

return new Promise(async function (resolve, reject) {
    const url = "<MyURL here>";
    const [tab] = await Cdp.List()
    const client = await Cdp({ host: '127.0.0.1', target: tab });
    await Promise.all([
       Network.enable(),
       Page.enable()
    ]);

    Page.loadEventFired(function () { 
         setTimeout(function () {
             resolve(Page.printToPDF({displayHeaderFooter:true}))); //https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
         }, 3000);
    });
    await Page.navigate({ url }); 
};

我得到的 PDF 很好,但只能得到默认的 Chrome 页眉和页脚。有什么办法修改吗?

注意:我意识到我可以在我的页面中使用 JavaScript 将元素附加到每个页面的底部,但我更喜欢在导出时更改浏览器附加的页脚/打印,因为我发现正确放置并且不会导致页面中其他 div 出现任何奇怪的重新流动更加可靠。

【问题讨论】:

  • 当chrome处于窗口模式时,它也不支持更改页眉和页脚内容,所以我认为headless方法也不支持。从代码中的链接 (chromedevtools.github.io/devtools-protocol/tot/Page/…) 可以清楚地看出,没有这样的参数
  • 使用 javascript 你将如何在每个页面的顶部添加元素?我知道我们可以在文档顶部添加元素,但我们将如何定位到最终 PDF 中每一页的顶部?
  • @kyriakos 您需要每个页面元素都在其自己的div 中才能实现。这是一个解决方案,但不是一个好的解决方案。

标签: javascript google-chrome google-chrome-headless


【解决方案1】:

正如 Alec Jacobson 在 cmets 中提到的,在页面上使用 margin:0 以及在正文上使用 margin:1.6cm 仅适用于一页。

对我有用的是将我的内容包装在一个表格中,使用 thead 作为上边距,使用 tfoot 作为下边距。 thead 和 tfoot 在所有页面上重复,您的主页内容进入表格的 tbody。

例子:

`

    <thead> 
        <tr> 
            <th style="height: 1cm">
                Header    
            </th>
        </tr>
    </thead>

    <tbody>
        <tr>
            <td>

                Page Content

            </td>
        </tr>
    </tbody>

    <tfoot>
        <tr>
            <td style="height: 1cm">

                Footer

            </td>
        </tr>
    </tfoot>

</table>`

本来想添加到评论线程但没有足够的声誉。

【讨论】:

  • 我非常喜欢您的解决方案,它应该可以满足大部分需求。您应该和一个
【解决方案2】:

更新

您可以使用printToPDF 中的headerTemplatefooterTemaplate 参数来自定义打印为PDF 时的页眉和页脚。

headerTemplatefooterTemaplate 接受有效的 HTML 标记,您可以使用以下类将打印值注入您的 HTML 元素:

  • date - 将以可打印格式将当前日期注入到包含该类的 HTML 元素中
  • title - 文档标题
  • url - 文档位置
  • pageNumber - 当前页码
  • totalPages - 总页数

例如打印页码和总页数:

Page.printToPDF({
    displayHeaderFooter: true,
    footerTemplate: "<span class='pageNumber'></span> <span>out of</span> <span class='totalPages'></span>"
})

原创

(当时,Chrome DevTools 无法实现。)

根据this forum,目前在谷歌浏览器中没有办法做到这一点。您所能做的就是打开或关闭页眉/页脚。注释表明了这一点:

目前无法在打印文档时编辑页眉。您目前只能打开或关闭页眉和页脚,其中包括日期、网页名称、页面 URL 以及您正在打印的文档的页数。您可能想查看 Chrome 网上应用店,看看是否有任何方便的第三方扩展程序可以安装在 Chrome 上,这些扩展程序可能适合您在打印方面的需求 -- Source 可能有第三方扩展来获得您正在寻找的功能,或者按照您的建议,您可以使用 JavaScript 来附加您想要打印的元素。

【讨论】:

  • 如何关闭页眉和页脚?
  • @VaibhavBhatia 使用 Chrome DevTools,您可以使用 Page.printToPDF,并将 displayHeaderFooter 设置为 false。
  • 是否可以使用命令行?现在我正在做类似“start-process chrome.exe -ArgumentList”--headless --print-to-pdf=C:\Users\VAIBHAV\Desktop\AllPdf\test.pdf google.com" 但我不能隐藏页眉和页脚
  • 这个包提供了一个带有displayHeaderFooter参数的命令行界面:github.com/dataverity/chromehtml2pdf
  • @ChavaG 有没有直接使用 Chrome DevTools 的方法?
【解决方案3】:

对于那些只想要开箱即用的东西的人,我想分享我今天根据 apokryfos 的回答编写的脚本。

首先需要安装依赖

yarn global add chrome-remote-interface

接下来你需要启动一个启用了调试端口的无头铬

chromium-browser --headless --disable-gpu --run-all-compositor-stages-before-draw --remote-debugging-port=9222

现在您必须将我的脚本保存为print-via-chrome.js

#!/usr/bin/env node

const homedir = require('os').homedir();
const CDP = require(homedir+'/.config/yarn/global/node_modules/chrome-remote-interface/');
const fs = require('fs');

const port = process.argv[2];
const htmlFilePath = process.argv[3];
const pdfFilePath = process.argv[4];

(async function() {

        const protocol = await CDP({port: port});

        // Extract the DevTools protocol domains we need and enable them.
        // See API docs: https://chromedevtools.github.io/devtools-protocol/
        const {Page} = protocol;
        await Page.enable();

        Page.loadEventFired(function () {
                console.log("Waiting 100ms just to be sure.")
                setTimeout(function () {
                        //https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
                        console.log("Printing...")
                        Page.printToPDF({
                                displayHeaderFooter: true,
                                headerTemplate: '<div></div>',
                                footerTemplate: '<div class="text center"><span class="pageNumber"></span></div>',
                                //footerTemplate: '<div class="text center"><span class="pageNumber"></span> of <span class="totalPages"></span></div>'
                        }).then((base64EncodedPdf) => {
                                fs.writeFileSync(pdfFilePath, Buffer.from(base64EncodedPdf.data, 'base64'), 'utf8');
                                console.log("Done")
                                protocol.close();
                        });
                }, 100);
        });

        Page.navigate({url: 'file://'+htmlFilePath});
})();

使用chmod +x print-via-chrome.js 使其可执行后,您应该能够将 html 文件转换为 pdf 文件,如下所示:

./print-via-chrome.js 9222 my.html my.pdf

完成改造后别忘了退出铬。

我很确定这个解决方案远非完美,但至少它是有效的我的解决方案。我遇到的一些问题与页眉和页脚模板有关,因为似乎空模板不会替换现有模板(您需要&lt;div&gt;&lt;/div&gt;),并且虽然记录不同,但新模板不会出现在可见区域中,直到用&lt;div class="text center"&gt; 或类似的东西。

【讨论】:

  • 当我运行所有这些时,当我登录到 root 和/或我的常规非 root 用户时,我会得到一个 Cannot find module '/root/.config/yarn/global/node_modules/chrome-remote-interface/'
  • @BrianLeishman 请不要为此使用 root(这既不必要也不明智)。您的错误听起来像是您在开始时跳过了yarn global add chrome-remote-interface 命令还是失败了?你用的是 yarn 还是 npm?
【解决方案4】:

这是对问题的更新/答案。从 Chromium 64 开始,可以使用 headerTemplatefooterTemplate 参数到 printToPDF

使用chrome remote interface 下面的示例代码应该可以工作:

return new Promise(async function (resolve, reject) {
    const url = "<MyURL here>";
    const [tab] = await Cdp.List()
    const client = await Cdp({ host: '127.0.0.1', target: tab });
    await Promise.all([
       Network.enable(),
       Page.enable()
    ]);

    Page.loadEventFired(function () { 
         setTimeout(function () {
    //https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
             resolve(Page.printToPDF({
                  displayHeaderFooter:true,
                  footerTemplate: "<span class='pageNumber'> of <span class='totalPages'>"
             }))); 
         }, 3000);
    });
    await Page.navigate({ url }); 
};

【讨论】:

  • 请注意,无法将参数 displayHeaderFooter 传递给 chrome CLI。 cs.chromium.org/chromium/src/headless/app/… 中支持的 chrome headless cli 参数列表。在 nodejs 中使用 puppeteer 或通过 websocket 以任何其他语言连接到 DevTools。
  • @ZeroZhang 是的,该代码用于 chrome 远程接口(基本上是 chrome devtools 协议的 SDK),但可能没有正确强调,我可以看到有人很容易错过它.我已经更新了 github repo 的链接。
  • 对于在命令行工具中寻找这些选项的其他人。我花了一些时间。
  • @VaibhavBhatia 我终于用 puppeteer了。
【解决方案5】:

如果您真的想以一种非 hacky 的方式执行此操作,则必须使用 chrome devtools 协议,因为命令行界面不支持太多(又名--print-to-pdf 就是您所得到的,没有打印选项)

协议记录在这里:https://chromedevtools.github.io/devtools-protocol/tot

客户端库有多种语言版本,可通过包管理器获得。

以下是我整理的一些示例来演示用法:

Page.printToPDF 协议方法支持为页眉和页脚传递自定义标记的参数。

基本上,该协议在protocol.json 中定义,客户端库使用该协议来生成用于任何应用程序的类/方法。这些方法封装了与协议的底层通信。

我所要做的就是安装一个客户端库包(通过 npm 或 composer),确保已安装 chrome,编写一些代码,然后我正在生成没有页眉/页脚的 pdf!太棒了。

【讨论】:

    【解决方案6】:

    可以使用&lt;header&gt;&lt;footer&gt; 标签创建自定义页眉和页脚。我使用它来使用 Chrome Headless 生成 PDF。我还没有在 Firefox、IE 等中测试过...

    <header>
      Custom Header
      <img src="http://imageurl.com/image.jpg"/>
    </header>
    <div class="content">Page Content - as long as you want</div>
    <footer>
      Footer Content
    </footer>
    

    CSS

    @page {
      margin: 0;
    }
    @media print {
      footer {
        position: fixed;
        bottom: 0;
      }
      header {
        position: fixed;
        top: 0;
      }
    }
    

    @page { margin: 0 } 删除默认页眉和页脚。

    希望这会有所帮助。

    【讨论】:

    • 是的,我在多页的 pdf 上使用过这个。
    • 这个答案怎么有+16?事实上,这只会创建一个页脚,而不是放入它会自动添加到每个页面的 Chrome 页脚。
    • 这是一个很好的答案。如果也有添加页码的方法就好了!
    【解决方案7】:

    您的问题有两种解决方案

    A) 不留边距将 chrome-header 推出:

     @page { 
         margin: 0;
         size: auto;
     }
    

     @media print {
       @page { margin: 0; }
       body { margin: 1.6cm; }
     }
    

    B) 原本应该适用于 Chrome 的 Firefox 解决方案

     <html moznomarginboxes mozdisallowselectionprint>
    

    一些样本:

    <!DOCTYPE html>
    <html moznomarginboxes mozdisallowselectionprint>
    <head>
    <title>Print PDF without header</title>
    <style>
    @media print {
        @page { margin: 0; }
        body { margin: 1.6cm; }
    }
    </style>
    </head>
    <body>
    <p>Some Text in Paragraph to print!</p>
    <a href="javascript:print()">Print</a>
    </body>
    </html>

    【讨论】:

    • 问题不在于推出默认的 chrome 页眉/页脚,而在于自定义它们。
    • 那么 Chrome 的行为是当你推出它时,标题选项将被消除,这很奇怪但确实如此,试试这个,你会看到标题复选框消失了
    • 这确实只对单页有效,否则body的上下边距不会在后续页面产生上下边距。
    猜你喜欢
    • 2019-08-20
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 2011-06-20
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    相关资源
    最近更新 更多