Phantomjs: PhantomJS 2: PDF rendering too large, page.zoomFactor doesn't work

Created on 28 Oct 2014  Â·  198Comments  Â·  Source: ariya/phantomjs

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 the zoom 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.

Bug PJS core

Most helpful comment

+1 experiencing exactly the same problem.
compiled from source (eddb0db1d253fd0c546060a4555554c8ee08c13c) on debian 7.6

any idea how to work around this?

edit: used css to work around the problem for now
downsides: rendering gets a little ugly and its still a pixel too wide i'd say

html {
    zoom: 0.68; /*workaround for phantomJS2 rendering pages too large*/
}

All 198 comments

+1 experiencing exactly the same problem.
compiled from source (eddb0db1d253fd0c546060a4555554c8ee08c13c) on debian 7.6

any idea how to work around this?

edit: used css to work around the problem for now
downsides: rendering gets a little ugly and its still a pixel too wide i'd say

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:

I've just done some thorough testing of 2.0.0 PDF conversions and noticed the paperSize 'A4' definition that was 992px wide(120dpi) in 1.9.8 is now 595px wide(72dpi) in 2.0.0. Previously in 1.9.8 your unit values other than % had were scaled down, so that the PDF version required you to zoom to 125% to view units at their original size, also caused the whitespace issue on the right present in your picture due to that scaling. In 2.0.0 units don't appear to be scaled down, they are 100% matching to the browser. paperSize however is now scaling up from it's given px size by 1/3rd, this is matching it to 96dpi/96px per 1 inch which is a CSS inch. Thus 72DPI 595px A4 paperSize is resized to 794px 96DPI A4 when rendered. I've also learnt from OSX(and likely Linux) users that 1.9.8 provided 100% match for their PDF renders but with 2.0.0 they're having to downscale their units from 96dpi to 72dpi, eg 794px wide element needs to be changed to 595px for correct 100% zoom A4 PDF, for comparision on 1.9.8 with windows users that meant changing from 96dpi to 120dpi, 794px wide element needed to be 992px wide. Also worth noting is that between both versions % units would still remain precise, 90% element would always be 90% of the PDF at 100% zoom, for whatever reason they were not scaled like other units.

+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
HTML source -> http://s000.tinyupload.com/index.php?file_id=97390552363329839541
Bootstrap override.css -> http://pastie.org/10011951

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

