Snapshot HTML pages then convert to image using node.js and phantom

I'm trying to create an image snaphot of my website using node-weshot which depends on phantomjs. It work as expected on my local machine, but when I deploy it on a live server. It just keeps firing the callback saying that image is generated. But underneath, the process is still generating the image. (i.e) The filename is generated, but it has no size and contents. After 10 minutes the file will be populated with the image data. However the fonts did not render correctly.

here is the screenshot:

and heres my webshot code:

var options = {
  screenSize: {
   width: 403,
   height: 403
  },
  shotSize: {
    width: 403,
   height: 403
  },
  script: function() {
    $(function() {
      window.callPhantom('takeShot');
    });
  },
  takeShotOnCallback: true
};

webshot(baseUrl+frame_url, path, options, function(err) {
    if(err){
      return res.json({ok:false, error:err.error || err});
    }
    return res.json({image:baseUrl+img,ok:true});
  });

So technically I have 2 problems here:

  1. Webshot returns the callback even though the image generation is not finished yet.
  2. The generated image does not render the fonts correctly. (Im using Google fonts here).

Is there any of fixing the issue? I can see that this is related to How do you take a screenshot of an angularjs app?

Or are there any good alternatives to node-webshot and phantomjs?

Answers


I'm pretty new to webshot and phantom myself, but it seems you are providing an anonymous function there, which will execute as soon as possible REGARDLESS of whether your images are generated or not. If you want to wait for all the images to load before calling window.callPhantom, you may want to try something like

script: function() {
    window.onload = function() {
        if (window.callPhantom === 'function') {
            window.callPhantom('takeShot');
        }
    };
},

window.onload will only be called once all the assets on the page have been loaded. It probably worked fine on your local machine because the assets were loaded much faster, BEFORE your anonymous function was called.

EDIT: I tried this (and other similar things) myself: it DOES NOT WORK. I've also tried putting the callPhantom code on the client side:

<script>
    window.onload = function() {
        if (typeof(window.callPhantom) === 'function') {
            window.callPhantom('takeShot');
        }
    };
</script>

ALSO does not work (it doesn't break the page, though).

I'll keep at this and post my findings here, even if I end up abandoning webshot all together.

EDIT: So two things -- firstly, having re-read the question this has more to do with fonts rather than images (meaning probably a duplicate of Some issues capturing web page image with, node-webshot). Secondly, it turns out the reason behind why my webshot setup wasn't working because of snapping timing, but SSL issues on phantom level (PhantomJS failing to open HTTPS site).

I feel like I've been barking up the wrong tree for the past few days, but it feels good to finally get to the bottom of things. One lesson (among many) I learned in this ordeal is that any problems you encounter using webshot may be at phantom-level. Below is the code I used to view phantom's network activities (modified the pizza example from the module). Just copy it into a js file and run it with phantom (> phantom test.js)

var page = require('webpage').create(),
    url = 'http://some.url.you.want.to.test';

page.onResourceRequested = function(request) {
  console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function(response) {
  console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
page.onResourceError = function(resourceError) {
  console.log('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')');
  console.log('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
};
page.open(url, function (status) {
    if (status !== 'success') {
        console.log('Unable to access network');
    } else {
        console.log(status);
    }
    phantom.exit();
});

Need Your Help

Django does not properly STARTTLS when attempting to email the admins upon internal server error

django smtp smtp-auth starttls

I have a very strange problem. When an internal server error happens, Django 1.6 attempts to send an email to the admins, and apparently it agrees with the mail server to use TLS, but subsequently ...

Alter the "Complete action using" dialog

android android-intent sms intentfilter

I am writing an app to send an MMS with an image file. I wrote the following code