omaia
omaia

Reputation: 21

Adding a header to a PDF generated by Node Webshot

I'm trying to add a header to a PDF that is generated with node-webshot, but nothing shows up.

I'm using this code:

webshot('https://www.google.com', 'google.pdf', options, function (err) {
    if(err) throw err;
    console.log('Saved to PDF');
});

With the options object like this:

var options = {
        "paperSize": {
            "format": "A4", 
            "orientation": "portrait", 
            "border": "0.25cm",
            "header": {
                "height": "2cm",
                "contents": function () {
                    return phantom.callback(function(pageNum, numPages) {
                        return '<h1>' + pageNum + ' / ' + numPages + '</h1>';
                    });
                }
            }
        }
    };

I tried doing the contents function how it's showed on the PhantomJS documentation but it doesn't work, since phantom is not defined. I can't find any examples of how to add a header/footer using webshot.

The PDF is generated correctly, but the header is blank, with nothing written on it.

How can I solve this?

Upvotes: 2

Views: 1150

Answers (2)

bgmaster
bgmaster

Reputation: 2333

I know this question is more than a year old, but for others who have the same issue as above, eval() didn't work for me. What I ended up doing is adding the following code in the same spot:

if (key === "paperSize" && page[key] && page[key].header && page[key].header.contents) {
    var header = {
      "height": page[key].header.height,
      "contents": phantom.callback(function() {return options.paperSize.header.contents;})
    }
    page.paperSize.header = header;
  }
  if (key === "paperSize" && page[key] && page[key].footer && page[key].footer.contents) {
    var footer = {
      "height": page[key].footer.height,
      "contents": phantom.callback(function() {return options.paperSize.footer.contents;})
    }
    page[key].footer = footer
  }
  if (key === "paperSize") {
    page.paperSize = {
      "format": options.paperSize.format,
      "orientation": options.paperSize.orientation,
      "margin": options.paperSize.margin,
      "header": header,
      "footer": footer
    }
  }

The reason for this is webshot stringifies all data in the options object, so the phantom.callback required for rendering headers and footers with phantomjs doesn't stringify properly. Instead, you will need to add just the html you are going to use in your header/footer in your options object, and it will then be inserted into the phantom.callback in the code above. The only issue with this approach is you can't use the numPages and pageNum arguments with the callback.

Upvotes: 1

Artjom B.
Artjom B.

Reputation: 61892

Since the options are passed as an object into webshot and the "callback" is directly, so there is no way around modifying webshot.

So change the lines from here (file node-webshot/lib/webshot.phantom.js) to:

optUtils.phantomPage.forEach(function(key) {
  if (toOverwrite[key]) page[key] = toOverwrite[key];
  if (key === "paperSize" && page[key] && page[key].header && page[key].header.contents) {
    page[key].header.contents = eval(page[key].header.contents);
  }
  if (key === "paperSize" && page[key] && page[key].footer && page[key].footer.contents) {
    page[key].footer.contents = eval(page[key].footer.contents);
  }
});

Provided that you compose the header content function as a string like this:

"contents": "phantom.callback(function(pageNum, numPages) { return '<h1>' + pageNum + ' / ' + numPages + '</h1>'; })";

It cannot be passed as a function, because along the way the options object is stringified which removes all functions.

Upvotes: 0

Related Questions