Chrome-pdf
recipe is using headless chrome to print html content into pdf files.
The settings reflects the headless chrome API where you can also find detail information.
These basic settings are typically stored with the template, but you can also send them through API calls inside the template.chrome
property.
The options can be also dynamically set from within the page javascript using:
<script>
...
window.JSREPORT_CHROME_PDF_OPTIONS = {
landscape: true
}
</script>
Use chrome-pdf
node in the standard config file.
"extensions": {
"chrome-pdf": {
"timeout": 30000,
"launchOptions": {...}
}
}
to find more information about what is available in launchOptions
configuration object you can check the docs here.
you can also use top level chrome
property in configuration, the difference is that this configuration will be shared with any other extension that uses chrome and the configuration snippet above is specifically for options in chrome-pdf
extension.
"chrome": {
"timeout": 30000
}
The fonts can be easily embedded into PDF reports using the assets extension. You can find the tutorial on how to do it here.
CSS contains styles like page-break-before
that you can use to specify html page breaks. This can be used as well with chrome-pdf in order to specify page breaks inside pdf files.
<h1>Hello from Page 1</h1>
<div style='page-break-before: always;'></div>
<h1>Hello from Page 2</h1>
You can also use css property page-break-inside
to for example avoid breaking an element to multiple pages.
You may need to postpone pdf printing until some javascript async tasks are processed. If this is your case set the chrome.waitForJS=true
in the API or Wait for printing trigger
in the studio menu. Then the printing won't start until you set window.JSREPORT_READY_TO_START=true
inside your template's javascript.
...
<script>
// do some calculations or something async
setTimeout(function() {
window.JSREPORT_READY_TO_START = true; //this will start the pdf printing
}, 500);
...
</script>
See an example of using printing triggers when rendering charts here.
The header and footer are evaluated as if they were a full jsreport template. This means you can add, for example, a child template reference into a header and it will be extracted. You can also use main template helpers or data in the header/footer. Remember that in order to show the header/footer you need to activate the displayHeaderFooter
option first and add some top, bottom margin to the template in order to give the page some space to show the header/footer.
Inside the header/footer template you can use some special css classes to make chrome inject some content for you. the special css classes supported by chrome are the following:
date
-> injects formatted print datetitle
-> injects the content of the document titleurl
-> injects the document locationpageNumber
-> injects current page numbertotalPages
-> insject the total pagesThere are some issues with native header/footer you should be aware of:
-webkit-print-color-adjust: exact
as workaroundIn the most of the cases it is better to use pdf-utils instead which is less limiting and without these issues.
The chrome by default displays the current date in the header and file name in the footer when displayHeaderFooterSelected
. You can place an empty tag <span/>
to the header or footer to avoid this behavior.
The header/footer has some extra padding you can remove using:
<style>#header, #footer { padding: 0 !important; }</style>
Example showing how to use the special css classes and the workaround for the scaling issues.
<!--header template content-->
<html>
<head>
<style>
/* defining explicit font-size solves the scaling issue */
html, body {
font-size: 12px;
}
</style>
</head>
<body>
<!--
defining some elements with the special css classes makes chrome
inject content in runtime
-->
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
</body>
</html>
The pdf-utils extension provides advanced and more rich features to merge dynamic content into the chrome pdf output, like rich header/footer, print page numbers, watermarks, merge pages with different orientation, etc. make sure to check the docs for some examples.
Chrome by default uses print
CSS media query when printing pdf. This impacts CSS frameworks like Bootstrap which usually produces different results for print
media type. The pdf in this case applies different styles then html. You can adapt/unite this by changing media type settings from print
to screen
in the template's chrome settings.
Chrome by default adds special tags to the pdf to make it more accessible to people with disabilities. This is typically good but can cause performance problems in very long pdfs. The rendering time can be affected as well as the final pdf size. In this case, you can try to disable the pdf tagging by adding aria-hidden="true"
attribute to the HTML body or wrapping element.
You can simply double check if the output pdf is ARIA tagged if you open it in an text editor and find text /StructTreeRoot
You can also print an existing webpage through chrome-pdf
recipe without a need to define your templates in jsreport studio. Just send a request like this:
{
"template": {
"recipe": "chrome-pdf",
"engine": "none",
"chrome": {
"url": "https://jsreport.net"
}
}
}
Or you can create an empty template and define the url using jsreport script.
function beforeRender(req, res) {
req.template.chrome = {
"url": "https://jsreport.net"
}
}
The recipe by default allocates a single instance of chrome per worker thread and reuses it. This means that for the configuration "workers": { "numberOfWorkers": 5 }
there will be 5 chrome instances allocated.
This is reasonable for most of the cases, but in case your report is initiating many nested reports, you may want to increase the parallelization by increasing the number of chrome instances allocated per thread.
{
"chrome": {
"numberOfWorkers": 3
}
}
Or you can change the allocation strategy and let the recipe always create a new instance of chrome. This increases the parallelization of the nested reports to the maximum. However, note that starting a new chrome process costs about 100ms.
{
"chrome": {
"strategy": "dedicated-process"
}
}
In many cases, you can switch to the html recipe and debug the output using the F12 browser's tool just like any other page.
To troubleshoot the javascript evaluated in the chrome-pdf
recipe, you can write to the console.log
and inspect the outputs in the studio profile tab when clicking on the chrome-pdf
operation.
For a full chrome-pdf
debugging experience, find the video tutorial here. Full credits go to the author.
Note the same debugging techniques applies also to the chrome-image recipe.
self closing divs (<div />
) are heavily slowing down chrome pdf rendering, don't use them
<div style='height:500'>
<img src='foo' />
</div>
border-spacing: collapse
which does not work properly when content is split across pages. An example of both cases and solutions is available here
--no-sandbox
argument. This can be achieved using the following config. See also puppeteer troubleshooting.
"extensions": {
"chrome-pdf": {
"launchOptions": {
"args": ["--no-sandbox"]
}
}
}