将 RMarkdown 渲染导出到 .pdf 时,Puppeteer 不尊重颜色

Puppeteer doesn't respect colors when exporting RMarkdown render to .pdf

我正在使用 puppeteer(无头 Chrome)将 RMarkdown 脚本生成的 .html 渲染为 .pdf。但是,puppeteer 似乎不尊重我的 colorbackground-color 样式设置。从网络上呈现页面时不存在该问题,表明它是 puppeteerRMarkdown 之间的交互。

考虑以下 test.Rmd 脚本:

---
title: "Testing colors"
output: html_document
---

<style>
html {
  -webkit-print-color-adjust: exact;
}

h4 {color: blue;}
</style>

#### Blue heading
<div style="color:red">This text is red</div>
<div style="background-color:red">This text has red background</div>

我们可以通过在 R 中调用 rmarkdown::render( "test.Rmd", output_file="test.html" ) 将其呈现为 test.html。注意 -webkit-print-color-adjust 设置; it is often recommended 作为颜色相关问题的解决方案,但我发现它对我的情况没有影响。

puppeteer tutorials之后,我整理了以下render.js

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setViewport({width: 400, height: 200});
    await page.goto('file:///home/sokolov/test/puppeteer/test.html');
    await page.screenshot({path: 'test.png'});
    await page.pdf({path: 'test.pdf', printBackground: true});
    await browser.close();
})();

运行 node render.js 从命令行生成 test.pngtest.pdf。前者看起来完全符合您的期望:

但是,.pdf 失去了所有颜色规格:

如果我将 render.js 中的 url 替换为外部页面(例如,https://www.w3schools.com/css/css_background.asp),该页面将在 .png 和 [=26] 中正确呈现=] 格式。指定 printBackground: true 是使其适用于此外部页面的关键,但它似乎对我的本地 test.html.

没有影响

关于如何让颜色发挥作用有什么想法吗?

P.S. 为了简要说明为什么我不简单地在我的 .Rmd 中使用 output: pdf_document 的问题,我想请注意,我正在使用的真实 RMarkdown 文档使用 flexdashboard 布局,即 doesn't play nicely with knitr。我读过的大多数教程都建议使用无头浏览器将最终的 .html 渲染为 .png/.pdf。除了颜色样式丢失外,该解决方案对我来说效果很好。

最简单的解决方案

为什么不尝试删除所有 !important 标签?我们的目标是 rmarkdown:render 嵌入的 css。只需 运行 一些搜索和替换代码,puppeteer 就会正确地为由 test.html 制作的 pdf 着色。 运行 在安装了 vim 的 shell 中:

echo "%s/%21important// | w!" | vim -e test.html

就是这样!下面我只是记录了我解决这个问题的第一次尝试,并解释了为什么它可能不是最好的解决方案。其他人可能会发现它有用。

我的第一次尝试

运行 在安装了 vim 的 shell 中:

echo "%s/%40media%20print%7B.\{-}%7D// | w!" | vim -e test.html

上面的命令覆盖了 test.html 并部分删除了 @media print{} 样式。虽然 @media print{} 样式没有完全或干净地删除,但新的 test.html 具有预期的效果。

这是我正在做的事情

我们正在研究url编码的css,所以当我真的想写这个的时候需要%s/%40media%20print%7B.\{-}%7D//:

%s/@media print{.\{-}}//

目标是完全删除这样的语句:@media print {a: ""}。我没有正确处理嵌套的括号,所以这个脚本只部分删除像这样 @media print {.a{a: ""};b{}...} 的语句,而第一个右括号之后的所有内容都保持不变。那是一个错误。由于与 .\{-} 的非贪婪匹配而不是与 .* 的贪婪匹配,我删除的太少,这可能会删除太多。

这是我要删除的内容

为了便于阅读,我在 test.htmlURL decoded 实际 css。你可以看到我删除了不匹配的括号。很可能,有问题的 css 实际上并没有被删除,但是删除这些行足以破坏 css 以在检测到 @media print 时禁用有问题的 css 。不管怎样,删除这6个匹配项就解决了问题。

@media print{*,:after,:before{color:#000!important;text- 
shadow:none!important;background:0 0!important;-webkit-box- 
shadow:none!important;box-shadow:none!important}

@media print{.visible-print{display:block!important}

@media print{.visible-print-block{display:block!important}

@media print{.visible-print-inline{display:inline!important}

@media print{.visible-print-inline-block{display:inline-block!important}

@media print{.hidden-print{display:none!important}