22

我正在尝试使用 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>";
    })
  }
}

格式日期与问题中的功能相同如何格式化JavaScript日期

但是我还没有找到一种方法可以在无头的谷歌浏览器中复制这种行为。我正在使用来自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 的任何奇怪的重新流动。

4

7 回答 7

18

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

使用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 () {
    //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 }); 
};
于 2018-03-07T08:47:00.477 回答
16

可以使用<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 }删除默认页眉和页脚。

希望这可以帮助。

于 2017-09-22T15:41:09.160 回答
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>

于 2017-06-25T17:35:03.030 回答
8

更新

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

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 中是不可能实现的。)

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

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

于 2017-06-26T07:15:19.073 回答
4

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

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

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

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

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

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

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

于 2018-04-24T21:48:18.730 回答
2

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

完成改造后不要忘记退出铬。

我很确定这个解决方案远非完美,但至少它是有效的,因为我看到了很多关于这个功能的问题并且不得不花费我自己的几个小时来让它工作,所以我想分享我的解决方案。我遇到的一些问题与页眉和页脚模板有关,因为似乎空模板不会替换现有模板(您需要<div></div>),并且虽然记录不同,但新模板不会出现在可见区域中,直到用 a<div class="text center">或其他东西包裹相似的。

于 2018-07-19T21:11:55.613 回答
2

正如 Alec Jacobson 在评论中提到的那样,在页面上使用 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>`

本来希望添加到评论线程中,但没有足够的声誉。

于 2020-05-07T03:52:37.447 回答