page.viewportSize = {
width: 595,
height: 400
};

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 :(

Can someone provide a working example? So can take a look on it.

@Vitallium That'd be great, thanks in advance! There is a test case in #12936.

You can also just compare the PDF output of any web page with rasterize.js in 1.9.8 and 2.0.0.

just throwing my hat into the ring... also have this issue. switching back to 1.9.8 for the time being.

@floundies

paperSize: {
  width: (width * (72/96)) + 'px',
  height: (height * (72/96)) + 'px'
}

This seems to solve issues of broken PDF rendering on 2.0, the reason being they have made changes to the DPI in some way, detailed discussion here: https://github.com/ariya/phantomjs/issues/12936.

Let me know if that works for you.

@dhwaneetbhatt Doesn't work for me. Why reduce page dimensions when the rendering is _too large already_?

@thomasbachem You are using OSX/Linux? From what I understand you have 72dpi being used by the OS, and the browser displays at 96dpi. So when you provide px values those get scaled up to 96dpi and then rendered to PDF, @dhwaneetbhatt is reducing those values to 72dpi so that Phantom will return them to the size you wanted at 96dpi as you see in the browser. Alternatively provide the value in inches and multiply by 72, should have a similar effect.

So just to clarify, Phantom appears to upscale your px(and other units besides %) values to 96dpi, take the pic then save it back to your pdf which the image is too large for the original intended size. When you provide the size in 72dpi it should be corrected and look right. I use windows so I cannot verify this, on 1.9.8 I previously had to change my values from 96dpi to 120dpi due to the rendering being too small. This wasn't perfect though, and needed some extra code to scale css or text I think....which still wasn't 100% correct for some websites.

@polarathene Yes, I'm using OS X 10.9. I get what your saying, and it sounds reasonable, but it doesn't work on my environment.

As noted above and also observed by others here, the upscale factor is 1.44, so you need to e.g. set the CSS zoom property to 0.69 (= 1 / 1.44) to fix it. Dividing 72 and 96 dpi (= 0.75) doesn't lead to this number however.

Furthermore @dhwaneetbhatt proposed to _reduce_ the page dimensions, but the content is rendered too large already, so we if we were going to work around this by manipulating page size (which sucks as I want an A4 PDF) we'd need to _increase_ page size.

A4 at 72dpi should roughly be 597px by 842px, try using that as your paperSize? I'm assuming that when you provide paperSize as A4 it's using a different value? I see the zoomFactor solution as a bit odd at 0.7, fairly certain it's due to DPI, whatever caused the problem for OSX/Linux users with 2.0.0 fixed the same issue for Windows users in 1.9.8, I'm pretty sure that either PhantomJS or QTWebkit has changed the way it handles DPI.

Again to clarify, you are reducing the values so that Phantom renders at the correct values. With Windows we had to increase the page dimensions for content that was rendered far too small and this was a DPI issue with units. zoomFactor only scaled a portion of the the website correctly(text I think) when I tried that prior to rescaling the units before passing on to Phantom. It might have changed or be different for OSX/Linux users however.

Worth noting, depending on the website you're rendering, you may want to also adjust your viewPort size as well, I can't recall if I matched them or if one of these had not been affected by the rescaled units. What you need to keep in mind is that Phantom is adjusting your units prior to rendering, and that an A4 PDF has DPI of 96, at least on Windows which is a width of 8.3in to 797px at 100%.

Just to verify, does increasing the paper size work for you as you are stating it does? Or does reducing it have the desired effect?

My solution

           var zoom = page.zoomFactor;
            page.evaluate(function(zoom) {
                    document.getElementById('body').style.zoom=zoom;
             },zoom);
            page.render(output);

Also experiencing this problem when using Phantom 2.0 on Linux, using 96 DPI. I'm using the following paper settings:

page.paperSize = {
    format: 'A4',
    orientation: 'portrait',
    margin: '1.5cm'
};

Rendering a report without any zoom settings (as mentioned by @elgarfo) results in my document being rendered as following:

broken

The resulting PDF spans multiple pages in the above screenshot. If I apply the following CSS:

body {
    zoom: 0.53; /* using 0.55 or higher results in the elements not lining up correctly */
}

I instead get the following PDF:

correct

This particular PDF only spans a single page (as intended, clipped off in the screenshot). The downside is that some text is a bit fuzzy and the spacing between certain elements is a little bit different.

@YorickPeterse Can you read my previous message and try setting the paperSize dimensions yourself instead of 'A4'? If that doesn't work can you also try adjusting the viewportSize dimensions as well? It's been a while since I've used Phantom, would be helpful to others if you can confirm my assumptions of the 2.0.0 linux/osx issues being similar to the windows issues in 1.9.8.

@polarathene Using these settings I get a PDF that does fit on a single page, although said page (and its content) are much bigger than a usual A4:

page.viewportSize = {
    width: 1030,
    height: 1500
};

page.paperSize = {
    width: page.viewportSize.width,
    height: page.viewportSize.height,
    margin: '1.5cm'
};

These particular dimensions were based on the dimensions of the PDF, I set them in such a way that the width/height are enough to fit the document into a single page. Printing the resulting PDF works perfectly fine (probably because the printer downscales the PDF), so for now this should do the trick.

@YorickPeterse I'm using the same environment as yourself (Unix).

My workaround for v2 was as @polarathene says to explicitly set pageSize:

page.paperSize = { width: '595px', height: '842px', margin: '0px' };

The reason for those specific numbers for A4 is that DPI for Unix is 72.
A4 Portait in inches is 8.26772 x 8.26772 which translated to 595px by 842px.

Setting a viewPort has no effect.

It looks to me that the code isn't accounting for the fact that Linux is 72DPI. It assumes it's 96 which throws off all the calculations.
.

@itgslabs

page.paperSize = { width: '595px', height: '842px', margin: '0px' };

These particular settings still result in content clipping out of the page:

clip

If I recall correctly, setting the viewport size can have an effect depending how your site works. For me I had a highcharts graph that set it's size based on the viewport size given not the pagesize. I'd have to look into my old source code but I am pretty sure for 1.9.8 on Windows, one was set to the A4 at 96dpi px size, and the other was set to 120dpi(page size I think).

For linux/osx you'd be using dimensions for 72dpi as @itgslabs confirms. When rendered the pdf at 100% should match in px the dpi it's being displayed at for A4? I cannot confirm on other OS but for Windows pdfs display at 96dpi thus a width of 794px.

I do remember that I also had to apply a CSS transform in addition to this, these seem familiar:
http://stackoverflow.com/a/10559205/2639089
https://filippo.io/taking-retina-screenshots-with-phantomjs/

You'd just want to do the opposite of scaling up. An alternative also might be SlimerJS.

Doh! I just wasted a few hours getting 2.0 built and ready on Ubuntu 14.04 to discover A4 PDF's are doing this (cutting off the side of the page).

Does anyone have a working solution? Setting page dimensions didn't make a difference.

Do we understand to what extent this is PhantomJS .vs. Webkit's fault? Pinning that down seems like it needs to be the first step.

Is it even realistic to expect the same results from PhantomJS PDF export, as they are in Chrome/Chromium print preview / Save as PDF? I mean...that would be awesome!

To get this, I think we need to match PDF export settings. As far as I can tell from Chrome export settings, that would be

Format: A4,
Orientation: portrait
DPI: 600
Margin left: 0.4"
Margin top: 0.4"
Margin right: 0.4"
Margin right: 0.39"

I also tried to export some wide table and failed (table got cut off, similar to @davidwindell), but I need to investigate a bit more.

This not very elegant solution worked for me: pulled 1st1@de90d0712f20dd7a68eb5ac5b302e535ced5a7f4 onto release 2.0 and replaced the hardcoded 72dpi values with hardcoded 96dpi values in the function stringToPointSize().

@MarttiR broken link?

Does anyone have any idea on where this bug might live or how to start tracking it down? It's tough without any experience with this codebase, so does anyone with experience have ideas on where to start searching?

@mgartner It's possibly not in PhantomJS codebase but a change in QT's webkit. Or look at @MarttiR 's fix. From when I worked with the issue on Windows in 1.9.8(now fixed but an issue in Linux/OSX), I noticed that the input values at some point are altered(DPI thing), and while that also transforms units other than px such as mm, cm, etc; it did not affect % 100% remained 100% of the final document size, as did 50% stay at halfway. I assume those unit transformations are consistent with Linux/OSX in 2.0.0, so I'd look for code that is handling these unit conversions.

Alternatively if @MarttiR 's solution doesn't cause any problems, define constants for each supported platform DPI and perhaps a custom DPI variable, if you can detect the platforms DPI default to that, and have a cli flag enforce using different platform DPI's or a custom DPI value. Would there be any issues with that solution?

The company I work for desperately wants to upgrade to 2.0 to get web font support, but this bug is currently preventing us from doing so.

As we don't have in depth knowledge of this repository or WebKit, we were considering putting up some money on bountysource.com or a similar website to try to get this fixed as soon as possible. Has anyone had success with this approach, and would someone be willing to take a serious stab at it if we put some money behind it? Any idea what a fair price would be?

@Vitallium When was this fixed in dev? I had a look at recent commits from this year and didn't notice any related to the issue. Any idea how far off a release containing the fix will be?

@polarathene I fixed this issue but didn't push the fix yet. (https://github.com/Vitallium/phantomjs/tree/custom-dpi)

eagerly awaiting this PR!!!

I really appreciate you producing a fix for this @Vitallium. After building your branch though, I can't work out how to use it xP Is it possible / how does one call those methods be from the JS? Cheers

+1 this issue is holding us back

Hi @ZimbiX

Did you manage to get this working? I was waiting for someone else to try before I did this in JS also.

@TheSmokingGnu I'm afraid not =( I've really spent far too long trying to do adequate PDF export, and to be so close is rather frustrating.

+1

@vitallium I'm having trouble building your custom-dpi branch on debian 8 64x. the 2.0 branch builds just fine using the instructions on phantomjs.org/build.html. I don't have any experience with make, but here's where the output fails, less than a minute in:

Building main PhantomJS application...

cd src/ && ( test -e Makefile.phantomjs || /home/phillip/Projects/phantomjs/src/qt/qtbase/bin/qmake /home/phillip/Projects/phantomjs/src/phantomjs.pro -o Makefile.phantomjs ) && make -f Makefile.phantomjs 
make[1]: Entering directory '/home/phillip/Projects/phantomjs/src'
make[1]: *** No rule to make target 'qt/mkspecs/linux-g++-64/qmake.conf', needed by 'Makefile.phantomjs'.  Stop.
make[1]: Leaving directory '/home/phillip/Projects/phantomjs/src'
Makefile:42: recipe for target 'sub-src-phantomjs-pro-make_first-ordered' failed
make: *** [sub-src-phantomjs-pro-make_first-ordered] Error 2

Thanks for your work on this issue, there seems to be a lot of us here waiting for this to be sorted out!

update
I needed the libicu52:i386 package to get the build working, I only had the 64 bit version.

Hey guys, it would be nice if someone could compile this branch and test it to check if we really fixed this issue. Thanks!

To set custom dpi, use page.settings.dpi property.

Hi @Vitallium

I'm having problems setting the dpi. I tried
page.settings.dpi = "75";
then
page.settings.dpi = "120";

and I didn't see any difference, is there some way I can hard code the value.

I tested this by compiling and running on:

Linux version 3.2.34-55.46.amzn1.x86_64 (mockbuild@gobi-build-31003) (gcc version 4.6.2 20111027 (Red Hat 4.6.2-2) (GCC) ) #1 SMP Tue Nov 20 10:06:15 UTC 2012

My javascript is as follows, I've added it to the rasterize.js that is included in by project (I didn't put the rasterize file there, but I'm stuck with it. The arguments I'm using are: token reportPath "A4") so I'm only setting address and output. Do I need to set a zoom factor and papersize also?

var page = require('webpage').create(),
    system = require('system'),
    address, output, size;

if (system.args.length < 3 || system.args.length > 5) {
    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    phantom.exit(1);
} else {
    address = system.args[1];
    output = system.args[2];
    page.viewportSize = { width: 1100, height: 750 };
    if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
        size = system.args[3].split('*');
        page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
            : { format: system.args[3], orientation: 'landscape', margin: '0cm' };
    }
    if (system.args.length > 4) {
        page.zoomFactor = system.args[4];
    }
    page.settings.userAgent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36';
    page.settings.dpi = "120";

Oh, and and thanks for your work so far @Vitallium it's really appreciated!

@petergrainger could you please try again? I pushed small changes.

Thanks @Vitallium compiling now.

Hi @Vitallium

I'm still unable to alter the dpi value
I tried with an integer
page.settings.dpi = 120;
and a string
page.settings.dpi = "120";

but I still can't see any change in the output. I can change the page size to fit or make the original page smaller but it doesn't look as good, thanks anyway. It worked OK in previous version (1.9) :) I would use that but I can't get it to work with https TLSv1.2

I was able to change DPI on Windows and OS X. I'll check it on Linux.

@Vitallium I was able to build on a fresh debian jessie chroot (commit 21722f70cb5220638a6088bbc86f35d67dc9c5ed), but like @petergrainger I'm seeing no effect with setting page.settings.dpi. I am using a modified rasterize.js, similar to peter's.

I booted into my pc's os x 10.10.1 hackintosh partition, and built the same commit there, and was still unable to see any changes when messing with page.settings.dpi. Maybe it has to do with other variables like zoomFactor, but I can't seem to get dpi to matter no matter what i fiddle with. Here's my script, like I said, pretty similar to peter's.

var page = require('webpage').create(),
    system = require('system'),
    address, output, size;

