Phantomjs: take screenshot of the current page? - javascript

I'm trying to use Phantomjs to capture a screenshot from the same page that the user is on.
For example, A user is on my-page.html and has made some changes to the elements of this page, now I need to take a screenshot of an element (DIV) inside this page (my-page.html) and save it.
I found a few examples of Phantomjs and php which I tested and worked on my server and it stores the image on my server too BUT all of the examples I found are for taking screenshots of external pages/URLs and not the 'current page'.
This is fairly a straight forward process in Html2canvas but the quality of the produced image is not good at all so I decided to use Phantomjs to produce higher quality screenshots AND also it allows me to zoom in on the page.
Here is a simple example of using Phantomjs for taking screenshot of External URL's:
var system = require("system");
if (system.args.length > 0) {
var page = require('webpage').create();
page.open(system.args[1], function() {
//viewportSize being the actual size of the headless browser
page.viewportSize = { width: 3000, height: 3000 };
//the clipRect is the portion of the page you are taking a screenshot of
page.clipRect = { top: 0, left: 0, width: 3000, height: 3000 };
page.zoomFactor = 300.0/72.0;
var pageTitle = system.args[1].replace(/http.*\/\//g, "").replace("www.", "").split("/")[0]
var filePath = "img/" + pageTitle + '.png';
page.render(filePath);
console.log(filePath);
phantom.exit();
});
}
Could someone please let me know if this is possible at all?
EDIT (Answer to my own question),
it turns out that you cannot take a screenshot of the current page if the page's elements have been edited by the user on the live basis. the only screenshots you can take with phantomjs is a bare bone of the page.
Reason: phantomjs is a headless browser and uses QtWebKit which runs on the server and it is not a javascript library same as html2canvas.
Explained and experienced by others HERE:
Another use case that is an issue for a project I’m working on is that you need drag and drop. Headless drivers have some basic functionality, but if you need to be able to set precise coordinates you’re stuck with Selenium.

For taking screenshot of current page you must pass the correct URL to Phantom script
Syntax :
phantomjs <"Phantom code url(as in documentation report.js)"> <"page url of which you want to take scrrenshot"> <"result saving url">
Now assuming you are passing correct URL :
In my case I was unable to take screenshot of my page as there was a spring security annotation to it, so it was not letting me to proceed so Please check for any security you added to your page if yes then remove it and then try again.
If case 1 does not apply to you surely there is an problem with URL you are passing please double check it.
Please let me know if problem still persist please post any errors(if occurring) you are getting.

Related

How to fix images not loading in phaser.js

Whenever I try to load images into phaser they always appear as a green box on my screen?
I've not only tried the root file path like normal, but also every file path imaginable, but it still never works?
I'm assuming you've already set up a web server.. Did you look at developer tools and check if there are any errors? On Google Chrome, right click your web page and hit inspect. Navigate to the Consoles Tab and look for errors. Be sure to also Log XMLHttpRequests, as these will indicate when the request for said image has been fulfilled (just click the Log XMLHttpRequests checkbox).
Did any of the above solutions work for you? For me, I've used a Simple HTTP Server with Python. I was referencing my images correctly and had my web server hosted correctly. When using developer tools, there were no error messages.. I was banging my head against the wall for hours. The Phaser API was not able to tell what the local directory (http://192.168.0.2:8080/) was from the webpage from some reason.
I fixed my issue by using the following path for my images:
'http://192.168.0.2:8080/assets/sky.png'
where 192.168.0.2 was my local IP address hosting the server & 8080 was the port I was using for communications
Alternative to adding that lengthy file path for each of your images, you can call the this.load.setBaseURL('http://192.168.0.2:8080') function in combination with what you already have.
For example, see the following code:
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 200 }
}
},
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
console.log('preload');
this.load.setBaseURL('http://192.168.0.2:8080');
this.load.image('bombP','bowmb.png');
this.load.image('einMary','/bowmb.png');
}
function create ()
{
console.log('create');
this.add.image(126, 119, 'bombP');
this.add.image(222,269,'einMary');
//var s = game.add.sprite(80,0,'einMary');
//s.rotation=0.219;
}
I should start by checking those two points below :
Check if the image has the right path to the file
Check if the 'key' you are using is the right one

Failed to execute 'postMessage' on 'DOMWindow': https://www.youtube.com !== http://localhost:9000

