I have a PhantomJS script that goes through folders in my file system and takes screenshots of HTML pages.
Because of window size and a variety of issues explained here I've opted to place the HTML file in an Object of the width and height of my choosing and then take a screenshot of that instead.
If I create a basic HTML file with an object with a relative data URL and open it in my browser, it works perfectly.
Here's an overview of my file structure.
.
├── dist
| ├── page_one
| └── page_one.html
| └── page_two
| └── page_two.html
└── tools
└── screenshot.js
The code below, is saved in a file I call screenshot.js. I want to be able to run this through PhantomJS. It essentially reads through a comma separated string of directories (eg page_one,page_two), navigates to those pages, takes a screenshot and moves onto the next one. But despite the fact that the HTML generated is the same as the test file I created earlier, the screenshots are always blank.
If I replace the relative data URL with an absolute path, the script works perfectly, but obviously this isn't very re-usable if the file path has to be changed for every project.
I've tried using a number of ../
before the relative data url, but this still doesn't work.
var args = require('system').args,
resourceWait = 300,
maxRenderWait = 10000,
filesbefore = "page_one,page_twoK",
files = filesbefore.split(','),
mode = 'iframe',
page = require('webpage').create(),
count = 0,
forcedRenderTimeout,
renderTimeout;
page.viewportSize = { width: 1024, height : 768 };
function doRender() {
page.render(filename);
next();
}
page.onResourceRequested = function (req) {
count += 1;
clearTimeout(renderTimeout);
};
page.onResourceReceived = function (res) {
if (!res.stage || res.stage === 'end') {
count -= 1;
if (count === 0) {
clearTimeout(forcedRenderTimeout);
renderTimeout = setTimeout(doRender, resourceWait);
}
}
};
page.onConsoleMessage = function (msg) {
console.log("from page: " + msg);
};
function evaluateJsWithArgs(func) {
var args = [].slice.call(arguments, 1);
var fn = "function() { return (" + func.toString() + ").apply(this, " + JSON.stringify(args) + "); }";
return page.evaluate(fn);
};
function next(error) {
if(!error) {
if (files.length == 0){
phantom.exit();
}else{
takeScreenshot(files.pop());
}
}
}
function takeScreenshot(file){
var url = 'dist/' + file + '/' + file + '.html';
filename = file + '.png';
page.open('about:blank', function (status) {
if (status !== "success") {
console.log('Unable to load url');
phantom.exit();
} else {
page.includeJs(
"https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js",
function() {
evaluateJsWithArgs(
function(url, w, h) {
console.log(url);
$('body')
.css({margin: 0, padding: 0})
.html('<object style="background: red;" data="../' + url + '" width="'+ w + '" height="' + h + '" id="screen-frame" />');
console.log($('body').html());
},
url,
page.viewportSize.width,
page.viewportSize.height
);
}
);
forcedRenderTimeout = setTimeout(function () {
doRender();
}, maxRenderWait);
}
});
}
takeScreenshot(files.pop());
Please can someone tell me why this doesnt work.
Thanks in advance.
-
Note: If you'd like to run this locally, then create a basic file structure like mine above, download PhantomJS, cd to root directory of the project and run phantomjs tools/screenshot.js
.
-
EDIT After searching I've found this Q&A. So to my understanding, PhantomJS just can't open local files when using a relative path.
Having an absolute path isn't a suitable option as it will never always be the same.
The only other option I can find at the moment is to put the files on a local server and then run the script from the server URL.