if (system.args.length < 3) {
    console.log('Usage: rasterize.js URL filename.pdf dpi zoomFactor');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    console.log('  image (png/jpg output) examples: "1920px" entire page, window width 1920px');
    console.log('                                   "800px*600px" window, clipped to 800x600');
    phantom.exit(1);
} else {
    address = system.args[1];
    output = system.args[2];
    page.viewportSize = { width: 1000, height: 600 }; //this viewport forces bootstrap's medium grid pattern
    size = system.args[3].split('*');
    page.paperSize = size.length === 2 ? { width: '8.5in', height: '11in', margin: '0px' }
                                       : { format: '8.5in*11in', orientation: 'portrait', margin: '0.25in' };
    page.settings.dpi = system.args[4];
    page.zoomFactor = system.args[5];

    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit(1);
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

Got it working hack-ily. Setting the zoom factory dynamically on the body, via evaluate. Still, I hope a fix comes through.

Hey @Vitallium - unless you recently changed it, I believe it's page.dpi not page.settings.dpi. I am seeing some changes when altering that setting but many page elements are still rendering too large - it seems to be primarily affecting padding/spacing.

As an update: I seem to have isolated the problem to some kind of issue with body elements being scaled up incorrectly. Using the compiled bugfix branch, setting page.dpi = 96.0;, and adding body { min-width: 1200px; } solved all of my issues.

I am able to use page.settings.dpi to achieve the desired result.

There are some strange bugs however. For example, setting page.paperSize to Letter, and viewportSize.width to 2275, and dpi to 150 makes a 100% width div render within the confines of the produced 8.5in page, but measuring clientWidth on the body or div elements then returns 2275 pixels instead of what ends up being printed. I will try and put together a small demonstration case later this evening or tomorrow.

hey @zeroedin-bill what exact setup did u use? i tried building custom-dpi from @Vitalliums repository, but was unable to get any changes by setting page.dpi or page.settings.dpi.
i've used a fresh debian 7.8 x64 machine for building. i tried setting absolute pixel sizes and millimeters for the page and neither worked for me.

Has anybody had success with @Vitallium's branch on linux?

I had success with it (along with my comment above) on Ubuntu 14.04 LTS.

@schneidmaster i need to try that. thank you for the ubuntu version info.

does not work for me.
i installed ubuntu 14.04.2 lts in a virtual machine and built custom-dpi branch of @Vitallium. i've used the testcase from #12936 with an added page.dpi = 96.0 (also tried 72 and 120) right after var page = require('webpage').create(); but nothing changes. something is still odd. anyone else had any success with the custom-dpi branch?

@elgarfo same here, changed page.dpi = 96.0; but no changes at all

Did y'all also add body { min-width: 1200px; }? That was the key for me.

No, the page.dpi and page.settings.dpi setting to 96.0 doesn't do any effect. @schneidmaster, i think your solution is the min-width itself, the dpi does also not effect on your side, I guess

I've experimented with @Vitallium branch (on linux Centos) after compiling for 10h!.
So, page.settings.dpi has effect _only_ if page.paperSize is set in px, it won't have any effect if it is set as A4 or in.

I've set page.settings.dpi = 72 and page.paperSize = { width: '595px', height: '842px', margin: '0px' } according to the rules read in this thread and here to have an A4 page dimension but I had not luck.
Using these settings result in the pdf being clipped because the original page is too big to fit in it. Changing viewport or zoofFactor has no effect for me. Also setting body { min-width: 1200px; } as suggested by @schneidmaster won't change anything.

Weird thing is: my original container's width of the web page is 1100px and if I set page.paperSize.width = '1100' @72dpi it will fit in width perfectly. But the point is that most probably this is not the correct size for printing an A4...any idea?

@LeonardoGentile indeed, the dpi setting takes place, if the paperSize is set to "px".

What I can suggest you is to set the dpi to 96.0 and use following:

page.paperSize = { width: '1122px', height: '793px' }; page.settings.dpi = 96.0;

or vice versa for potrait

@LeonardoGentile You set the paperSize width to 595px for 72dpi A4 width, then later you tried setting a min-width of 1200px but you didn't try that as a paperSize width value. You then tried paperSize width of 1100 without px unit? Do you get the same result with the px unit included, or was the omission a typo?

Just to note, 992px is 120dpi A4 width. 120dpi is Windows native dpi and I've talked about the differences between PhantomJS 2.0 and prior with this issue previously. What used to happen is PhantomJS was converting 96dpi(CSS) to 72dpi(Linux/OSX), and now with 2.0 the bug has done a 180 and Windows platform no longer has the scaling issue(opposite to clipping, result would be downscaled with whitespace), so now it seems that the conversion is 96dpi(96px=1inch) to 120dpi(120px = 1inch), and due to this px values are upscaled.

This is from memory, if something I've said is off, try track down my earlier responses(February?) where I investigated and shared my findings. Another confirmation to add to your response should be if the PDF at 100% zoom is 1:1 scale with the browser version, presumably it's been upscaled when rendered to PDF and that is the reason for your clipping. With the width corrected to 1100 measure the width of your PDF at 100% zoom, it is likely around 660px? That'd be 1100px from 120dpi converted to 72dpi which is the usual PDF display value.

@mapodev your settings didn't work for me: page.paperSize = { width: '793px', height: '1122px' }; page.settings.dpi = 96.0; still results in my page being clipped.

@polarathene the 1100 was a typo, I used px values. I followed you suggestion, so I used paperSize.width = 1200px with min-width : 1200px and the page resulted being downscaled at 72dpi with white empty space on the borders while being clipped at 96dpi.

So I then I've experimented following what @polarathene said. I set 72dpi but applied the pageSize as if it was 96px (1123px*794) but the page resulted still clipped, so I kept on until I found that my page fits perfectly by setting 72dpi but applying a paperSize as if it was 130dpi, that is 1520px*1075px, check here for playing around: http://www.hdri.at/dpirechner/dpirechner_en.htm

Even tough the page fits in the pdf and the proportions seems ok, when I try to print the pdf, the print preview (in A4) cuts some part of the the page (at least 1/3) if I don't explicitly chose to downscale from within the the pdf viewer print preview. So this is still not a solution unless I'm misunderstanding something

@LeonardoGentile So to confirm, at 100% zoom on PDF, you have 1:1 scale to the browser version correct? And if you measure the PDF width it should be a 72dpi version of your paperSize width in px I think?

Remember that dpi is related to the physical density(inches), and px values are just a result of displayed content. In Windows I get PDF A4 dimensions displayed at 72dpi in px, even though I provided 120dpi paperSize values. I think with 2.0, 100pxin CSS(96dpi) translated to 100px at 100% on PDF(72dpi). If you could confirm that your platform is also displaying the PDF at 72dpi values that'd be helpful, I believe for A4 the PDF output is meant to be 72dpi px values and when you print dpi could be whatever the printer supports, with content apart from images scaling to the increased resolution/density perfectly fine. The print preview is presumably working with inches or a fixed dpi, so clipping should occur when you exceed what it expects for A4.

If I can find the time to come back to this issue, I'll try document everything myself instead of repeating it on these issues, it gets a bit complicated with PDF displaying at it's own dpi setting, browsers working with 96dpi CSS inches(1 inch doesn't always translate to 96px I think?) and then OS with their internal dpi 120 on Windows, 72dpi on Linux/OSX, but this shouldn't be confused with the dpi the screen.. I also recall prior to 2.0 when this problem was on Windows platform instead, that additional code was required that performed a CSS transformation to rescale the content prior to conversion via Phantom. Also worth noting is that % values in your CSS translate correctly, so 50% should be 50% on the PDF.

Does @Vitallium 's branch with the dpi feature do anything in your testing? From what I've read here no one is seeing a diffrence with different dpi value settings?

@polarathene what do you mean 100% zoom pdf? Is it supposed to be svg so it should scale to any dimension, I'm not aware of a 100% zoom..maybe my reader doesn't support it..

About your question, I don't know how to confirm that my platform is also displaying the PDF at 72dpi values. Anyway, I'm still not satisfied with the result, something is wrong about the dimensions..

i've now checked with different settings.
not setting page.dpi at all and setting page.paperSize = { width: '1060px', height: '1500px', border: '0px' }; yields a pdf which is 200.8mm*396.9mm (and means 96dpi) that perfectly fits a html page with height: 297mm; width: 210mm; (or in pixels: height: 1123px; width: 794px;)

so the content is still upscaled from 794px to 1060px.
in conclusion it is:

  • setting paperSize and not touching page.dpi translates yields a pdf rendered with 96dpi
  • setting css sizes in mm or absolute pixels does not matter, the content gets upscaled (but for the record setting 297mm is the same as setting 794px which translates to 96dpi)

it feels like... it's something in between two steps. like: the browser takes the content and inteprets any mm values as 96dpi. then something happens and the result is not displayed in 96 but 72. then the render process starts and upscales everything from 72 to 96 because that is the desired output dpi.
the upscaling factor (96/72 = 1.33) really makes sense, if everything worked correctly. it just seems like. idk. like the browser interprets content in 96, and stores the absolute px values like that in memory but just assumes it was 72 afterwards, so the renderer upscales everyhing.

sadly, i've way too less knowledge about qt to track that down.

@LeonardoGentile Most PDF viewer allow you to zoom in/out and provide a % value, 100% as your zoom value in PDF viewer should translate to 72dpi 595px(PDF A4) vs say 96dpi 794px(Browser A4) widths. I have Foxit PDF Reader on Windows, can set zoom % to 100 and then take screenshot and measure px width of PDF. All vector graphic content(fonts/css) will be crisp no matter how far you zoom, this is true, but at 100% zoom the scale renders to px values that would be 72dpi.

@elgarfo As I have mentioned, PDF renders/displays at 72dpi at 100%, browsers render at 96dpi, and your OS have internal dpi value of 120 or 72 if I remember right. I probably have some details mixed up so will refrain from further commenting. Prior to 2.0 Windows would render the PDF content at a smaller size than the PDF output size, you'd get a bunch of whitespace, with 2.0 it's the opposite on Linux/OSX, your content gets rendered at a larger size and exceeds the PDF output size?

I think best thing that can be done is share repo's to replicate same results you experience with others. That way if it works/fails for someone and you can test on your machines to verify then developers like @Vitallium can help more :) If I need PhantomJS again I will do the same to help test/fix the bug.

@polarathene I couldn't find a way to zoom to 100% with my available mac applications (only zoom in, zoom out, zoom to fit, and so on..). If anyone is aware of an application that let me zoom to 100% of the actual size of the pdf please let me know.

@LeonardoGentile Shouldn't be hard to find, this page came up from google search: http://www.iskysoft.com/edit-pdf/pdf-reader-for-mac.html

The third listing shows zoom% in screenshot. Some Browsers can view PDF files too, when you zoom in/out you do not see a % value? It depends on software, some will open at 100% or they zoom to fit for display. Some cases it's an arbitrary zoom % though.

@LeonardoGentile in Preview, do CMD+0 or Menu > View > Actual Size.

Thanks, as a matter of fact the generated pdf with my setting doesn't respect the original size, everything seems to be enlarged. See the attached screenshots. I guess you can only see it when you download the png because github is scaling them to fit in here

ORIGINAL

original

GENERATED PDF

generatedpdf_screenshot 2

Weird, the PDF pic has width of 1400px, what paperSize width did you use? Was it around 1060px? Seems to fit with your 1.33(96/72dpi) results from earlier. For it to fit A4 for printing I think the paperSize might need to be set to 595px for width or 794px, I can't recall if it was meant to be given A4 in browser(96dpi) or PDF(72dpi), pretty sure you could use 'A4' though?

Since your webpage exceeds 794px it'd get clipped regardless I think. The enlargement is likely due to your system dpi(72dpi on OSX/Linux) and the browser(96dpi). This Article mentions the system dpi values for Win/OSX platforms, perhaps the system dpi is used for a calculation/conversion which is giving you the 1.33x upscale. As it doesn't happen on Windows anymore, that must be it? It get's a bit more confusing though since the PDF 100% view is meant to be px values of 72dpi, the original 1060px at 96dpi should become 795px at 72dpi.

Thinking about it from a physical media perspective, If I placed low dpi content such as a rasterized image into higher dpi content, it'd get smaller, and just like with the opposite, placing 96dpi content into 72dpi made it bigger. That latter case might be what is happening here. This is different from the previous assumption of digital media where we only think in pixels say instead of physical measurements. When changing the DPI of a graphic, either the pixel or physical dimensions stay constant. When the DPI of a document increases, the displayed 'pixels' get denser/smaller on the document, resulting in the graphic reducing in physical size(like changing monitor resolution). Now when decreasing density from 96dpi to 72dpi(system not PDF), these pixels would occupy more physical space(Pixels Per Inch / PPI), what I believe is happening, is physical width(inches) of the document/canvas is increased to adjust to the new DPI value, while treating the pixel dimensions as if they were still the same despite their larger size per 'pixel'. However, in digital media pixels don't get physically bigger when PPI is changed, so we see an increase in pixels used when converted/displayed via PDF. With actual printing and printer DPI it's a bit different, content physical size remains the same and the amount of 'pixels' is affected by DPI setting you print with.

If it is due to the systems DPI, I'm not sure why that is used or why adjusting the physical dimensions instead of pixels to 72dpi from 96dpi isn't happening? Maybe it is a simpler bug just doing 96/72(1.33) instead of 72/96(0.75). If it were the more complicated approach I described, if you could instead constrain the dpi conversion to the physical dimensions(paperSize) that would either clip through your 1060px webpage for A4, or possibly permit scaling further to fit your content within the physical bounds(effectively a higher dpi?).

EDIT: Came across this StackOverflow question , rather than 72dpi at 100%zoom for PDF it mentions 72pt per inch(presumably 100% zoom inch on screen should be equivalent to physical inch?). I've read in the past of browsers treating an inch as 96px, so if conversion was working correctly if 96px = 1inch in the browser, that should match 1:1 on the PDF at 100% zoom?

@polarathene thanks for your insight.
I'm giving up, I've made every possible experiment, you can read about the settings I've used to generate that pdf from my earlier comment.
@Vitallium thank you for your dev branch but it seems it doesn't fix this issue or I was not able to use it the right way. Any words on this, what is causing it and any plan to fix it? This is holding me back and I need at least 2.0 in order to support web font

@LeonardoGentile have you tried alternatives like SlimerJS? It is based of Firefox, I haven't tried it personally but it offers PDF rendering of HTML files as well.

@LeonardoGentile somebody also compiled a Phantom 1.x version with web-font support. I don't have a direct link but I suspect you could find it with some searching. I've used it before and I can confirm web-fonts work. There are, however, other problems/bugs I've run into with it.

Has anyone tried the suggestion here about using page.set instead of page.papersize? I don't have a built binary right now to test against https://github.com/ariya/phantomjs/issues/13099#issuecomment-84433694

@davidwindell it makes me endless loading when I tried to generate PDF....

@davidwindell the fix in #13099 does not work for me either. just keeps loading till i kill it. i've used a fresh build of vitalliums custom-dpi branch on linux

There seems to be a number of confusing issues here. I can't say about linux builds (haven't tried yet), but under Windows it seems that @Vitallium's fix works rather well.

1) The correct setting's key is page.settings.dpi. Not page.dpi.
2) You have to specify dpi _before_ doing page.open(). Setting it afterwards won't have any effect.
3) Under Windows, it produces correct zoom when you set it to page.settings.dpi = 96

