how to take a screenshot of piece of a webpage with phantomjs? - javascript

I understand how to take screenshot of entire webpage but how about capturing the view of an specific element using phantomjs.
I'm trying as follow
var page = require('webpage').create();
page.content = page.open('https://www.google.co.in/');
page.evaluate(function() {
var canvas = document.getElementById('hplogo');
var ctx = canvas.getContext('2d');
var img = new Image();
var imgdata = document.querySelectorAll('img');
img.src = imgdata[0].src;
var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 300, 300);
});
page.render('canvas.png');
phantom.exit();
Above code is not working, What 'm doing in above code is selecting the element of Google webpage img section though id then create an object of image and assign the src of query selected tag IMG and then fill the pattern, my hours of hard work did not yield any result.
WHAT I WANT: I want the screenshot of an img element rendered through 'page.open' which can be selected by query selector and output the png file. OTHER ALTERNATIVES OF PHANTOMJS ARE WELCOME.
Thanks in advance..

Related

Overlay two base64 image url and save them as single image in Javascript

I have a whiteboard option during a video call in my web application built in angularjs (1.x). Users can draw above the video in a canvas element. I need to take a screenshot of the current video position and drawing on the canvas. I am able to get the video frame as base64 URL(second image) and canvas drawing as base64 URL(third image) separately. But I need to get it as a combined single image in base64 URL like the first image.
HTML
<img id="img1">
<img id="img2">
<canvas id="mergedImage" width="382" height="510"></canvas>
JS
var drawingImg1 = document.getElementById('img1');
drawingImg1.setAttribute('src', img1);
var drawingImg2 = document.getElementById('img2');
drawingImg2.setAttribute('src', img2);
var c = document.getElementById('mergedImage');
var width = 382;
var height = 510;
var ctx = c.getContext("2d");
var imageObj2 = new Image();
imageObj2.onload = function (){
ctx.drawImage(imageObj2, 0, 0, width, height);
var imageObj1 = new Image();
imageObj1.onload = function (){
imageObj1.style.objectFit = "cover";
ctx.drawImage(imageObj1, 0, 0,width, height);
};
imageObj1.src = img2;
};
imageObj2.src = img1;
I tried the above code and it gives the output as video frame image only not the drawing included.
I want the output as the first image. Please, someone, guide me to do this.
I have created a jsfiddle here
The following solution worked for me to overlap 2 images and got a single image in a canvas.
Link

How to wait for the multiple images to load in the canvas and convert to base64?

I'm trying to get a base64 version of a canvas in HTML5.
Currently, the base64 image that I get from the canvas is blank.
I have found similar questions for example this one:
HTML Canvas image to Base64 problem
However, the issue that I have is that because I am adding 2 images in the canvas, I cannot use the example provided in those answers as most of them are using single image.
I understand that I have to wait until the canvas image is loaded properly before trying to get the base64 image. But I don't know how in my case.
This is my code:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
var imageObj1 = new Image();
imageObj1.src = "http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg";
imageObj1.onload = function() {
context.drawImage(imageObj1, 0, 180, canvas.width, canvas.height);
};
var imageObj2 = new Image();
imageObj2.src = "http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"
imageObj2.onload = function() {
context.drawImage(imageObj2, 0, 0, canvas.width, 180);
};
// get png data url
//var pngUrl = canvas.toDataURL();
var pngUrl = canvas.toDataURL('image/png');
// get jpeg data url
var jpegUrl = canvas.toDataURL('image/jpeg');
$('#base').val(pngUrl);
<div class="contents" style="overflow-x:hidden; overflow-y:scroll;">
<div style="width:100%; height:90%;">
<canvas id="myCanvas" class="snap" style="width:100%; height:100%;" onclick="takephoto()"></canvas>
</div>
</div>
<p>
This is the base64 image
</p>
<textarea id="base">
</textarea>
and this is a working FIDDLE:
https://jsfiddle.net/3p3e6Ldu/1/
Can someone please advice on this issue?
Thanks in advance.
EDIT:
As suggested in the comments bellow, i tried to use a counter and when the counter reaches a specific number, I convert the canvas to base64.
Like so:https://jsfiddle.net/3p3e6Ldu/4/
In both your examples (the one from the question and the one from the comments), the order of commands does not really respect the async nature of the task at hand.
In your later example, you should put the if( count == 2 ) block inside the onload callbacks to make it work.
However, even then you will run into the next problem: You are loading the images from different domains. You can still draw them (either into the canvas or using an <img> tag), but you are not able to access their contents directly. Not even with the detour of using the <canvas> element.
I changed to code so it would work, if the images are hosted on the same domain. I also used a function to load the image and promises to handle the callbacks. The direct way of using callbacks and a counting variable, seem error-prone to me. If you check out the respective fiddle, you will notice the SecurityError shown. This is the result of the aforementioned problem with the Same-Origin-Policy I mentioned.
A previous question of mine in a similar direction was about how to detect, if I can still read the contents of a <canvas> after adding some images.
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
// function to retrieve an image
function loadImage(url) {
return new Promise((fulfill, reject) => {
let imageObj = new Image();
imageObj.onload = () => fulfill(imageObj);
imageObj.src = url;
});
}
// get images
Promise.all([
loadImage("http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg"),
loadImage("http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"),
])
.then((images) => {
// draw images to canvas
context.drawImage(images[0], 0, 180, canvas.width, canvas.height);
context.drawImage(images[1], 0, 0, canvas.width, 180);
// export to png/jpg
const pngUrl = canvas.toDataURL('image/png');
const jpegUrl = canvas.toDataURL('image/jpeg');
// show in textarea
$('#base').val(pngUrl);
})
.catch( (e) => alert(e) );