This is the error message that I get:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided
('https://www.youtube.com') does not match the recipient window's origin
('http://localhost:9000').
I've seen other similar problems where the target origin is http://www.youtube.com and the recipient origin is https://www.youtube.com, but none like mine where the target is https://www.youtube.com and the origin is http://localhost:9000.
I don't get the problem. What is the problem?
How can I fix it?
I believe this is an issue with the target origin being https. I suspect it is because your iFrame url is using http instead of https. Try changing the url of the file you are trying to embed to be https.
For instance:
'//www.youtube.com/embed/' + id + '?showinfo=0&enablejsapi=1&origin=http://localhost:9000';
to be:
'https://www.youtube.com/embed/' + id + '?showinfo=0&enablejsapi=1&origin=http://localhost:9000';
Just add the parameter "origin" with the URL of your site in the paramVars attribute of the player, like this:
this.player = new window['YT'].Player('player', {
videoId: this.mediaid,
width: '100%',
playerVars: {
'autoplay': 1,
'controls': 0,
'autohide': 1,
'wmode': 'opaque',
'origin': 'http://localhost:8100'
},
}
Setting this seems to fix it:
this$1.player = new YouTube.Player(this$1.elementId, {
videoId: videoId,
host: 'https://www.youtube.com',
You can save the JavaScript into local files:
https://www.youtube.com/player_api
https://s.ytimg.com/yts/jsbin/www-widgetapi-vfluxKqfs/www-widgetapi.js
Into the first file, player_api put this code:
if(!window.YT)var YT={loading:0,loaded:0};if(!window.YTConfig)var YTConfig={host:"https://www.youtube.com"};YT.loading||(YT.loading=1,function(){var o=[];YT.ready=function(n){YT.loaded?n():o.push(n)},window.onYTReady=function(){YT.loaded=1;for(var n=0;n<o.length;n++)try{o[n]()}catch(i){}},YT.setConfig=function(o){for(var n in o)o.hasOwnProperty(n)&&(YTConfig[n]=o[n])}}());
Into the second file, find the code: this.a.contentWindow.postMessage(a,b[c]);
and replace it with:
if(this._skiped){
this.a.contentWindow.postMessage(a,b[c]);
}
this._skiped = true;
Of course, you can concatenate into one file - will be more efficient.
This is not a perfect solution, but it's works!
My Source : yt_api-concat
Make sure you are loading from a URL such as:
https://www.youtube.com/embed/HIbAz29L-FA?modestbranding=1&playsinline=0&showinfo=0&enablejsapi=1&origin=https%3A%2F%2Fintercoin.org&widgetid=1
Note the "origin" component, as well as "enablejsapi=1". The origin must match what your domain is, and then it will be whitelisted and work.
In my case this had to do with lazy loading the iframe. Removing the iframe HTML attribute loading="lazy" solved the problem for me.
I got the same error. My mistake was that the enablejsapi=1 parameter was not present in the iframe src.
You also get this message when you do not specify a targetOrigin in calls to window.postMessage().
In this example we post a message to the first iFrame and use * as target, which should allow communication to any targetOrigin.
window.frames[0].postMessage({
message : "Hi there",
command :"hi-there-command",
data : "Some Data"
}, '*')
Try using window.location.href for the url to match the window's origin.
Remove DNS Prefetch will solve this issue.
If you're using WordPress, add this line in your theme's functions.php
remove_action( 'wp_head', 'wp_resource_hints', 2 );
There could be any of the following, but all of them lead into DOM not loaded before its accessed by the javascript.
So here is what you have to ensure before actually calling JS code:
* Make sure the container has loaded before any javascript is called
* Make sure the target URL is loaded in whatever container it has to
I came across the similar issue but on my local when I am trying to have my Javascript run well before onLoad of the main page which causes the error message. I have fixed it by simply waiting for whole page to load and then call the required function.
You could simply do this by adding a timeout function when page has loaded and call your onload event like:
window.onload = new function() {
setTimeout(function() {
// some onload event
}, 10);
}
that will ensure what you are trying will execute well after onLoad is trigger.
In my instance at least this seems to be a harmless "not ready" condition that the API retries until it succeeds.
I get anywhere from two to nine of these (on my worst-case-tester, a 2009 FossilBook with 20 tabs open via cellular hotspot).... but then the video functions properly. Once it's running my postMessage-based calls to seekTo definitely work, haven't tested others.
It looks it's only a Chrome security system to block repeated requests, using CORB.
https://www.chromestatus.com/feature/5629709824032768
In my case, YouTube was blocking Access after the first load of the same webpage which has many video API data request, high payload.
For pages with low payload, the issue does not occur.
In Safari and other non Chronuim based browsers, the issue does not occur.
If I load the webpage in a new browser, the issue does not occur, when I reload the same page, the issue appears.
In some cases (as one commenter mentioned) this might be caused if you are moving the player within DOM, like append or etc..
This helped me (with Vue.js)
Found here vue-youtube
mounted() {
window.YTConfig = {
host: 'https://www.youtube.com/iframe_api'
}
const host = this.nocookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com'
this.player = player(this.$el, {
host,
width: this.width,
height: this.height,
videoId: this.videoId,
playerVars: this.playerVars
})
...
}
UPDATE:
Working like a charm like this:
...
youtube(
video-id="your_video_code_here"
nocookie
)
...
data() {
return {
playerVars: {
origin: window.location.href,
},
};
},
I think the description of the error is misleading and has originally to do with wrong usage of the player object.
I had the same issue when switching to new Videos in a Slider.
When simply using the player.destroy() function described here the problem is gone.
I had this same problem and it turns out it was because I had the Chrome extension "HTTPS Everywhere" running. Disabling the extension solved my problem.
This exact error was related to a content block by Youtube when "playbacked on certain sites or applications". More specifically by WMG (Warner Music Group).
The error message did however suggest that a https iframe import to a http site was the issue, which it wasn't in this case.
You could change your iframe to be like this and add origin to be your current website. It resolves error on my browser.
<iframe class="test-testimonials-youtube-group" type="text/html" width="100%" height="100%"
src="http://www.youtube.com/embed/HiIsKeXN7qg?enablejsapi=1&origin=http://localhost:8000"
frameborder="0">
</div>
ref: https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
Just wishing to avoid the console error, I solved this using a similar approach to Artur's earlier answer, following these steps:
Downloaded the YouTube Iframe API (from https://www.youtube.com/iframe_api) to a local yt-api.js file.
Removed the code which inserted the www-widgetapi.js script.
Downloaded the www-widgetapi.js script (from https://s.ytimg.com/yts/jsbin/www-widgetapi-vfl7VfO1r/www-widgetapi.js) to a local www-widgetapi.js file.
Replaced the targetOrigin argument in the postMessage call which was causing the error in the console, with a "*" (indicating no preference - see https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).
Appended the modified www-widgetapi.js script to the end of the yt-api.js script.
This is not the greatest solution (patched local script to maintain, losing control of where messages are sent) but it solved my issue.
Please see the security warning about removing the targetOrigin URI stated here before using this solution - https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Patched yt-api.js example
Adding origin=${window.location.host} or "*" is not enough.
Add https:// before it and it will work.
Also, make sure that you are using an URL that can be embedded: take the video ID out and concatenate a string that has the YouTube video prefix and the video ID + embed definition.
I think we could customize the sendMessage of the YT.Player
playerOptions.playerVars.origin = window.location.origin or your domain.
this.youtubePlayer = new YT.Player(element,playerOptions);
this.youtubePlayer.sendMessage = function (a) {
a.id = this.id, a.channel = "widget", a = JSON.stringify(a);
var url = new URL(this.h.src), origin = url.searchParams.get("origin");
if (origin && this.h.contentWindow) {
this.h.contentWindow.postMessage(a, origin)
}
}
I used this function to resolve in my project.
Extending #Hokascha's answer above it was also lazy loading for me being automatically added by WordPress. This code will remove all lazy loading on the site's iframes (add to functions.php):
function disable_post_content_iframe_lazy_loading( $default, $tag_name, $context ) {
if ( 'iframe' === $tag_name ) {
return false;
}
return $default;
}
add_filter('wp_lazy_loading_enabled', 'disable_post_content_iframe_lazy_loading', 10, 3);
I got a similar error message in my attempt to embed a Stripe pricing table when:
Adding the embed code via PHP through a custom WordPress short code
Or by appending the code to the page dynamically with JavaScript (Even a using a setTimeout() delay to ensure the DOM was loaded didn't work).
I was able to solve this on my WordPress site by adding the code to the WordPress page itself using plain html code in the block editor.
mine was:
<youtube-player
[videoId]="'paxSz8UblDs'"
[playerVars]="playerVars"
[width]="291"
[height]="194">
</youtube-player>
I just removed the line with playerVars, and it worked without errors on console.
You can try :
document.getElementById('your_id_iframe').contentWindow.postMessage('your_message', 'your_domain_iframe')
I was also facing the same issue then I visit official Youtube Iframe Api where i found this:
The user's browser must support the HTML5 postMessage feature. Most modern browsers support postMessage
and wander to see that official page was also facing this issue. Just Visit official Youtube Iframe Api and see console logs. My Chrome version is 79.0.3945.88.

How to access performance object of every resource in a web page?

I can see, in Chrome Developer tools, loading time, time it took to get a particular resource from server and other info, for all of the resources in a webpage.
I want to capture these stats using JavaScript. How is it possible?
there is window.performance object available, but only for the requested page, not for page resources.
Is there any way to access performance object of all of the page resources.
You should be able to use window.performance.getEntries() to get resource-specific stats:
var resource = window.performance.getEntries()[0];
console.log(resource.entryType); // "resource"
console.log(resource.duration); // 39.00000000430737
console.log(resource.startTime); // 218.0000000007567
Sample from the above link:
There is still a bug in latest version of chrome - 29.0.1547.76 m
When you raise an xmlhttprequest, lets say while downloading an image, you can see that the resource is downloaded with status code 200 OK in network tab, but the performance.getEntries() or performance.getEntriesByName(resourceUrl) doesn't list the resource entry. When the page load is complete and you evaluate performance.getEntriesByName(resourceUrl) in console, it lists properly. So, there is a lag in chrome while populating the resource entries in performance entries?
In IE10, this works perfectly fine.
window.performance.getEntries()
may return not all resources. after bufferful some records is disapear
need check it before it happend
head code part
var storedEntries = [];
var updateStoredEntries = p => {
storedEntries.concat(
p.getEntries().filter(rec => /yourRegExp/.test(rec.name))
)
};
performance.addEventListener('resourcetimingbufferfull', e => {
updateStoredEntries(e.target)
});
...
later part
updateStoredEntries(performance)

Jquery - how to load everything except the images?

I'm currently working on a WordPress addition which loads full post content (normally it shows exceprts) when asked to. I did my code like this:
$(".readMore").click(function() {
var url = $(this).attr("href");
$(this).parent("p").parent("div").children("div.text").slideUp("slow", function () {
$(this).load(url + " .text", function(){
$(this).slideDown("slow");
});
});
$(this).parent("p").fadeOut();
return false; });
And it works. But I don't want images to be loaded. I tried .text:not(img), but it didn't worked. How can I do this?
The trick, of course, is preventing the images from being downloaded unnecessarily by the user's browser; not displaying them is easy.
I only have two browsers were it's easy and convenient to tell what's downloading: Chrome and Firefox+Firebug. In my tests, Martin's solution using *:not(img) results in the images being downloaded (although not displayed) in both Chrome and Firefox+Firebug. (I emphasize "Firefox+Firebug" because Firebug can change the behavior of Firefox on occasion, and so it may well be changing its behavior here, although I don't think it is; more on that below.)
It took some tweaking, but this seems to do the trick (more on testing below):
$.ajax({
url: url,
success: function(data) {
var div = $("<div>").html(data);
if (stripImages) {
// Find the images, remove them, and explicitly
// clear the `src` property from each of them
div.find("img").remove().each(function() {
this.src = "";
});
}
$(targetSelector).append(div.children());
},
error: function(jxhr, status, err) {
display("ajax error, status = " + status + ", err = " + err);
}
});
Live example The "Include big image" checkbox includes a large file from NASA's Astronomy Picture of the Day (APOD).
The key there was setting the src of the img elements to "". On Chrome, just removing the elements was enough to prevent Chrome starting the download of the images, but on Firefox+Firebug it not only started downloading them, but continued even when the download took considerable time. Clearing the src causes Firefox to abort the download (I can see this in the Firebug Net console).
So what about IE? Or Firefox without Firebug? I only did unscientific testing of those, but it's promising: If I run my live example of Martin's solution on either IE or Firefox without Firebug in a VM, I see the VM's network interface working hard, suggesting that it's downloading that big APOD picture. In contrast, if I run my solution above in that same environment (with caches cleared, etc., etc.), I don't see the VM network interface doing that work, suggesting that the download is either not being started or is being aborted early on.
.text *:not(img) will select every descendant from .text that is not an image, so in theory it should work.

printing protovis output (programmatically)

I'm pondering switching to protovis for visualizations. One thing that keeps me skeptical however - since protovis creates its output as a div in a browser, I wonder if there is any at least semi-automatic way for me to create a bunch of images at once without opening each one and pressing "print" manually.
So the question would be:
do you think I can use a browserless JS engine like V8 to execute the code and print the result?
can I automate opening and printing within a browser?
is there another way to get automated images from protovis?
Thanks,
Nicolas
Have a look at this Google Groups thread about this very topic.
Check out http://www.phantomjs.org/
It is a headless browser.
It can do exactly what you want :
http://code.google.com/p/phantomjs/wiki/QuickStart#Rendering
rasterize.js:
if (phantom.state.length === 0) {
if (phantom.args.length !== 2) {
console.log('Usage: rasterize.js URL filename');
phantom.exit();
} else {
var address = phantom.args[0];
phantom.state = 'rasterize';
phantom.viewportSize = { width: 600, height: 600 };
phantom.open(address);
}
} else {
var output = phantom.args[1];
phantom.sleep(200);
phantom.render(output);
phantom.exit();
}
An example to produce the rendering of the famous Tiger (from SVG):
phantomjs rasterize.js http://ariya.github.com/svg/tiger.svg tiger.png

Categories

Resources