In my own case -- prining variable-width pages to pdf scaled to fit the paper -- I'm setting up dpi, then open the page, then set up page.paperSize (in pixels, manually calculated, for example, A4 is 8.27inches wide * 72dpi (hardcoded PDF1.4 dpi) = ~595px), then measure the page by looking at document.body.scrollWidth, then calculate a zoom factor (paper size width / page width), then apply up zoom via document.body.style.zoom, and finally, render the pdf. And it looks rather perfect.

Hope this helps someone.

For me, instead of playing with the zoom to fix the clipping and loosing resolution, I enlarged the paperSize to fit the content:

My original paper size was 18x12 inches. So instead of applying a 75% zoom, I calculated the new paper size to be 24x16 inches to accommodate all the content:

page.paperSize = {
    width: (18 / 0.75) + 'in', // '24in'
    height: (12 / 0.75) + 'in', // '16in'
    margin: '0'
};

Hope this helps someone...

Now after much more tests, I admit I spoke too soon. @Vitallium's fix _does_ something (as in: I can see differences in PDFs when I change page.settings.dpi), but it certainly doesn't do it properly. And no matter what I do with DPI, I can't correctly scale documents to fit standard paper sizes unless I change in-browser document zoom level (which introduces various other problems, like text behaving badly if you downscale too much).