downloading images of two different d3 graphs in single html page?

I created an html page for my tool which works offline(client side). This page is creating two different d3 based graph and I created two different buttons (save and save1)for each graph to downlaod images of these. These two image download button works fine, when tested separately in two different html pages.
Now, Problem in combined html page, is that each button is downloading the image of first d3 based graph only.
I defined two different svg variable (svg and svg1) for each graph creation but i donot know how to call it differently in downloadimage script.
**I think there is problem while calling "node( ).parentNode.innerHTML;" (mentioned in following svg downlaod script)?
But I don't know how to call different SVG in this script.
This is my first time, I am working on d3.
**
d3.select("#save1").on("click", function(){ //button save in first graph;
var html1 = d3.select("svg") //var html in first graph;
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node( ).parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html1);
var image = new Image;
image.src = imgsrc;
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.fillStyle = "#FFFFFF";
context.fillRect(0,0,image.width,image.height);
context.drawImage(image, 0, 0);
var a = document.createElement('a');
a.download = "image.png";
a.href = canvas.toDataURL('image/png');
document.body.appendChild(a);
a.click();
}
});
This line:
var html1 = d3.select("svg")
Is always selecting the first SVG in the DOM, regardless the button you click.
Instead of that, give your SVGs unique IDs (like svg1 and svg2), and select by those IDs:
var html1 = d3.select("#svg1")
var html2 = d3.select("#svg2")

Convert SVG dataUrl to base64

I'm using a plugin (dom-to-image) to generate a SVG content from a div.
It returns me a dataURL like this:
data image/xml, charset utf-8, <svg...
If a put this on a <img src the image is shown to normally.
The intent is to grab this dataURL, convert it to base64 so I can save it as an image.png on a mobile app.
Is it possible?
I tryied this solution https://stackoverflow.com/a/28450879/1691609
But coudn't get to work.
The console fire an error about the dataUrl
TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
==== UPDATE :: PROBLEM EXPLANATION/HISTORY ====
I'm using Ionic Framework, so my project is an mobile app.
The dom-to-image is already working cause right now, its rendering a PNG through toPng function.
The problem is the raster PNG is a blurry.
So I thought: Maybe the SVG will have better quality.
And it IS!! Its 100% perfect, actually.
On Ionic, I'm using 2 step procedure to save the image.
After get the PNG generated by the dom-to-img(base64) dataURL, I convert it to a Blob and then save into device.
This is working, but the final result, as I said, is blurry.
Then with SVG maybe it will be more "high quality" per say.
So, in order to do "minimal" change on a process that s already working :D I just need to convert an SVG into base64 dataURL....
Or, as some of you explained to me, into something else, like canvas...
I don't know any much :/
===
Sorry for the long post, and I really, really thank your help guys!!
EDIT COUPLE OF YARS LATER
Use JS fiddle for a working example: https://jsfiddle.net/msb42ojx/
Note, if you don't own DOM content (images), and those images don't have CORS enabled for everyone (Access-Control-Allow-Origin header), canvas cant render those images
I'm not trying to find out why is your case not working, here is how I did when I had something similar to do:
get the image sourcce (dom-to-image result)
set up a canvas with that image inside (using the image source)
download the image from canvas in whatever image you like: png, jpeg whatever
by the way you can resize the image to a standard format
document.getElementById('mydownload').onclick= function(){
var wrapper = document.getElementById('wrapper');
//dom to image
domtoimage.toSvg(wrapper).then(function (svgDataUrl) {
//download function
downloadPNGFromAnyImageSrc(svgDataUrl);
});
}
function downloadPNGFromAnyImageSrc(src)
{
//recreate the image with src recieved
var img = new Image;
//when image loaded (to know width and height)
img.onload = function(){
//drow image inside a canvas
var canvas = convertImageToCanvas(img);
//get image/png from convas
var pngImage = convertCanvasToImage(canvas);
//download
var anchor = document.createElement('a');
anchor.setAttribute('href', pngImage.src);
anchor.setAttribute('download', 'image.png');
anchor.click();
};
img.src = src;
// Converts image to canvas; returns new canvas element
function convertImageToCanvas(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
return canvas;
}
// Converts canvas to an image
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
}
}
#wrapper{
background: red;
color: blue;
}
<script src="https://rawgit.com/tsayen/dom-to-image/master/src/dom-to-image.js"></script>
<button id='mydownload'>Download DomToImage</button>
<div id="wrapper">
<img src="http://i.imgur.com/6GvKdxY.jpg"/>
<div> DUDE IS WORKING</div>
<img src="http://i.imgur.com/6GvKdxY.jpg"/>
</div>
I translated #SilentTremor's solution into React/JS-Class:
class SVGToPNG {
static convert = function (src) {
var img = new Image();
img.onload = function () {
var canvas = SVGToPNG.#convertImageToCanvas(img);
var pngImage = SVGToPNG.#convertCanvasToImage(canvas);
var anchor = document.createElement("a");
anchor.setAttribute("href", pngImage.src);
anchor.setAttribute("download", "image.png");
anchor.click();
};
img.src = src;
};
static #convertImageToCanvas = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
return canvas;
};
static #convertCanvasToImage = function (canvas) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
return image;
};
}
export default SVGToPNG;
Usage:
let dataUrl = someCanvas.toDataURL("image/svg+xml");
SVGToPNG.convert(dataUrl);

