打印到PDF时更改默认页眉/页脚

时间:2017-06-15 19:38:12

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

我正在尝试使用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

中的功能相同

但是,我还没有找到一种方法来在谷歌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的任何奇怪的重新流动更加可靠。

7 个答案:

答案 0 :(得分:12)

可以使用<header><footer>标记创建自定义页眉和页脚。我使用它来使用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 }删除默认的页眉和页脚。

希望这会有所帮助。

答案 1 :(得分:12)

这是对问题的更新/回答。从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 }); 
};

答案 2 :(得分:8)

您的问题有两种解决方案

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>

答案 3 :(得分:3)

根据this forum,目前无法在Google Chrome中执行此操作。您所能做的就是打开或关闭页眉/页脚。这由评论表示:

  

目前,在打印文档时无法编辑标题。您当前只能打开或关闭页眉和页脚,其中包括日期,网页名称,页面URL以及您要打印的文档的页数。您可能需要查看Chrome网上应用店,看看是否有任何方便的第三方扩展程序,您可以在Chrome上安装这些扩展程序,这些扩展程序可能符合您在打印方面的要求 - Source

可能有第三方扩展程序可以获取您要查找的功能,或者按照您的建议,您可以使用JavaScript附加要打印的元素。

答案 4 :(得分:2)

如果你真的想以一种非hacky的方式做这件事,你必须得到chrome devtools协议,因为命令行界面不支持太多(aka --print-to-pdf就是你得到的,没有打印选项)

此处记录了协议:https://chromedevtools.github.io/devtools-protocol/tot

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

以下是我用于演示用法的一些示例:

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

基本上,协议是在protocol.json中定义的,客户端库使用它来生成在任何应用程序中使用的类/方法。这些方法将较低级别的通信封装在协议中。

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

答案 5 :(得分:2)

正如亚历克·雅各布森(Alec Jacobson)在评论中提到的那样,在页面上使用margin:0以及在正文上使用margin:1.6cm仅适用于一页。

对我有用的是将内容包装在表格中,顶部使用thead,底部使用tfoot。 Thead和tfoot在所有页面上重复,并且您的主页内容位于表格的正文中。

示例:

`

    <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>`

本来希望添加到评论主题中,但信誉不够。

答案 6 :(得分:1)

对于那些只想要开箱即用的东西的人,我想分享我今天根据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

完成转化后,别忘了去除铬。

我很确定该解决方案还远远不够完美,但是至少它能起作用,而且由于我看到了很多有关此功能的问题,我不得不花自己的几个小时来使它起作用,我想分享一下我的解决方案。我遇到的一些问题与header-和footerTemplates有关,因为空模板似乎无法代替现有模板(您需要<div></div>),而在文档中有不同说明的情况下,新模板不会出现在可见区域中,直到用<div class="text center">或类似的符号包裹。