I've got a problem where I can't seem to set the viewport for PhantomJS from within Node.js, using Phantom-Proxy as the module I'm using to bridge the two.
I've successfully got it all taking screengrabs of Web pages but like I've said above, I just can't set the viewport size.
In the Phantom-Proxy docs it says I should set the viewport property like:
//set viewport size for browser window
proxy.page.set('viewportSize',
{ width:320, height:480 }, function (result) {
console.log(result.toString().cyan);
worldCallback.call(self);
});
So in my code, I've tried setting the viewport above the lines that actually take the screengrab:
module.exports = function (app, phantom) {
app.get('/url/:url/:width?/:height?', function (req, res) {
phantom.create({"debug": true}, function (proxy) {
var page = proxy.page;
page.set('viewportSize', { width: 320, height: 480 }, function (result) {
console.log(result);
});
page.open(req.params.url, function () {
page.waitForSelector('body', function () {
page.renderBase64('PNG', function (img) {
res.set('Content-Type', 'image/png');
res.end(new Buffer(img, 'base64'), 'binary');
});
});
});
});
});
};
Though I didn't think this would work, so I tried putting the page.open inside page.set's callback and it got ignored, and also tried putting page.set inside page.open's callback and then page.waitForSelectorinside that.
The viewport still seems to be ignored though!
Any help would be greatly appreciated with this! Thank you all
Turns out it was working all along.
Basically, although the viewport was set correctly, that does not mean the Web page will necessarily be the width and height of the viewport (unless for example; the body had a width of 100%).
The Web page would scroll within the viewport, so the whole page is still rendered.
Related
I have problems to remove a handler from the viewer.
viewer.addHandler('viewport-change', function() {
// do stuff works
});
viewer.addHandler('zoom', function() {
if (viewer.viewport.getZoom() > threshold) {
viewer.removeHandler('viewport-change', function() {
console.log("removed");
});
console.log("Zoom:" + viewer.viewport.getZoom());
}
});
I can see the output with the zoom factor, but I never saw the "removed" output.
Also just adding and removing the "viewport-change"-handler did not worked. removeAllHandlers seems to work, but I fail with removing only one handler.
What I really try to do is something like a swipe effect. If the image is not zoomed in and the left edge hits the viewer border i want to show next image. Maybe there is a better way to do that.
Thanks in advance
In order to make removeHandler work, it needs to be the exact same function that you used with addHandler, like so:
var viewportChangeHandler = function() {
// do stuff works
};
viewer.addHandler('viewport-change', viewportChangeHandler);
viewer.addHandler('zoom', function() {
if (viewer.viewport.getZoom() > threshold) {
viewer.removeHandler('viewport-change', viewportChangeHandler);
console.log("Zoom:" + viewer.viewport.getZoom());
}
});
That said, if all you want to do is detect swipes, just a handler on canvas-drag (plus some additional logic of your own writing) should be sufficient.
I'm making a fun open sourced sample for doing Edge Compute Computer Vision using the Raspberry Pi as my hardware.
The current SDK I have to access hardware is nodejs based (I'll release a second with python when it is available). Warning: I am a node novice.
The issue I am facing is that I want to take pictures using the stock camera in a loop without saving a file. I just want to get access to the buffer, extract the pixels, pass to my second edge module.
Taking pictures with no file save in a while(true) loop appears to never execute.
Here is my sample:
'use strict';
var sleep = require('sleep');
const Raspistill = require('node-raspistill').Raspistill;
var pixel_getter = require('pixel-getter');
while(true) {
const camera = new Raspistill({ verticalFlip: true,
horizontalFlip: true,
width: 500,
height: 500,
encoding: 'jpg',
noFileSave: true,
time: 1 });
camera.takePhoto().then((photo) => {
console.log('got photo');
pixel_getter.get(photo,
function(err, pixels) {
console.log('got pixels');
console.log(String(pixels));
});
});
sleep.sleep(5);
}
console.log('picture taken');
In the above code, none of the console.log functions actually ever log; leading me to believe that photos are never taken and therefor pixels can not be extracted.
Any assistance would be greatly appreciated.
UPDATE:
It looks like the looping mechanic might be funny. I guess I don't really care if it takes pictures in a loop as long as it takes a picture, I pass it off, I take a picture and I pass it off, indefinately.
I decided to approach the problem with a recursive loop instead which worked brilliantly.
'use strict';
const sleep = require('sleep');
const Raspistill = require('node-raspistill').Raspistill;
const pixel_getter = require('pixel-getter')
const camera = new Raspistill({ verticalFlip: true,
horizontalFlip: true,
width: 500,
height: 500,
encoding: 'jpg',
noFileSave: true,
time: 5 });
function TakePictureLoop() {
console.log('taking picture');
camera.takePhoto().then((photo) => {
console.log('got photo');
pixel_getter.get(photo, function(err, pixels) {
console.log('got pixels');
TakePictureLoop();
});
});
}
TakePictureLoop();
I am trying to build a messenger bot which does some image processing in 3d and returns a brand new image. I use THREE.CanvasRenderer and my app is hosted on Heroku.
When a user /POSTs an attachment to my webhook, I want to take the URL of the newly created image and insert it into my 3d Scene.
This is my code (using the node-canvas library):
const addTexture = (imageUrl) => {
request({
uri: imageUrl,
method: 'GET'
}, (err, res, body) => {
let image = new Canvas.Image();
image.src = body;
mesh.material.map = new THREE.Texture(image);
mesh.material.needsUpdate = true;
});
}
The callback gets run and I can actually console.log() the image's contents, but nothing shows up in the scene - the plane I am supposed to render to just gets black without any errors... What am I missing here?
I also tried several other ways, without any success...
I tried using THREE.TextureLoader and patch it with jsdom (mock document, window) and node-xmlhttprequest, but then there is error with my load event (event.target is not defined...) Just like in this example
How should one approach this problem? I have a url generated by Facebook, I want to download the image from it and place it in my scene?
Okay, I figured it out after half a day and am posting it for future generations:
Here is the code that did the trick for me:
const addTexture = (imageUrl) => {
request.get(imageUrl, (err, res, data) => {
if (!err && res.statusCode == 200) {
data = "data:" + res.headers["content-type"] + ";base64," + new Buffer(data).toString('base64');
let image = new Canvas.Image();
image.onload = () => {
mesh.material.map = new THREE.Texture(image);
mesh.material.map.needsUpdate = true;
}
image.src = data;
}
});
}
This way, I still get an error: document is not defined, because it seems under the hood three.js writes the texture to a separate canvas.
So the quick and ugly way is to do what I did:
document.createElement = (el) => {
if (el === 'canvas') {
return new Canvas()
}
}
I really hope this helps somebody out there, because besides all the hurdles, rendering WebGL on the server is pure awesomeness.
i have a div that slides out of the screen, loads the new content and slides back.
I use jquery pjax and that part works great:
$('#menu a').on('click', function(event){
event.preventDefault();
var target = $(this).attr('href');
$('li.current').removeClass("current");
$(this).parent().addClass("current");
$(content).transition({left:$(document).width()}, 900, 'out', function() {
$.pjax({
url: target,
container: '#content',
fragment: '#content',
success: function(){
$(content).transition({ left:'0px'}, 900, 'out');
var contentHeight = $('#content').outerHeight(true)+258+$("#footer").outerHeight(true);
if(contentHeight<parseInt($("body").css("min-height"))){
contentHeight = "100%";
}
$(page).stop(true).animate({height:contentHeight}, 1000, "easeOutCubic");
}
});
});
});
But i don't get it do work if the browsers back/forward buttons are used.
I tried different things.
Here i found a nice article but i don't get it: http://artfindertech.wordpress.com/tag/historyapi/
The thing is that the content of the div changes in the moment you click the browser back button.
Then it slides out but not back.
Also the url changes to the previous page for a second but the jumps to the main url of the site.
Here is my trial for popState:
$(window).on('pjax:popstate', function() {
$(content).transition({left:$(document).width()}, 900, 'out', function() {
$.pjax({
container: '#content',
fragment: '#content',
success: function(){
$(content).transition({ left:'0px'}, 900, 'out');
var contentHeight = $('#content').outerHeight(true)+258+$("#footer").outerHeight(true);
if(contentHeight<parseInt($("body").css("min-height"))){
contentHeight = "100%";
}
$(page).stop(true).animate({height:contentHeight}, 2000, "easeOutCubic");
}
});
});
});
I'm trying to do the same thing right now i.e. to get animation functionality onpopstate. The way I see it right now is to:
on menu click call a function which will animate content and fill with the new content the container -
function animation(PageTitle,PageLink,check) {
//check if it is a call from menu and if it is than
//on animation and ajax complete call
if (check) {
setHistory(PageTitle,PageLink); // separate function to call it indimpendently
}
}
as set above, after animation finished call a function regarding window.history.pushState if is a call from menu links -
function setHistory(PageTitle,PageLink) {
window.history.pushState({'ptitle':PageTitle,'plink':PageLink}, PageTitle, PageLink);
}
after that set an onpopstatee function to call the function to the reverse animation and ajax -
window.onpopstate = function(event) {
animation(event.state.ptitle,event.state.plink,false);
}
I have not test it yet but I'm implementing it right now. If it will work I will update this...
UPDATE:
Just to update this and to tell that it works like a charm, as I presumed. An one more thing, for whom it may concern... I figured out that you must call a history.replacestate on original page load in order to have the possibility to go back to the original page with the relative variables and animation.
I have a popup, call 'welcome.html', the thing I would like to do is when the user select a text, and click my plugin, it will use some of the page information, and print back to the welcome.html. For example, the web site title, and the text which the user selected and the url. But how can I pass value to that welcome.html? Thank you.
I do a lot of this in my extension as it mines a lot of data enabling the user to easily copy it to their clipboard.
Since you're looking for a lot less data it's even simpler. When your popup is being loaded you can call the following function to retrieve the information you require;
function getData(callback) {
chrome.tabs.getSelected(null, function (tab) {
var data = {
selection: '',
title: tab.title,
url: tab.url
};
/*
* We can't call content scripts on some pages and the process will get
* stuck if we try.
*/
if (tab.url.indexOf('chrome') === 0 ||
tab.url.indexOf('https://chrome.google.com/webstore') === 0) {
callback(data);
} else {
chrome.tabs.sendRequest(tab.id, {}, function (response) {
data.selection = response.selection;
callback(data);
});
}
});
}
Ensure you pass in a callback function which will be called once all the data has been extracted;
getData(function (data) {
console.log('Title: ' + data.title);
console.log('URL: ' + data.url);
console.log('Selected Text: ' + data.selection);
// Display the data instead
});
As you may have noticed the getData function sends a request to the selected tab. A content script will need to be injected in to the page in order for this to work so be sure you've configured your manifest correctly or injected it programmatically prior to calling getData or it won't work. The script that will need to be injected should resemble the following;
(function () {
chrome.extension.onRequest.addListener(function (request, sender,
sendResponse) {
sendResponse({
selection: window.getSelection().toString()
});
});
})();
This simply returns the currently selected text. One concern is that this data look-up could potentially cause a slight pause while the popup is rendered but you should test this yourself and experiment with it but there are solutions.
This should cover all you need to know so good luck and let me know if you need any further help as I'm aware this could be slightly overwhelming if you're new to Chrome extensions.