-
Notifications
You must be signed in to change notification settings - Fork 5.8k
PhantomJS 2: PDF rendering too large, page.zoomFactor doesn't work #12685
Comments
+1 experiencing exactly the same problem. any idea how to work around this? edit: used css to work around the problem for now html {
zoom: 0.68; /*workaround for phantomJS2 rendering pages too large*/
} |
I'm seeing this issue too. It is especially frustrating that I'm trying to use 2.0 to get webfont support, but normal HTML content doesn't fit into PDFs like it did so nicely in 1.9.x. I'd really appreciate it if anyone could point me in the right direction to what might be causing this in the PhantomJS code base. I'd glady work on submitting a PR to fix this. |
@ariya I fear this bug will be overlooked quite easily regarding the amount of open tickets. Perhaps you can mark this ticket properly as a regression? |
+1 still broken in 2.0 brach |
Still broken for me also. The elgarfo patch works, but it's hacky :) |
@thomasbachem Good point, labelling it now. Thanks! |
@ariya Thanks, I just linked two duplicate tickets. @polarathene mentions some observations in #12936 that may be of help, though I couldn't verify those myself:
|
+1 Version 2.0 fixes Function.prototype.bind but breaks paperSize) |
Also experiencing this issue. I'd love to switch to v2 to fix the page-break-avoid:inside issue but this is a problem now. elgarfo's tweak seems to work but as noted it causes rendering issues. Has anyone a better work around? Are there adapted pixel settings for A4&Letter? I'm on Unix. |
@Feendish I wrote a lot on the mentioned issue above, but if you read the workaround I gave for mac it should work for unix. |
@Feendish Following on from the analysis by @polarathene we opted for a transform which seemed to result in fewer rendering issues than using zoom. .page {
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
transform: scale(0.75);
-webkit-transform: scale(0.75);
} |
@polarathene thanks. You gave a comprehensive break down. I just couldn't follow it exactly. I tried using the dimensions_width formula you suggested but it was still off. In the end given your note that the DPI is 72 in Mac/Unix I use a DPI to pixel calculator http://www.hdri.at/dpirechner/dpirechner_en.htm and just hard coded the pageSize to 595x842 for A4 Portrait. 595px = 8.26772 inches x 72dpi where 8.26772=210mm. @jimclarkuk I tried your solution too with no luck. Page breaking was messed up with overlapping elements. |
@Feendish What exactly do you mean? Setting page.paperSize = { width: '595px', height: '842px', margin: '0px' }; Doesn't change or fix anything for me under Mac OS X 10.9. The page is still too small compared to 1.9.8. |
@thomasbachem I'm building the HTML from scratch to test it. Haven't tried running it on established HTML source yet. I used Bootstrap 3 to make a sample long Invoice. JS code-> http://pastie.org/10011943 It now generates a clean A4 sized portait PDF of 44 pages. I'm on Linux (Centos 6.4). |
@thomasbachem It's been a while but from memory that's the dimensions for A4 at 72dpi(Mac/Linux): http://www.a4papersize.org/a4-paper-size-in-pixels.php Setting A4 as your papersize would have the same effect. I don't have a mac and haven't tested on linux, what are the px dimensions of an A4 pdf document for you at 100%? On windows they're A4 at 96dpi, I'm guessing you get 72dpi(595x842)? It's been a while but I think you need to upscale your viewport from 72dpi px to 96dpi. On 1.9.8 I used a similar technique that @jimclarkuk provided, though mine scaled up(120dpi to 96dpi). The windows workaround on 1.9.8 wasn't perfect however, if you can get away with it, you should be able to adjust the paperSize to fit your viewports(probably not the same px width/height) and then alter the zoom on the pdf viewer to see the document as intended. Another alternative could be to run a windows VM or use a web service like Azure to run Phantom on a windows instance. |
Just to clarify @polarathene on Linux setting "A4" as paperSize doesn't work. The content is sliced off on the right hand side. I have to explicitly set the pixel width&height to get it to work on Linux with v2.0.0 |
@Feendish what viewport size are you using with your papersize? |
I'm not setting a viewport. I always assumed it was one or the other based on Phantom examples. Should I be setting one? In 1.9 branch it worked without viewport. |
I'd be interested to know if your results are different after setting the viewport. If you get a full A4 pdf filled with the website, also try setting your viewport to half just to confirm that you're getting half once it's rendered to pdf format. My understanding is that there is a default viewport size, I can't recall what that is though. Plenty of responsive sites will adjust based on the viewport you provide, as well as fixed width sites. Both I imagine can be affected by having a poorly chosen viewport size? |
@polarathene @Feendish I tried to play around with setting different viewport sizes, and it changed nothing with PhantomJS 2. |
@thomasbachem it would depend on the site you're rendering. If you use it on a responsive site that has a mobile layout at a small viewport, changing your viewport to a small size should trigger it just like resizing your chrome window would. I think rendering will still scroll the viewport if needed to fill in the papersize? I'll be using phantom again soon, perhaps can set up an example project for the issue with workaround :) Honestly though, the issue is with phantom, with 2.0.0 osx/linux got the problems windows had with 1.9.8, while on 2.0.0 windows works like osx/linux used to. Whomever worked on that part of phantom should be able to provide a fix, even if it's a different build which breaks windows, I'd imagine that'd be the quick fix. |
If phantomjs itself is the cause, I can only see tinkering with the values here: https://github.com/ariya/phantomjs/blob/2.0/src/webpage.cpp#L1061 that seem like they'd be relevant, but it might actually be handled by QT which was updated with 2.0.0. I see plenty of references for 96dpi, perhaps dpi handling has changed between the QT versions used in 1.9.8 and 2.0.0....which'd mean phantomjs won't ever fix this issue until QT does? I have no QT experience, if someone from the phantomjs team could chime in, is it a QT bug or has phantomjs done something differently with pdf rendering via QT since? |
Setting a viewport of
has no effect on the rendered page. |
@Feendish try 100x100,if you're still getting no difference then tweaking viewport won't help much. Again I did say it completely depends on the website design itself. For the website I was working with, js scripts were generating highchart graphs based on viewport width, they rendered incorrectly without setting the viewport properly. |
+1 this sucks really bad :( |
Wow, phantom js dev seems dead, or just noone caring for the issues coming up. How can a zoomFactor issue persist for that long? It is one crucial function. Switching to electron pdf now. Works like a charm. |
Hi there, |
From my fiddlings, the solution I have come up with is to set the paper size to what it should be (A4 or whatever), then simply set the width of the document on the body tag in pixels, that seems to zoom it to fit the page to the paper size you have set. I have rewritten rasterize.js to do this for you with a DPI setting. On the commandline use:
Use the option names defined in args. Also you can use - for either input or output to read from STDIN or STDOUT:
I also had an issue where 2.1.1 rasterized everything on Linux, so I am now using 1.9.8 on there, which this script compensates for, so should work with old and new versions. Note that this fix relies on your content being responsive (not in a fixed width container), it basically sets the width of the body tag, and the output zooms it to fit on the page. |
This really has to be re-opened. The workarounds above are hacks, should not be necessary, and so far I've found they can't handle my more complex reports, whereas 1.9 was stable (until #14558 which has been closed but not fixed). I'm marooned. |
@geoffcallender The issue is closed because there's a fix in master that will be part of the next stable release of PhantomJS. However there hasn't been any activity in this project in quite a while now and I suspect it's dead so chances are there won't be a stable release. |
@geoffcallender You could try electron-pdf. I'm holding out for headless chrome. For anyone else stuck, this will help your poor souls: /*------------------------------------------------------------------------------
PDF
--------------------------------------------------------------------------------
This file contains styles for the main layout used to generate PDFs.
Basic styles should be kept separate from renderer-specific fixes.
PhantomJS-specific styles are at the bottom of this file
------------------------------------------------------------------------------*/
html.pdf-renderer {
/*----------------------------------------------------------------------------
Global styles
----------------------------------------------------------------------------*/
body {
background:#fff;
}
.main-container {
width: 800px;
}
/*----------------------------------------------------------------------------
Global fixes for PDF rendering
----------------------------------------------------------------------------*/
// Remove box shadow:
*,
*::after,
*::before {
box-shadow: none !important
}
// print helpers: ------------------------------------------------------------
// Add to elements to force page-break behaviour.
.page-break-before {
page-break-before: always !important;
float: none;
}
// This is usually the solution you need. Add this to anything, and the page should not break inside it. If this didn't work, you have a child element with a 'float:' set. Remove it.
.page-break-avoid {
page-break-inside: avoid !important;
float: none;
}
.page-break-after {
page-break-after: always !important;
float: none;
}
// PhantomJS-specific fixes: -------------------------------------------------
&.is-phantomjs-pdf {
/**
* This CSS class is added by phantomJS. Set 'injectJs' option to a new
* javascript file that contains this one line:
document.documentElement.classList.add('is-phantomjs-pdf');
*/
// Fix extra blank pages
height:0;
body {
// Fixes scale issue (renders at 96dpi instead of 72dpi)
// https://github.com/ariya/phantomjs/issues/12685
zoom: 0.65;
// Fixes text color:
color: inherit !important;
}
// Fixes ugly unstyled checkbox inputs:
input[type=checkbox]:not(.checkbox) {
-webkit-appearance:none;
border: 1px solid #ccc;
border-radius:2px;
height:1.16em;
width:1.16em;
margin:0 0 0 0;
display:inline-block;
vertical-align:text-bottom;
position:relative;
&:checked::after {
content:'✔';
display:inline-block;
width:1em;
height:1em;
-webkit-transform: translate(0, -1px);
}
}
// Examples of some PhantomJS-specific fixes we found ourselves needing:
// Chartist SVG fixes:
.ct-chart svg {
.ct-grid.ct-vertical {
stroke-dasharray: none; // should be '0', but we must use 'none' for PhantomJS
stroke: #eeeeee !important;
}
}
.widget {
// Border fixes:
.widget-heading {
border-bottom: 1px solid #ddd;
}
// Button fixes:
.btn {
padding-bottom: 3px;
}
}
}
} |
In my case,
but page layout is broken so, I use this page_size (a4 / 0.75)
it realy work good! |
Just adding to this, and hopefully saving a few headaches for people. the devices DPI is taken into effect in this. We run phantomJS on an AWS machine that we remote into, one of our dev's (who has a 300+dpi laptop) connected and restarted the server, which updated the DPI of the server itself, causing all PDF outputs to become really small. we had to connect with a standard machine (non retina) to reset it back to normal. |
Thank you all for posting your solutions. I combined two of the above answers and was eventually able to get it to display properly using the following in my css: html {
height: 0;
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
transform: scale(0.53);
-webkit-transform: scale(0.53);
} For me, the key was setting the height to 0, without was causing my single page pdf to take up two pages. |
Hey @jazo10 so how can you set the AWS machine DPI setting? |
@PierBover <https://github.com/PierBover> the only way i was able to was to
change my local machines resolution back to 1080.
It seems that the RDP client inherited the resolution of the laptop i was
using, and passed it through.
|
Headless Chrome through Puppeteer is much better than this as it uses the latest Chromium rather than an ancient version of QT. Produces much better results. |
@SWGFL did you get header and footer configurable? |
@kromit since Chrome/Chromium headless supports CSS3 now we can probably configure the header and footer via CSS instead of via custom PDF libraries. Check https://stackoverflow.com/a/46368450/487813 it is useful. It's not native but then again CSS3 page styles are there just for this reason (I think). |
Version 1.0.0. of Puppeteer has just been released, and this includes now support for headers and footers. See https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagepdfoptions |
@SWGFL thanks for the suggestion! It seems rendering an HTML string is done using |
FYI: You might have more milage in using:
rather than:
|
Thanks @SWGFL . We're on national holidays here, but I'll report back once I've made some tests. |
I'm running with this issue too. PhantomJS 2.1.1 here. In Windows is working flawlessly. In Linux, it appears zoomed and with text centering and other minor CSS issues (strange btw, because the WebKit version should be the same in both binaries). Any advances? |
@fergardi phantomjs was discontinued, try headless chrome |
Wow. Per suggestions above for >2.0.0, I had luck enlarging my A4 for pdf generation by scaling the html css style from within the rasterizer.js just before the page.render. page.evaluate(function () { |
The problem with using "transform: scale(0.75);" is that it broke the page break. The only method I found is that to set the options below. BTW, I use html-pdf which is wrapper around phantomjs, and I want letter size (8.5 inch by 10 inch) for the pdf. let width = 8.5, height = 11.0; // Letter size in inches
if (process.platform !== "win32") { // phantomJs has issue creating pdf in linux; has to zoom 1/0.75 first, then use ghostscript later to resize to letter size
width /= 0.75;
height /= 0.75;
}
const options = {
"height": `${height}in`, // allowed units: mm, cm, in, px
"width": `${width}in`, // allowed units: mm, cm, in, px
}; The above settings should give good pdfs if you open the file with Acrobat Reader. The only caveat is that the pdf is not letter size but 4/3 larger than letter size. If you want perfect result, you can then use ghostscript to resize the pdf to letter size. The command is: const { exec } = require("child_process");
function execPromise(command){
return new Promise(function(resolve, reject){
exec(command, (error, stdout, stderr) => {
if (error) reject(error.message);
if (stderr) reject(stderr);
resolve(stdout);
});
});
}
const inputFiles = '/tmp/input.pdf';
const outputFile = '/tmp/output.pdf';
let command = `gs -dNOPAUSE -dFIXEDMEDIA -dPDFFitPage -sDEVICE=pdfwrite -sPAPERSIZE=letter -sOUTPUTFILE=${outputFile} -dBATCH ${inputFiles}`;
await execPromise(command); // sorry, I used await outside of async; you know what I mean :-) |
I realize this issue is now closed, however I thought I would share my simple solution for this problem. I can't guarantee it will work for you, but alas - it worked for me. I'm using phantomjs 2.1.1. In summary - set the I think For example (taken at random from someone's code above in this thread):
This is what I do:
|
Thanks this kind of works. The only downside is when you try to print the pdf created like this from chrome. You need to change the scale property to fit to paper, because default would print it bigger. |
I compiled PhantomJS 2 HEAD on OS X 10.9.5 (MacBook Pro Retina) via
brew install phantomjs --HEAD
.When rendering a PDF via
rasterize.js
, the page contents are rendered much larger than with PhantomJS 1.9, and using thezoom
argument doesn't change anything at all.Experimenting with
paperSize
, the page contents that do usually fit exactly into 210mm (A4) do now need 303mm, so there's a 144% increase in size.The text was updated successfully, but these errors were encountered: