将 RMarkdown 渲染导出到 .pdf 时,Puppeteer 不尊重颜色
Puppeteer doesn't respect colors when exporting RMarkdown render to .pdf
我正在使用 puppeteer
(无头 Chrome)将 RMarkdown 脚本生成的 .html 渲染为 .pdf。但是,puppeteer
似乎不尊重我的 color
和 background-color
样式设置。从网络上呈现页面时不存在该问题,表明它是 puppeteer
和 RMarkdown
之间的交互。
考虑以下 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.png
和 test.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.html
中 URL 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}
我正在使用 puppeteer
(无头 Chrome)将 RMarkdown 脚本生成的 .html 渲染为 .pdf。但是,puppeteer
似乎不尊重我的 color
和 background-color
样式设置。从网络上呈现页面时不存在该问题,表明它是 puppeteer
和 RMarkdown
之间的交互。
考虑以下 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.png
和 test.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.html
中 URL 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}