The phantomjs project is archived. There are, and will be security issues rising! We recommend to migrate to the jsreport default pdf printing using chrome.
The Phantom-pdf
recipe uses the phantomjs screen capture feature to print HTML content into PDF files. This approach is very productive in defining report templates, and also the most used one with jsreport.
The Phantom-pdf
recipe is capable of rendering any HTML and JavaScript you provide. This means you can also use external JavaScript libraries or canvas to print visual charts.
npm install @jsreport/jsreport-phantom-pdf
margin
- px or cm specification of margin used from page borders, you can also pass an Object
or JSON object string
for better control of each margin side. ex: { "top": "5px", "left": "10px", "right": "10px", "bottom": "5px" }
format
- predefined page sizes containing A3, A4, A5, Legal, Letterwidth
- px or cm page width, takes precedence over paper formatheight
- px or cm page height, takes precedence over paper formatorientation
- portrait or landscape orientationheaderHeight
- px or cm height of the header in the pageheader
- header html contentfooterHeight
- px or cm height of the footer in the pagefooter
- footer html contentprintDelay
- delay between rendering a page and printing into pdf, this is useful when printing animated content like chartsblockJavaScript
- block executing javascriptwaitForJS
- true/falseThese basic settings are typically stored with the template, but you can also send them through API calls inside the template.phantom
property.
CSS contains styles like page-break-before
that you can use to specify html page breaks. This can be used as well with phantom-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>
<div style="page-break-before: always;"></div>
<h1>Hello from Page 3</h1>
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.
Phantom-pdf
provides the special tags {#pageNum}
and {#numPages}
to header and footer which can be used to print page numbers.
<div style='text-align:center'>{#pageNum}/{#numPages}</div>
Note that Phantom-pdf
also evaluates javascript in the header and footer which you can use to modify the paging start for example:
<span id='pageNumber'>{#pageNum}</span>
<script>
var elem = document.getElementById('pageNumber');
if (parseInt(elem.innerHTML) <= 3) {
elem.style.display = 'none';
}
</script>
Phantom-pdf
is currently not able to print some national characters by default. To be able to print correct national characters into pdf you need to set utf-8
charset in your html first.
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body>
ščřžý
</body>
</html>
You may notice image won't show up when you try to add it into phantom header in a common way:
<img src='http://domain.com/foo.jpg'>
This is because the header and footer are printed into PDF format in a synchronous way. This means that any asynchronous request like getting image won't finish in time. This is a current limitation of phantom.js
Solution:
Add the same image to template content and hide it with the style display:none
. Then, you can add it to the header and it will show up because it is already cached and then no asynchronous request is needed. This is required to do for both images referenced by url as well for Data URI scheme base64 image.
phantomjs doesn't let you link an external style to header and footer. You need to always inline it using <style>
tag. If this becomes tedious, you can use child template to extract and reuse it.
You may need to postpone PDF printing until some JavaScript async tasks are processed. In this case, set the phantom.waitForJS=true
in the API or enable 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>
The default phantomjs@1.9 currently doesn't work on the macOS sierra update, you need to use the phantomjs2. See the next chapter.
The recipe default installation uses phantomjs@1.9. You can additionally install other versions and use them in parallel.
npm install phantomjs-exact-2-1-1
"template.phantom.phantomjsVersion":"2.1.1"
in api callYou can also set the default phantomjs version globally in the config:
"phantom": {
"defaultPhantomjsVersion": "2.1.1"
}
Note that phantomjs2 produces different sizes of fonts versus 1.9. Also, it doesn't support repeating thead
when the table spawns multiple pages.
Using a responsive CSS framework such as Bootstrap for printing to PDF may not be the best idea. However, it still works. You need to keep in mind that the output PDF typically won't look the same as HTML, because Bootstrap includes different printing styles under @media print
.
The fonts can be easily embedded into PDF reports using the assets extension. You can find the tutorial on how to do it here.
Normally, if you need that some content to be shown on each page, you would use headers or footers.
However, since headers and footers are rendered like new templates and don't have any context about what is being evaluated in your main template, sometimes you will find that headers and footer are very limited for your actual requirements. In that case, you can use an approach similar to the one described in this post.
The approach uses some magic numbers (values that will need to be tweaked depending on your machine and content and by your best judgment) to get the total number of pages rendered and do some calculations to be able to emulate headers and footers for each page, or just to render some content in a specific position for each page (like a watermark).
Another option for printing content in each page is to use the pdf-utils extension, it provides features to merge dynamic content into the pdf output.
Both phantomjs 1.9.8 as well as 2.1.1 are producing different sizes of PDF elements when rendered on Windows versus a Unix platform. This issue can be tracked here. We recommend to design your reports on the same OS where you plan to run your production jsreport instance because of this. If this is not an option for you, you may try to apply the following css to adapt the sizes on your local or production templates.
body {
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
transform: scale(0.654545);
-webkit-transform: scale(0.654545);
}
Use the phantom
configuration node in the standard config file.
"extensions": {
"phantom-pdf": {
"numberOfWorkers": 1
"timeout": 180000,
"allowLocalFilesAccess": false,
"defaultPhantomjsVersion": "1.9.8"
}
}
you can also use top level phantom
property in configuration, the difference is that this configuration will be shared with any other extension that uses phantomjs and the configuration snippet above is specifically for options in phantom-pdf
extension.
"extensions": {
"phantom": {
"numberOfWorkers": 1
"timeout": 180000,
"allowLocalFilesAccess": false,
"defaultPhantomjsVersion": "1.9.8"
}
}
available options for configuration:
phantom.strategy (dedicated-process | phantom-server
) - The first strategy uses a new phantomjs instance for every task. The second strategy reuses every instance over multiple requests. Where phantom-server
has better performance, the default dedicated-process
is more suitable to some cloud and corporate environments with proxies
phantom.numberOfWorkers (int
) - specify how many phantomjs instances will phantom-pdf recipe use. If the value is not filled, jsreport will use number of cpus by default
phantom.timeout (int
) - specify default timeout for pdf rendering using phantomjs
phantom.allowLocalFilesAccess (bool
) - default is false
. When set to true you can use local paths to get resources.
phantom.host (string
) - Set a custom hostname on which phantomjs server is started, useful is cloud environments where you need to set specific IP.
phantom.portLeftBoundary (number
) - set a specific port range for phantomjs server
phantom.portRightBoundary (number
) - set a specific port range for phantomjs server
phantom.defaultPhantomjsVersion (string
) - set the default phantomjs version to use, note that if you are going to set this value other than the default you must install manually the desired phantomjs version (either using packages like phantomjs-prebuilt
or phantomjs-exact-2-1-1
). default: 1.9.8