So in the end, I had to resort to what @mikegleasonjr describing, I'm changing the paper size to accomodate the content and basically delegate all the scaling to PDF viewers (they do it better than PhantomJS currently can).

@Vitallium I've tried your branch and can confirm that the DPI does work, IE it sets the DPI of the output. Unfortunately it retains the scaling bug, just at a different DPI, so it doesn't really help. There is a problem somewhere in the code where there is a mismatch between the chosen DPI and the size at which the output is rendered, which is always 50% larger than the size it "should" be at the given DPI. Further work needed.

@danielaborg Pretty sure I've covered this multiple times on this and related issues. If you want to look into it further, compare with version prior to 2.0 where the bug caused content to render at a smaller scale than the A4 document dimensions instead of at a greater scale. Do note this bug was only pressent on Windows, Linux and OSX were fine, whatever the change was to Phantom or QT during the transition to 2.0 the bug completely flipped behaviour and platforms.

  • As far as conversion goes, you're dealing with 96px == 1 CSS Inch, with correct viewport settings in html flie this physical measurement is dpi-agnostic(actual amount of pixels used to render 96 CSS pixels could vary).
  • From there is internal system DPI(not related to monitor DPI), this is the same value on Linux and OSX at 72 but 96/120 on windows. Some conversion is probably going wrong here as it's the only notable platform difference.
  • Finally conversion to PDF document, 72pt == 1 inch. If I recall right, the PDF viewer at 100% will try to render to the physical size as best it can. You could then print this at whatever DPI density your printer supports, vector content such as text/CSS is going to scale just fine, raster content(images) will depend on the dpi quality they were embedded into the PDF as.

Actual cause should be identified(may not be in Phantom's codebase) and any working solutions that are verified by others documented rather than lost in all these posts.

I've also been having trouble with this and have had success with what @mikegleasonjr describes. It's not a perfect solution by any means, but it works well until this is fixed.

You can try this fork: https://github.com/martonw/phantomjs/tree/issue-%2313553 (on branch 'issue-#13553') I just pushed today. We use it under linux but I suspect this works on windows the same way. We use it to print 300dpi reports in standard A4 page size in PDF. Also, I think this is a better way than playing with zoom factor as this will set the actual DPI so it will look nice for printing - or when you zoom the pdf. See an example of usage here: https://github.com/ariya/phantomjs/issues/13553.

+1 to a full on fix for this. Will loom more into people's suggestions and branches tomorrow, for now I am just setting the zoom of body in CSS.

This is possibly plain wrong to post here but slimer.js (https://slimerjs.org/) has now full support for printing to PDF in any size. You need to use the latest master/unstable branch (0.10pre -> http://download.slimerjs.org/nightlies/latest-slimerjs-master/). In most cases you can even use the same config file since slimer.js aims full compatibility to phantom.js.

@martonw thanks dude, this stuff works great. we used it for our project and it scales it perfectly on centos 6

I think the reason why everybody had a wrong scale was, that using phantomjs on unix system caused wrong zoom factor, due unix system uses 72dpi as standard and phantom has set the dpi to 96, so there was a scale by 96/72, which caused things look bigger on the PDF export, but for example using phatomjs on windows had a right scale.

Therefore setting it to the right dpi solved my problem.

@mapodev Perhaps share how you set the dpi properly, quite a few attempted that and had nothing change.

You need to set the dpi on the page object. Like this page.dpi = 72. First try it out with 300 dpi, then you should see a very scaled page.

page.open(address, function (status) {
        page.dpi = 72;
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit(1);
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 10000);
        }
    });

@polarathene to be clear the page.dpi setting will not affect anything unless you build from the fork I linked above (and make sure you checkout the issue-#13553 branch).

@mapodev that is right default DPI setting in phantomjs (which you cannot change in the current stable/master branches) is different on linux (which is 72 DPI) and windows (96 DPI). So that means if you put together something on windows and will want to run the same phantomjs script on Linux, things will not fit in the page and it will look like it is zoomed by 96/72.

Just wanted to help some people out if they're looking for a good and stable solution to render PDF's. I highly recommend ditching PhantomJS. It's poorly supported and barely functions for rendering PDFs. I've had nothing but grief using it. Even if you could get it to work using some combination of zoom hacks, it's sure to give you more problems.

A much better alternative is to use electron (see http://electron.atom.io/). It has a printToPDF function that works very well and it uses the same PDF engine as Chromium, so you'll get output consistent with the print to PDF feature in Chrome.

@jleppert Is that only an alternative for desktop apps though? What about server side web apps?

A quick Google suggests that solutions exist but currently require a UI (e.g. xvfb on Ubuntu).

Looks like there's work being done to support a headless version of Electron which would be awesome...

https://github.com/bjrmatos/electron-html-to
https://github.com/atom/electron/issues/228

Very keen to hear if you've got a server working with Electron @jleppert (and how you've set it up) :)

@jleppert @polarathene @PaddyMann It's not surprising that in some cases PhantomJS doesn't suit your need but Electron works well for you. However, let's stay on topic and keep this issue focused on the PDF's zoom factor problem. I'm sure there's another forum where you can compare notes and discuss your Electron use case!

I ran into the same problem. I added "zoom: 54%" to the body tag of the documents I was printing and it fit the A4 paper. It doesn't appear to lose any quality when done. This is certainly not ideal, but it is a pretty easy solution if you have access to the HTML of the documents you are printing. I hope to be able to remove this workaround when there is proper viewport support again.

Hey guys, just letting people know I've been able to make the electron working headless, and it has been working very well now serving many requests. I spawn the electron process from node. Check out this project that has a ready to go docker solution with xvfb:

https://github.com/Janpot/electron-pdf

It's really nice to be able to just use Chrome print preview, and in this case I was able to print a complicated leaflet map that required all kinds of hacks on phantom. And if I have any issues I just open electron window and troubleshoot.

Not to be rude but @jleppert please continue the discussion somewhere as it's getting off-topic and we want to focus this issue on the PDF problem.

Not to be rude @ariya but this issue has been open over a year with no real progress on a fix. A lot of people, myself included, use PhantomJS for PDF rendering. So given the lack of any reasonable warning or explanation in the official documentation, I think this is probably about as appropriate a place as any to discuss alternatives and workarounds, including use of other packages.

In the interim while PhantomJS is broken, it is nice to know about alternatives that can render properly to PDF.

Frankly @zeroedin-bill that is quite rude. This is PhantomJS issue tracker so it's perfectly fine to focus the details of the defect for the benefit of someone who will volunteer to investigate and to fix it in PhantomJS. If you think this should be about "What is my alternative of converting HTML to PDF?" discussion, why not discussing it over in e.g. Stack Overflow? Not only it can reach a bigger audience and invite other experts, but it also keep the discussion here focused on PhantomJS-related details.

I tell you what, if you open a discussion on Stack Overflow as described above and link it from here, I think that's a win-win for everyone.

@ariya Yes, that would probably work out, _if_ there were not already a massive body of posts, questions, blogs, and content pointing people _here_ for HTML to PDF rendering. There are forum posts that reference this bug ticket.

You've got a pile of open bugs around PDF rendering, and nobody with the free time and very specific and rare domain knowledge to fix them. That is _OK_. Everyone understands that open source is a labor of love and free time. Eventually I am sure someone with the time and skills will step up to fix this. In the interim, however, the correct solution is to simply fix the documentation by adding a section explaining the caveats and suggesting alternatives for the broken use case.

I won't clutter up the thread any further, but I will close by saying that I have found PhantomJS to be a very useful tool, and I very much appreciate the work you and others have done on it. I apologize for being rude.

This pageZoom factor issue is already mentioned in http://phantomjs.org/release-2.0.html (under the section _Regression compared to PhantomJS 1.x_).
If anyone has an idea on how to expand that text, edit the content (see the _Please take a moment..._ at the beginning of the page), and create a pull request for that, I'd be happy to merge it.

@ariya I've opened an issue to discuss modifications to the docs.

https://github.com/ariya/phantomjs/issues/13868

@Vitallium maybe you can shed more light on what exactly the issue is?