Dynamically generated favicon

Would it be possible using only JavaScript and HTML to dynamically generate a favicon, using the current page's favicon as a background, and a random number in the foreground?
For example, lets say the current favicon looks similar to this:
======================
====XXXXXXXXXXXXXX====
====X=================
====X=================
====X=====XXXXXXXX====
====X============X====
====X============X====
====XXXXXXXXXXXXXX====
======================
If possible, how would I get it to look something similar to this using only JavaScript and HTML:
======================
====XXXXXXXXXXXXXX====
====X=================
====X=================
====X=====XXXXXXXX====
====X=========--111--=
====X=========--1-1--=
====XXXXXXXXXX----1--=
==============--1111-=
map:
= : white background
x : Original Favicon image
- : Red generated image with a number
1 : White text
Ideas:
Canvas?
Data Uri's?
EDIT: Got it working with
var canvas = document.createElement('canvas');
canvas.width = 16;canvas.height = 16;
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = '/favicon.ico';
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.fillStyle = "#F00";
ctx.fillRect(10, 7, 6, 8);
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 10px sans-serif';
ctx.fillText('2', 10, 14);
var link = document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.href = canvas.toDataURL("image/x-icon");
document.getElementsByTagName('head')[0].appendChild(link);
}
You can actually run chrome and paste this:
javascript: var canvas = document.createElement('canvas');canvas.width = 16;canvas.height = 16;var ctx = canvas.getContext('2d');var img = new Image();img.src = '/favicon.ico';img.onload = function() {ctx.drawImage(img, 0, 0);ctx.fillStyle = "#F00";ctx.fillRect(10, 7, 6, 8);ctx.fillStyle = '#FFFFFF';ctx.font = 'bold 10px sans-serif';ctx.fillText('2', 10, 14);var link = document.createElement('link');link.type = 'image/x-icon';link.rel = 'shortcut icon';link.href = canvas.toDataURL("image/x-icon");document.getElementsByTagName('head')[0].appendChild(link);}
into the browser and see it in action.
You might take a look at this question, which discusses how to change the favicon dynamically. Also here is a site that claims to play a game in the favicon using only JavaScript, canvas, and the data URI, which should work in all modern browsers except IE. Not sure if that would fulfill your requirements or not, but you can try reverse engineering how it works.
Here's an SO answer that explains how to use the canvas element to read the favicon data and get the image data out, which then can be modified and composed into a new icon.
I don't know about doing it all in the browser, but it would be easy to have a server endpoint that accepted parameters in the URL and returned a composed favicon. Then Javascript could modify the favicon url to get the image it wanted.
favicon.js does exactly this. This library can display a counter in the bottom right corner of the favicon, among other features.

Categories

Resources