I have been running PhantomJS 1.9.6 happily on a turnkey Linux server for about 4 months now. Its purpose is to take an SVG file and create different sizes using the page.render function.
This has been doing this but since a few days ago has started to generate a black mono output.
Please see below:
The code:
var page = require('webpage').create(), system = require('system'), address, output, ext, width, height;
if ( system.args.length !== 4 ) {
console.log("{ \"result\": false, \"message\": \"phantomjs.rasterize: error need address, output, extension arguments\" }");
//console.log('phantomjs.rasterize: error need address, output, extension arguments');
phantom.exit(1);
}
else if( system.args[3] !== "jpg" && system.args[3] !== "png"){
console.log("{ \"result\": false, \"message\": \"phantomjs.rasterize: error \"jpg\" or \"png\" only please\" }");
//console.log('phantomjs.rasterize: error "jpg" or "png" only please');
phantom.exit(1);
}
else {
address = system.args[1];
output = system.args[2];
ext = system.args[3];
width = 1044;
height = 738;
page.viewportSize = { width: width, height: height }; //postcard size
page.open(address, function (status) {
if (status !== 'success') {
console.log("{ \"result\": false, \"message\": \"phantomjs.rasterize: error loading address ["+address+"]\" }");
//console.log('phantomjs.rasterize: error loading address ['+address+'] ');
phantom.exit();
} else {
window.setTimeout(function () {
//--> redner full size postcard
page.render( output + "." + ext );
//--> redner smaller postcard
page.zoomFactor = 0.5;
page.clipRect = {top:0, left:0, width:width*0.5, height:height*0.5};
page.render( output + ".50." + ext);
//--> redner postcard thumb
page.zoomFactor = 0.25;
page.clipRect = {top:0, left:0, width:width*0.25, height:height*0.25};
page.render( output + ".25." + ext);
//--> exit
console.log("{ \"result\": true, \"message\": \"phantomjs.rasterize: success ["+address+"]>>["+output+"."+ext+"]\" }");
//console.log('phantomjs.rasterize: success ['+address+']>>['+output+'.'+ext+']');
phantom.exit();
}, 100);
}
});
}
Does anyone know what can be causing this? There have been no server configuration changes that I know of.
Many thanks for your help.
UPDATE:
It appears the problem is not with PhantomJS but with an update made to the Google Chrome browser on the 20th May (http://googlechromereleases.blogspot.co.uk/2014/05/stable-channel-update_20.html). This effectively changed the way SVG files are built and obviously a change has been made that stops PhantomJS reading the SVG correctly.
The application we have runs correctly on Safari so as expected my first thought about the code not being the issue was correct.
I have logged a forum post in Google Groups (https://groups.google.com/forum/#!topic/google-chrome-techhelp/Y99OXOtikXI) to try and get some help on this, whether it be to roll back the Chrome browser or to provide a flag that enables me to turn off this breaking feature.
FURTHER UPDATE:
This is an issue with an update made to the Google Chrome browser. I have logged a bug report at the address below so hopefully it can be rectified as soon as possible. Thank you for all your help.
http://code.google.com/p/chromium/issues/detail?id=382536
Related
I am making a chrome extension and wanted to add an option to resize the browser window.
I know I can't resize the window with normal JS.(window.resizeTo(600, 600); etc. won't work)
But with extension it's possible. For example with this tool you can resize the window. Problem is that I don't know how.
Also seems possible to open a new tab with desired sizes but it won't open a normal window but a tab.(Like ads)
Does anyone know how to achieve this?
You can try the window API for chrome extensions
chrome.windows.getCurrent(function(wind) {
alert(wind.id);
var maxWidth = window.screen.availWidth;
var maxHeight = window.screen.availHeight;
var updateInfo = {
left: 0, //change those to whatever you like
top: 0,
width: maxWidth,
height: maxHeight
};
chrome.windows.update(wind.id, updateInfo);});
Found an answer:
We need 2 js files. background.js and main.js(content js file, name can be anything).
main.js doesn't have access to extension apis, tabs, background stuff etc. So we will send a message to background.js from our main.js file and get that message in background.js file and execute what we want.
main.js:
chrome.runtime.sendMessage(
{
action: "resizeWindow",
},
function (createdWindow) {
console.log("Window Resize");
}
);
background.js:
//Windows resize
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request && request.action === "resizeWindow") {
chrome.windows.getCurrent(function (window) {
var updateInfo = {
width: 1200,
height: 710,
};
(updateInfo.state = "normal"), chrome.windows.update(window.id, updateInfo);
});
}
});
Note that we need updateInfo.state = "normal".
I am generating html pages with Google chart by domtoimage and jsPDF library. But its generated PDF document looks little bit blurry on Acrobat Reader and fine on Google Chrome. I've tried to printing it and result was so blurry. How to increase quality of PDF?
Code that generates PDF:
function makePDF(a, fname){
var key;
var doc = new jsPDF('l', 'mm', 'a5', true);
for(key in a){
doc.addImage(a[key],'PNG',0,0*key,210,148);
if(a.length - 1 === key*1){
}else{
doc.addPage();
}
}
doc.save(fname + ".pdf");
$(".www").css("margin","auto");
a = null;
isdone = true;
ngViewLoader(false);
}
Code that converts DOM Element to image:
function build_image(dis){
domtoimage.toPng(dis).then(function(dataUrl){
a.push(dataUrl);
arr_index++;
if(index === a.length){
makePDF(a, fname);
}else{
if(arr_index > 13){
return false;
}
build_image(arr_dis[arr_index]);
}
}).catch(function (error) {
console.error('oops, something went wrong!', error);
});
}
#Rozig
Try using the following code below instead:
domtoimage.toJpeg(dis, {
quality: 1.0
})
The JPEG full quality is better compared to the PNG output. But depending on how big your image is being rendered, it still won't be completely look sharp.
I have just downloaded Snap SVG and I'm trying to figure out how to display an image with a fall back arrangement. Here is the code:
var s = Snap("#MyPopup");
var g = s.g();
var image = g.image("http://myimages.com/xyz.png", 250, 10, 40,40 );
This displays the image perfectly. However, if the image is missing then you get that broken image-not-fond icon. Instead of that I want to display an alternate image, say http://myimages.com/abc.png , if the primary image is not found (similar to onerror used with <img>). Can someone please guide me how to do that.
Taking cue from #AustinC I have slightly modified the solution given at Check if image exists on server using JavaScript? that he suggested.
Basically the suggested function was returning 403 (instead of 404) as my images were hosted at amazon cloud, hence I opted to check return code 200 (OK). Here is the final solution.
var s = Snap("#MyPopup");
var image = null;
var mImagePath = "https://myimages.com/xyz.png";
if ( imageExists (mImagePath) == true ) {
image = s.image(mImagePath, 250, 10, 40,40 );
} else {
image = s.image("https://myimages.com/ImageNotFound.png", 250, 10, 40,40 );
}
function imageExists(image_url){
var http = new XMLHttpRequest();
http.open('HEAD', image_url, false);
http.send();
return http.status == 200;
}
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 am trying to create an ajax request to my views.py that returns a cropped segment of a larger image. The problem that I am having is that the image doesn't seem to be downloaded, or at least isn't being drawn. There isn't an error message associated with it, just nothing happens (including "test" not being logged to the console). I have left a few of my attempts with the javascript in but none of them seemed to work.
The view function also doesn't appear to be particularly rapid with the 'called' response being printed 5+ seconds after the request. I am wondering if this is because it takes a long time to load the image? If this is the case is there a way to speed this up i.e. to only load the image once and keep it in memory or just a better way of doing it. It is quite a large image (12000x6000px, 28.5 MB JPEG).
I know that the views.py function is being called by confirming it with the logging module.
So in short:
Why is my image not being displayed?
Is there a quicker way of delivering the image?
Views.py:
def test(request):
img = Image.open(settings.STATIC_PATH + 'geogame/big_map.jpg')
img.load()
xpos = int(request.GET.get('xpos', ''))
ypos = int(request.GET.get('ypos', ''))
upper = ypos*10 - 300
left = xpos*10 - 600
right = xpos*10 + 600
lower = ypos*10 + 300
cropped_img = img.crop((left, upper, right, lower))
logging.warn('called')
response = HttpResponse(content_type = 'image/jpg')
img.save(response, "JPEG")
return response
Ajax request:
Game.zoom = function() {
zoomx = Game.clickX
zoomy = Game.clickY
$.ajax({
url: 'zoom/',
data: {xpos: zoomx, ypos: zoomy},
type: 'get',
success: function(data) {
//Game.zoomedImg.src = "data:image/jpg;base64,"+data
//Game.zoomedImg.src = data;
//console.log(Game.zoomedImg.src);
Game.zoomedImg.onload = function() {
console.log("load");
Game.zoomedImg.src = "data:image/jpg;base64,"+data
}
//$("#" + this.zoomedImg).one("load", function() {
// console.log("test");
// Game.ctx.drawImage(Game.zoomedImg, 0, 0);
// }).attr("src", "data:image/jpg;base64,"+data);
//Game.ctx.drawImage(Game.zoomedImg, 0, 0);
console.log("hello");
//};
},
failure: function(data) {
console.log('failed to load zoomed image')
}
});
}
Thanks!
EDIT
buffer = cStringIO.StringIO() logging.warn('egege')
cropped_img.save(buffer, format = "JPEG")
logging.warn('ffgge')
img_str = base64.urlsafe_b64encode(buffer.getvalue())
logging.warn('leflefe')
return HttpResponse(img_str)
Well I believe I have solved both parts
The image needs to be loaded into a string buffer and base64 encoded to be downloaded after being loaded like so:
buffer = cStringIO.StringIO()
cropped_img.save(buffer, format = "JPEG")
img_str = base64.b64encode(buffer.getvalue())
return HttpResponse(img_str)
This is seemingly because the crop action is lazy and needs to be saved before it takes effect.
Also to speed up the process the image load operation and make it a single occurence the following two lines can be moved to the beginning of the views.py file OUTSIDE of the function.
img = Image.open(settings.STATIC_PATH + 'geogame/big_map.jpg')
img.load()