@zeroedin-bill AFAIR, zoomFactor doesn't work at all, e.g. it does nothing with the latest QtWebkit upgrade. To ensure the consistency of PDF rendering on all platforms we have to solve two issues:

  • custom DPI per a web page instance (I already have a WIP branch for this - https://github.com/vitallium/phantomjs/tree/custom-dpi)
  • fix zoomFactor

@zeroedin-bill This workaround seemed to address the pdf output issue for me (@YorickPeterse mentions it above.) I'm curious if you tried it? Maybe this workaround doesn't work correctly on all platforms?

page.viewportSize = { width: 1238, height: 1763 };
page.paperSize = {width:'1238px', height:'1763px'};
page.settings.dpi = 150;

Notes: I'm running main branch code on Linux (Wheezy). I did have to play around with the sizes to find one that I liked. And, I'm using a self-modified qtwebkit that turns off @media printing as per this discussion.

Hi all - for proper PDF DPI setting there is a working version I submitted previously and hopefully it will be merged soon to the master I just need some clarifications to submit the changes - see comments here: https://github.com/ariya/phantomjs/pull/13583.
The bad news that you will not be able to change PDF DPI without any modification in qtwebkit - at least this is where I ended up - see the link for detailed explanation. You can play with page size and css zoom but neither of these will change the actual DPI. Even if you manage to have a proper zoom, any image, diagram or other graphic will have a low resolution and will look ugly in the exported PDF.

@martonw That makes a lot of sense. So it sounds like to have a really usable PDF renderer we need changes to qtwebkit.

I'm running phantomjs 2.1.1 on CentOS 6.2 and having the same issue.

I tried changing viewport, pagesize, dpi setting, etc. all to no avail. The only thing that worked was setting CSS in the HTML of the page I'm rendering. Specifically setting:

<style type="text/css">
html {
    zoom: 0.55; /*workaround for phantomJS2 rendering pages too large*/
}
</style>

(I also tried 0.53 as someone else suggested, but 0.55 seemed to fit best with the 'original' PDF (pre 2.1.1).

Although this renders some lines thicker and a little off, but it's workable until theres a true fix.

I'm creating invoices in 8.5x11" format.

+1 struggling )

+1

+1 - using 2.1.1 and there is NO affect on the PDF when changing viewPortSize or zoomFactor.
Latest working version is 1.9.8 - guys!!!

13583 thank you so much @martonw this finally fixed my rendering issues. i used your pull-request to patch 2.2.0-development.

Seconded. Thanks to @martonw. I've been manually patching for awhile now.

I am very much looking forward to seeing some progress on this issue. It's been a year and a half since it was reported.

Hi! We're really sorry for taking this issue to be fixed for a so-so-so long time. Thanks @martonw for providing the fix! Landed in master (https://github.com/ariya/phantomjs/commit/dd07001e95cb21c8cb849e340f71a493013f9d65)!

Thanks!

@martonw Nice work! I've been following this issue for some time, and didn't realise that you had since submitted a fix: https://github.com/ariya/phantomjs/pull/13583. Your issue explanation there is quite good.

There are happenings in a few places regarding this issue; also relevant: https://github.com/ariya/phantomjs/issues/13553

The cross-project modifications seems to have complicated things a bit. It appears that the required changes to qtwebkit were submitted by @131 and merged a few days ago by @Vitallium: https://github.com/Vitallium/qtwebkit/pull/7

As far as my somewhat inexperienced eyes can see, the following is what now needs to happen:

  • Remove qtwebkit changes from @martonw's pull request
  • Update the qtwebkit dependency (this is probably the sticking point, with other things impacted)
  • Merge @martonw's PR

Thanks for the hard work everyone.

Haha nice xD

Good news thanks @Vitallium. If you need anything else for this merge let me know.

You guys rock!

Is this in master now as I can't get it to work?

I have tried a few of the suggested trix above without success. Thus I was wondering if there was an official script fix to solve the PDF printing issue? I am using 2.1.1.

Also is there any release binary available for this fix?

Hi,

I was stuck with the same problem with phantomjs-2.1.1-linux and finally these settings rocks for generating an A4 portrait version with 1cm margins:

rasterize.js :

"use strict";
var page = require('webpage').create(),
    system = require('system'),
    address, output;

address = system.args[1];
output = system.args[2];

var dpi = 72.0, dpcm = dpi/2.54;
var widthCm = 21.0, heightCm = 29.7; // A4
page.viewportSize = { width: Math.round(widthCm * dpcm), height: Math.round(heightCm * dpcm) };
page.paperSize = {width: page.viewportSize.width+'px', height: page.viewportSize.height+'px', orientation: 'portrait', margin: '1cm' };
page.settings.dpi = dpi;
page.zoomFactor = 1.0;

page.open(address, function (status) {
        if (status !== 'success') {
                console.log('Unable to load the address!');
                phantom.exit(1);
        } else {
                window.setTimeout(function () {
                        page.render(output);
                        phantom.exit();
                }, 200);
        }
});

CSS (extract):

@page {
    size: 21cm 29.7cm;
    margin: 10mm 10mm 10mm 10mm;
    orphans:4;
    widows:2;
}

html,
body {
    height: 100%;
}

body {
    margin:0;
    zoom: 0.75;
}

I hope it may help somebody...

This is not yet in master - it is in PR #14085. I have tested the patch by Vitallium and it works for me consistently on both linux and windows.

See my comment: https://github.com/ariya/phantomjs/pull/14085#issuecomment-203692787 for more info.

Agreed :) this works great - would be awesome to have it merged!

Merge +1

Merge +1

@TWKDreamState @jacquesfu @mskrzypek It's been merged.

I have been using PhantomJS for 3 years; version 1.9 randomly dies when creating lots of pdfs. Otherwise, it's been a great product for us. The suggested fix for this problem was 2+. Upon installing 2.1.1, I immediately ran into the issue of the zoomFactor not working at all/really huge pdfs that don't fit to A4 pages.

So I pulled master and tried to compile on Ubuntu 16.0.4 with 9GB free storage and 7.5 GB RAM. It fails every time with
Creating qmake...
.Done.
Running configuration tests (phase 2)...
No QPA platform plugin enabled!
If you really want to build without a QPA platform plugin you must pass
-no-qpa-platform-guard to configure. Doing this will
produce a Qt that can not run GUI applications.
The dependencies needed for xcb to build are listed in
src/plugins/platforms/xcb/README

I have xcb installed. I have tried modifying the build.py script to add -no-qpa-platform-guard. That will compile for awhile and then die at
kernel/qwidget.cpp: In member function ‘void QWidgetPrivate::show_sys()’:
kernel/qwidget.cpp:7921:50: error: ‘struct QWExtra’ has no member named ‘proxyWidget’
if ((q->isWindow() && (!extra || !extra->proxyWidget))
^
kernel/qwidget.cpp: In member function ‘void QWidgetPrivate::hide_sys()’:
kernel/qwidget.cpp:8056:50: error: ‘struct QWExtra’ has no member named ‘proxyWidget’
if ((q->isWindow() && (!extra || !extra->proxyWidget))
^

Makefile:47705: recipe for target '.obj/qwidget.o' failed
make[2]: ** [.obj/qwidget.o] Error 1
make[2]: *
* Waiting for unfinished jobs....
make[2]: Leaving directory '/home/ubuntu/phantomjs/src/qt/qtbase/src/widgets'
Makefile:497: recipe for target 'sub-widgets-make_first' failed
make[1]: ** [sub-widgets-make_first] Error 2
make[1]: Leaving directory '/home/ubuntu/phantomjs/src/qt/qtbase/src'
Makefile:45: recipe for target 'sub-src-make_first' failed
make: *
* [sub-src-make_first] Error 2

ERROR: Failed to build PhantomJS! Building Qt Base failed.

I will pay cash money for someone who can get me a build on Ubuntu 16.0.4 that 1) dies less often and 2) does not have this zoomfactor/dpi problem.

Thoughts? What am I doing wrong?
Thanks.
Scott

Is there a linux 64bit binary available including this fix? Just working with 2.1.1-linux and trying to get a pdf exported with 300dpi.

I am checking the pdf file using: pdfimages -list -f 1 -l 3 output.pdf which outputs the following indicating the images having only 72dpi:

page   num  type   width height color comp bpc  enc interp  object ID x-ppi y-ppi size ratio
--------------------------------------------------------------------------------------------
   1     0 image       8     8  rgb     3   8  jpeg   no         9  0    72    72  631B 329%
   1     1 mask        8     8  -       1   1  jpeg   no         9  0    72    72  631B 7888%
   1     2 image       8     8  rgb     3   8  jpeg   no        13  0    72    72  631B 329%
   1     3 mask        8     8  -       1   1  jpeg   no        13  0    72    72  631B 7888%
   1     4 image     116   136  rgb     3   8  jpeg   no        20  0    72    72 7535B  16%
   1     5 smask     116   136  gray    1   8  image  no        20  0    72    72 1141B 7.2%
   1     6 image     128   128  rgb     3   8  jpeg   no        25  0    73    73 11.0K  23%
   1     7 smask     128   128  gray    1   8  image  no        25  0    73    73 1128B 6.9%

@Vitallium That would be great if you can share any rough idea/time on when the resolution of pdf export zoom/scale issue resolved and available in the binary format?

Appreciated your efforts.

I second @ankit14101986
We have a major dependency on the ability to generate PDF documents, and the latest problems introduced across the board in phantomjs in all recent versions (1.9.x and 2.x) created total havoc. All of our customers are affected.

If there's any way to help speeding this being released up - I'd love to help.

It's not surprising this issue has yet to be fixed fully. The images are of course not respected for the DPI based upon my investigations and in fact vector content is not preserved as well, the entire thing is just one huge image. Just see for yourself with the cairo tools, open up the PDF. PhantomJS is not a good solution for rendering HTML to PDF.

Haven't read over this entire thread because it's too long. But for any interested, it was 1.9 that was mis-rendering the size and that was a known bug. I'm sure it's discussed in other threads but from what I remember it was fixed in 2. Which might explain why it suddenly broke for people who may not have been aware older phantom was wrong. Test in Weasyprint as a reference. or any other renderer.

@motoservo Not sure what the situation is currently, but iirc the problem that was fixed with 2.0 ended up appearing on other platforms instead of the affected platform(s) in 1.9. So bit of a tableflip, the problem isn't exactly the same, one was to do with images being too big the other too small from memory.

This issue should be reopened because I don't think setting the page.settings.dpi does anything.

By default, the PDF on linux tends to have bigger text. I was able to get the PDFs to render as the same size as chrome renders (i.e. the normal size) but this solution requires hard-coding desired DPI value.

A few observations

Disclaimer: these observations may be wrong but going through the source code and running my simple tests prove them to be true.

The current QWebFrame::print(...) that the current master of phantomJS uses, does _not_ scale the painter at all because in the current qtwebkit that phantomJS uses scales the painter by:

const qreal zoomFactorX = (qreal)printer->logicalDpiX() / printer->resolution() which I think works out to a zoomFactor of 1 all the time.

I found that printer->logicalDpiX() and printer->resolution() will always hold the same value: If you take a look at QPdfWriter and QPrinter, they both delegate to QPdfEngine. And if you look at the QPdfEngine::metric() with the case QPaintDevice::PdmDpiX in the qtBase, you'll see the that the logical dpi is equal to the resolution of the printer.

And since the page.settings.dpi property sets the resolution of the pdf writer the page.settings.dpi won't have any affect on the scale of the painter.


My patch fixes the multipaged PDFs and scaling inconsistency issues but again it hard codes the DPI to 96. What we really need some way to replace the hard-coded 96 with the custom DPI property set by page.settings.dpi. From the observations above, the printer->resolution() cannot be used.

I don't think it would be all that bad to hard-code this value to 96. Chrome seems to render PDFs at 96 DPI and more importantly hard-coding the value provides _consistency_. I don't think setting page.settings.dpi works in the current branch (especially because multipaged PDFs are broken).

Edit:

I think page.settings.dpi is currently broken in the master.

    pdfWriter.setResolution(m_dpi);
    std::cout << "m_dpi: " << m_dpi << "\n";
    std::cout << "pdfWriter.resolution(): " << pdfWriter.resolution() << "\n";
    QVariantMap paperSize = m_paperSize;

(i have no idea how to properly debug c++)

var page = require('webpage').create();

page.settings.dpi = 500;
page.content = '<html><head></head><body><h1>Heading 1</h1><p>The quick brown fox jumps over the lazy dog.</p></body></html>';

page.onLoadFinished = function () {
    page.settings.dpi = 500;
    page.renderBase64('pdf');
    phantom.exit();
};

This always prints 96 dpi for me.

I think the real solution is to add the methodQWebFrame::print(QPagedPaintDevice *pagedPaintDevice) to QWebFrame in webkit. QPagedPaintDevice is the super type for QPrinter and QPdfWriter. but QPagedPaintDevice doesn't have ::resolution() but if my observations are correct, then this should be the same as ::logicalDpiX.

I think a possible solution would be to change the print(...) to take in an additional two parameters.

void QWebFrame::print(QPagedPaintDevice *pagedPaintDevice, qreal dpi, qreal zoomFactor) const
{
    QPainter painter;

    if (!painter.begin(pagedPaintDevice))
        return;

    const qreal zoomFactorX = (qreal)pagedPaintDevice->logicalDpiX() / dpi * zoomFactor;
    const qreal zoomFactorY = (qreal)pagedPaintDevice->logicalDpiY() / dpi * zoomFactor;

    // similar to qprinterRect from ::print(...)
    QRect unscaledRect = pagedPaintDevice->pageLayout().paintRectPixels(pagedPaintDevice->logicalDpiX());
    QRect pageRect(0, 0, int(unscaledRect.width() / zoomFactorX), int(unscaledRect.height() / zoomFactorY));

    QtPrintContext printContext(&painter, pageRect, d);
    painter.scale(zoomFactorX, zoomFactorY);

    int lastPage = printContext.pageCount() - 1;
    for (int page = 0; page < printContext.pageCount(); page++) {
        printContext.spoolPage(page, pageRect.width());
        if (page != lastPage) pagedPaintDevice->newPage();
    }
}

I'll try to implement something like this soon and i'll post results back here.

This should fix:

  • multipaged PDFs
  • zoomFactor
  • DPI
  • renderBase64('pdf')

We should also remove support for printing headers and footer because I've found them to be slow but that's a different topic for discussion.


Related issues: https://github.com/ariya/phantomjs/issues/14268 https://github.com/ariya/phantomjs/issues/12691 https://github.com/ariya/phantomjs/issues/12936


@israelidanny @ankit14101986 @motoservo Try my patch. it might fix your issue. Here's some binaries (use at your own risk)

This issue is labeled as closed but I still have problems rendering multipaged PDFs on PhantomJS 2.1.x as the rendered pages are zoomed in. Any news on this?

Workaround for this bug

After 3 days of work I finally managed to find a good workaround for this bug.

We render pdfs, pngs and jpgs with phantom 1.9. This bug has been preventing us from upgrading for months. This bug is only present when rendering pdfs.

I pass a querystring to the page being rendered if rendering a PDF:
?compensateForPhantomV2PdfRenderingBug=true.

On the page being rendered I insert the scaling solution described above:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
</head>
<script>
if(document.location.href.indexOf('compensateForPhantomV2PdfRenderingBug=true') !== -1){
    var css = 'body { transform-origin: 0 0; -webkit-transform-origin: 0 0; transform: scale(0.75); -webkit-transform: scale(0.75); }';
    var head = document.head || document.getElementsByTagName('head')[0];
    var style = document.createElement('style');
    style.type = 'text/css';
    if (style.styleSheet){
        style.styleSheet.cssText = css;
    } else {
        style.appendChild(document.createTextNode(css));
    }
    head.appendChild(style);
}
</script>

I know this is a phantom bug, because we detect how big to render our content, in pixels, with javascript like this:

var pixels = function (cm) {
    if (typeof cm === 'number') {
        return cm;
    }
    if (dimensions[cm]) {
        return dimensions[cm];
    }
    var $dim = $('<div style="top:-10000px;left:-10000px;position:absolute;width:' + cm + ';height:1px;"></div>').appendTo('body');
    dimensions[cm] = $dim.width();
    $dim.remove();
    return dimensions[cm];
};
var pageHeight = pixels('29.7cm');
var pageWidth = pixels('21cm');

