When using PhantomJS for screen capture where most of a page's content is getting added on or during load via JavaScript, I run into a problem. Calling render() produces the correct image, showing the full content of the page, but evaluating document.body.clientHeight returns a tiny value that is presumably the page's height before any content gets added.
How can I get the height/width of the image as PhantomJS is rendering it? I don't think it's a timing issue, I've tried swapping the order of things or setting long delays to ensure everything is totally loaded.
var wp = require('webpage');
var page = wp.create();
page.viewportSize = { width: 1024, height: 768};
page.open(url, function (status) {
if (status === 'success') {
var f = "rendered.png";
//Produces an image with height 4073px
page.render(f);
//height is only 150
var height = page.evaluate(function() { return document.body.offsetHeight }),
width = page.evaluate(function() { return document.body.offsetWidth });
console.log(height,width);
}
});
Try using the page.onLoadFinished callback:
var wp = require('webpage');
var page = wp.create();
page.viewportSize = { width: 1024, height: 768};
page.open(url);
page.onLoadFinished = function() {
var f = "rendered.png";
//Produces an image with height 4073px
page.render(f);
//height is only 150
var height = page.evaluate(function() { return document.body.offsetHeight }),
width = page.evaluate(function() { return document.body.offsetWidth });
console.log(height,width);
};
This should return the correct height and width after the page content has finished loading. I think the difference is that page.onLoadFinished waits for all content to finish loading and not just for a 200 OK response which is equivalent to the success status.
Related
I wrote the following code:
var image_pinch_help = document.getElementById("image_pinch_help");
var pinch_img_el = document.getElementById("pinch_img_el");
function openImage(img_url) {
pinch_img_el.src = img_url;
if (pinch_img_el.complete) {
IMGloaded();
}
else {
pinch_img_el.addEventListener('load', IMGloaded())
pinch_img_el.addEventListener('error', function() {
alert('error')
});
}
image_pinch_help.style.display = "block";
document.getElementById("pinch_values").setAttribute("content", "");
}
function IMGloaded() {
var screen_height = window.screen.height;
console.log("HERE IS THE HEIGHT: " + screen_height);
var img_height = pinch_img_el.offsetHeight;
console.log("HERE IS THE IMAGE: " + img_height);
}
The code starts at the function openImage(). This function is called to open an Image at my webpage. So the image gets the full width of the screen. The screen where the image is shown on is image_pinch_help. You see that I make this screen visible. To allow the user to zoom into the image I am manipulation the HTML DOM, that the user can scroll at the whole page. I do this here: document.getElementById("pinch_values").setAttribute("content", "");.
When the Image loaded I need to get the height of the screen, which works perfectly. But I also need to get the height of the loaded image. The problem is that its always returning an empty string. I read a long time ago that this could be caused by HTML DOM Manipulations.
But how to fix this disaster?
~Marcus
I know that the question has been asked before, but all the answers are from a few years ago, so perhaps something changed.
I found this https://github.com/apollolm/phantasm , which seems like exactly what I need. But I'm on OSX and it appears not to be supported.
So, how can I use javascript to save an image of a partulcar portion of a webpage?
You can use phantomjs for rendering page and getting its image.
Example for rendering your question:
var page = require('webpage').create();
page.viewportSize = {width: 1600, height: 900};
console.log('opening page');
page.open('http://stackoverflow.com/questions/37570827/saving-element-of-webpage-as-an-image-using-js', function(status) {
console.log('check status ', status);
if (status == 'success') {
console.log('getting rect for part of page which we want to render to file');
var rect = page.evaluate(function() {
var questionElement = document.getElementById("question");
return questionElement.getBoundingClientRect();
});
console.log('setting rect ', rect);
page.clipRect = rect;
console.log('rendering, check file question.png near your script');
page.render("question.png");
}
console.log('exiting');
phantom.exit();
})
run it with phantomjs SCRIPT_FILENAME.js and wait for result:
I have a function that change the size of the iframe every time a new content is loading.
It works fine, but there is a little problem:
If I open a big content the size change to it correct hight. If I load after that a smaller content, the height stays the same(from the big content), it isn't getting shorter.
I don't know why, how can I fix it?
$("#mainframe").load( function () {
var c = (this.contentWindow || this.contentDocument);
if (c.document) d = c.document;
var ih = $(d).outerHeight() + 10;
var iw = $(d).outerWidth();
$(this).css({
height: ih,
width: iw
});
});
I fire a function on jQuery(document).ready() and on jQuery(window).load(). Both the same function. It is supposed to fire an image resize script.
However, sometimes, when the server is slow to respond, the script doesn't fire at all when the page is done loading.
I've been having this problem for quite a while now, and, maybe it's overkill, but by now, I call the function as shown below, in both the document ready and the window load:
jQuery('img', '.background').each(function(){
jQuery(this).load(function(){
jQuery(this).resizeImage();
});
});
The function it calls is:
jQuery.fn.resizeImage = function() {
console.log('fired');
var bgImg = jQuery(this);
/* get img sizes */
var imgwidth = bgImg.width();
var imgheight = bgImg.height();
/* get window sizes */
var winwidth = jQuery(window).width();
var winheight = jQuery(window).height();
/* get the ratio, checks wether window is bigger or smaller than the image */
var widthratio = winwidth / imgwidth;
var heightratio = winheight / imgheight;
/* checks the difference */
var widthdiff = heightratio * imgwidth;
var heightdiff = widthratio * imgheight;
/* if you want the entire image to always fit the screen, change the > to < */
if(heightdiff>winheight) {
bgImg.css({
width: winwidth+'px',
height: heightdiff+'px',
marginLeft: '-'+winwidth/2+'px'
});
} else {
bgImg.css({
width: widthdiff+'px',
height: winheight+'px',
marginLeft: '-'+widthdiff/2+'px'
});
}
};
Using the console.log, I found that the function doesn't fire at all.
Can anyone point me in the right direction as to why this might not work?
Guess you're miss using the this
jQuery('img', '.background').each(function(){
var $self = $(this);
$self.load(function(){
$self.resizeImage();
});
});
Solved it myself.
The issue was in the following:
jQuery(window).load(function(){
jQuery('img', '.background').each(function(){
jQuery(this).load(function(){
jQuery(this).resizeImage();
});
});
});
Due to the double load (jQuery(window).load and jQuery(this).load) the code didn't execute at all. Since when the window is loaded, the images are already loaded as well.
i load graphs via the following javascript function:
function loadMCorCBGraph(self,surveyID,questionID,varID) {
var img = new Image();
img.onload = function() {
$(self).parents().parents().siblings(".graph_container")
.empty().append(img);
};
img.src = 'drawGraph.php?type=surveys_report_MC_or_CB&surveyID=' + surveyID + '&questionID=' + questionID +
(varID != null ? '&varID=' + varID : '') + '&companyID=<?php echo $_SESSION['companyID'] ?>';
}
however, the graph height is unknown until it is drawn. i was wondering if there was a way to get this height after it has loaded and set the container height to cet height.
i thought about putting:
.css("height", THE_IMAGE_HEIGHT)
in the onload function, but i am having trouble finding this image's height. debugging shows that (inside the onload):
$(this).height() = 0
img.height = ReferenceError: img is not defined
this.height = 425
now the last one, this.height, is clearly referring to the container, which is set with a height of 425px.
any ideas as to how to get the height?
thanks!
img.onload = function() {
$Container = $(self).parents().parents().siblings(".graph_container");
$Container.empty().append(img);
this.find('img').each(function(){
//Dynamically check each image
if(this.height > 400)
{
$(this).height(400);
}
console.log(this); //Should see object with attribs.
})
};
Give that a go and tell me what happens, also check your console log to see if the Object is the image element.