So the content should fit perfectly on an A4 page. It does fit perfectly in phantom 1.9. But is broken and too large on phantom 2.1. Adding the scaling as described above compensates for this bug.

Workaround for blank pages bug

Then I came across a bug that Phantom 2.1 was adding blank pages to the PDF, that phantom 1.9 did not. This might be caused by the scaling bug compensation mentioned above, so I'm mentioning it here. I found that adding this javascript fixes the issue with extra blank pages:

var $html = $(document.getElementsByTagName('html')[0]);
$html.height(0);

(I'm using jQuery, because we already have it on the page, there should be an easy Vanilla JS solution too)

For those going the page.paperSize route, be aware height is required.

Similar to @lasterra my solution is this:

  page.open(url, function() {
      page.evaluate(function(zoom) {
        return document.querySelector('body').style.zoom = zoom;
    }, 1.0); // <-- your zoom here
  });

Why is this closed? This is still an issue with a lot of dirty hacks and no proper fix
@Vitallium

@israelidanny the fix has been landed to master and will be shipped with the next release version. If you feel that this issue is still present, feel free to file a new issue and attach a sample code that reproduces your problem.

@Vitallium alright, not aware that it was fixed, last time I tried master it was deeply broken. I'll give it a try and report my luck here.

the snippet provided by @jasonmorita works: https://gitlab.com/gbraad/document-generation-assets/commit/7a6721d6005ac1a2a3a20e125b87ce5358835167.

This is still needed for the current published version on 2.1.1. It feels like a workaround and didn't solve the problem. In an older version: 1.9.0 I was able to only rely on the page.zoomFactor to accomplish the same. When is the fix expected to be released?

The way I understand it, 2.2 release is not coming at all, instead 2.5 is planned, but is still very far away, so this issue won't be fixed any time soon - is this correct? Has anyone been successful in building a binary from current master? build.py is gone, so I'm not even sure how to get around to do that.

I have set the paperSize to A3, and everything seems to work fine (Phantomjs 2.1.1). This is my paperSize configuration:

page.property('paperSize', {
    format: 'A3',
    orientation: 'portrait',
    margin: { 'top': '1cm', 'left': '1cm', 'bottom': '2cm', 'right': '1cm' }
});

I had no problems with printers wanting to print in A3, and a colleague of mine added some extra (A4) pages without noticing :-)

Pagebreaks worked without additional hacks.

Should the released 2.1 actually contain this fix or is it just in the master at the moment?

The issue has been fixed already? or will be in the 2.5 next release? I'm still experiencing issues.

This is still an issue with 2.1.1.
I think this issue should be reopened!

Hi @mojoaxel, 2.1.1 was released before this problem was fixed.

what worked for me:

set the papersize in pixels and then the html body in pixels,

.....
<body style="
        width: 595px;
        height: 842px;
        margin:0;
        padding: 0;
        border-width: 0px;
        overflow: hidden;
        ....
        ">
....

then when setting phantomjs set the papersize in pixels but @ 72dpi:

paper: {
              width: '595px',
              height: '842px',
              margin: '0px',
            },

I would guess that if you set the papersize for phantom in cm it will assume 96dpi but the html is rendered in 72dpi giving for the difference in "zoom"

I know it's open-source, but no _released_ fix after two and a half years? Brutal

@cristianszwarc Is this definitely PhantomJS 2.1.7? This isn't working for me - could you post your whole config? I've tried almost everything.

Has anyone tried the new Headless Chrome for PDF generation? Looks really promising https://developers.google.com/web/updates/2017/04/headless-chrome

@davidwindell judging from https://bugs.chromium.org/p/chromium/issues/detail?id=603559 it doesn't look like it supports headers / footers quite yet, but it definitely looks promising!

@davidwindell judging from https://bugs.chromium.org/p/chromium/issues/detail?id=603559 it doesn't look like it supports headers / footers quite yet, but it definitely looks promising!

Actually I don't know about that... According to http://caniuse.com/#feat=css-paged-media, Chrome supports CSS3 Paged Media module, so setting headers and footers via CSS _should_ work. I'm going to try this over the weekend...

@melo oh interesting! Yes definitely let us know how that goes!

Awesome :bated breath:

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,
I work in a project where MacOs and Windows are used with PhantomJs 2.1.1, and we discovered that the measures in cm are working in Windows but not in Mac and the measures in pixels are working in Mac but not in Windows. Therefore we set a different solution depending on the OS. Unfortunatelly I have not tested it in Linux, but I hope this could help.

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:

phantomjs rasterize.js https://google.com/ test.pdf --dpi 200[ --optionname value,]

Use the option names defined in args. Also you can use - for either input or output to read from STDIN or STDOUT:

"use strict";
var page = require('webpage').create(),
    system = require('system'),
    render = function (phantom, page, output, config) {

        // set DPI
        if (config.dpi !== null) {
            page.evaluate(function (dpi) {
                var div = document.createElement("div"),
                    body = document.getElementsByTagName("body")[0],
                    dpi;
                div.style.width = "1in";
                body.appendChild(div);
                if (dpi > div.offsetWidth) {
                    body.style.width = ((body.offsetWidth / div.offsetWidth) * dpi) + "px";
                }
            }, config.dpi);
        }

        // timeout for javascript
        window.setTimeout(function () {
            page.render(output, {format: config.format, quality: config.quality});
            phantom.exit();
        }, config.delay);
    },
    config = {
        width: 800, // image width
        height: 600, // image height
        format: "pdf", // pdf png, gif, jpg
        paper: "A4",
        orientation: "portrait",
        margin: "2.54cm",
        delay: 300, // javascript delay
        href: "/", // the href alias of the page, allows it to retrieve assets relatively
        dpi: 200,
        quality: 80 // jpeg quality
    },
    output, key;

if (system.args.length > 2) {

    // process arguments
    system.args.slice(3).forEach(function (arg) {
        if (key) {
            config[key] = arg;
            key = null;
        } else if (arg.indexOf("--") === 0) {
            key = arg.substr(2);
        }
    });

    // set paper size
    if (config.format === "pdf") {
        page.paperSize = {
            format: config.paper,
            orientation: config.orientation,
            margin: config.margin
        };
    } else {

        // set viewport size
        page.viewportSize = {
            width: config.width,
            height: config.height
        };
        page.clipRect = { top: 0, left: 0, width: config.width, height: config.height };
    }

    output = system.args[2] === "-" ? "/dev/stdout" : system.args[2];
    if (phantom.version.major > 1) {
        system.stdout.setEncoding("ISO-8859-1");
    }

    // output page from stdin
    if (system.args[1] == "-") {
        if (phantom.version.major > 1) {
            system.stdin.setEncoding("UTF-8");
        }
        page.setContent(system.stdin.read(), config.href);
        render(phantom, page, output, config);

    // output page from url
    } else {
        page.open(system.args[1], function (status) {
            if (status !== 'success') {
                console.log('Unable to load the address!');
                phantom.exit(1);
            } else {
                render(phantom, page, output, config);
            }
        });
    }
}

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 https://github.com/ariya/phantomjs/issues/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,
First, I used print.css

zoom:0.75

but page layout is broken

so, I use this page_size (a4 / 0.75)

width : 210 * 4/3 // avoid pantomjs bug
height : 297 * 4/3 // avoid pantomjs bug

it realy work good!
but i, as possible, need to change a4 size without manual
(because of customer T.T)

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 page.setContent(htmlString). I'll be doing some tests and report back.

FYI: You might have more milage in using:

await page.goto("data:text/html,"+html, {waitUntil: "networkidle0"});

rather than:

const loaded = page.waitForNavigation({waitUntil: "load"});
await page.setContent(html);
await loaded;

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 () {
var the_page = document.getElementsByTagName("page")[0];
the_page.style.transformOrigin='0 0';
the_page.style.WebkitTransformOrigin='0 0';
the_page.style.transform='scale(1.28)';
the_page.style.webkitTransform ='scale(1.28)';
);

Was this page helpful?
3 / 5 - 2 ratings

Related issues

gustavohenke picture gustavohenke  Â·  4Comments

naitsirch picture naitsirch  Â·  3Comments

maboiteaspam picture maboiteaspam  Â·  3Comments

julmot picture julmot  Â·  5Comments

olee picture olee  Â·  4Comments