Export external SVG file painted with Javascript to PNG image - javascript

I am using an svg map from an external file. I insert it to my html code using the "object" tag.
<object id="mymap" data="map.svg" width="884" height="760" type="image/svg+xml" ></object>
In javascript I paint paths of the svg map with some given colors. For example:
<script>
var path1 = document.getElementById('mymap').getSVGDocument().getElementById('path1');
path1.style.fill='#f00';
var path2 = document.getElementById('mymap').getSVGDocument().getElementById('path2');
path2.style.fill='#0f0';
</script>
How can I export the resulted coloured map as a PNG image?
--UPDATE-- : The question has been answered, and the LiveExample now includes the solution for future reference. You can view the source and get the solution. The example draws a map and saves drawn map in a canvas that you can then save as file
Example Solution Displaying the canvas
Example Solution Hiding the canvas with direct download to generated image

Solution is the following:
Based on my accepted solution I include the full javascript that manages all steps
Create a canvas
<canvas id="canvas" style="border:1px solid black;" width="884" height="760"></canvas>
Draw into that canvas the image from the painted svg
function drawCanvas(){
// create a canvas and context
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// define svgdocument and make blob containing its data
var svgDoc = document.getElementById('mymap').getSVGDocument();
var svg = new Blob([svgDoc.lastChild.outerHTML], {type: 'image/svg+xml;charset=utf-8'});
// create a new image
var DOMURL = window.URL || window.webkitURL || window;
var url = DOMURL.createObjectURL(svg);
var img = new Image();
img.onload = function(){
ctx.drawImage(img,0,0,884,760);
DOMURL.revokeObjectURL(url);
};
img.src = url;
}
Example Solution Displaying the canvas
Example Solution Hiding the canvas with direct download to generated image

What about drawing the svg to the canvas, and then use the .toDataURL to get as PNG image?
--Update--
For a quick test, i run the below in the console from your live demo:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var svgDoc = document.getElementById('mymap').getSVGDocument();
var svg = new Blob([svgDoc.lastChild.outerHTML], {type: 'image/svg+xml;charset=utf-8'});
var img = new Image();
img.onload = function(){ ctx.drawImage(img,0,0); };
img.src = url
you should see the url, which has the image draw, at this time just call the .toDataURL you should get the base64 image data

Related

How to covert multiple svg to png in single html page?

I used d3 and venn.js for creating this venn diagram.
The code goes here : Svg actually created inside div venn2 by these scripts.
<div id="venn2"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="js/venn.js"></script>
<script>
var sets = [
{sets:["A"], size: 12, label: "A"},
{sets:["B"], size:12, label: "B"},
{sets: ["A", "B"], size: 4, label: "AB"}
];
var chart = venn.VennDiagram()
.wrap(false)
.fontSize("14px")
.width(400)
.height(400);
function updateVenn(sets) {
var div = d3.select("#venn2").datum(sets);
var layout = chart(div),
textCentres = layout.textCentres;
div.selectAll(".label").style("fill", "white");
div.selectAll(".venn-circle path").style("fill-opacity", .6);
return layout;
}
</script>
The script I got here to convert svg to png via canvas.
<canvas id="canvas" ></canvas>
<div id="png-container" ></div>
<script>
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
var png = canvas.toDataURL("image/png");
document.querySelector('#png-container').innerHTML = '<img src="'+png+'"/>';
DOMURL.revokeObjectURL(png);
};
img.src = url;
</script>
So, the venn diagram as svg was created inside venn2 div by script 1 and svg then written as a png by script 2.
It worked perfectly fine for one svg image per page.
When I have more than one such svg venn diagrams on single html page. Only the first gets converted to png.
But I am unable to fetch the svg at position 2 and 3 or more to convert to png.
I am stuck at this code
var svgString = new XMLSerializer().serializeToString(querySelectorAll('svg'));
where 'svg' means only first svg i guess but not later.
I can't even create svgs with different "id" as svg is formed by d3 and venn.js scripts.
The question is that : How to convert all svg images in a html page
when I don't know their id to png images via above code?
I do not know how to parse this whole string var svgString to convert all to different png images?
In case someone else comes looking for sample code, I figured it out as follows.
My case: I had an svg with two layers drawn by plotly. I was only getting the first layer like the OP. Plotly drew into an element with id="chart". A new canvas already created with id="layer0".
Eventually I needed to send back to PHP as a dataURL so:
var nodes = document.getElementById("chart").querySelectorAll('svg');
for (var i = 0; i < nodes.length; i++) {
result = new XMLSerializer().serializeToString(nodes[i]);
eval('layer'+[i]+'chart').src = 'data:image/svg+xml;base64,' + btoa(result);
}
elem0 = document.getElementById("layer0");
ctx0 = elem0.getContext("2d");
layer0chart.onload = function() {
ctx0.drawImage(layer0chart,0,0,w*1.5,h*1.5);
ctx0.drawImage(layer1chart,0,0,w*1.5,h*1.5);
canvasdata = elem0.toDataURL();
console.log(canvasdata);
}
I appreciate the help from #BioDeveloper and #RobertLongson. The key for me ultimately was to also make sure the toDataURL was being called as an image was being loaded. Cheers.

Execute Function After Canvas toDataURL() Function is Complete

I'm converting images to base64 using canvas. What i need to do is convert those images and then show the result to the user (original image and base64 version). Everything works as expected with small images, but when i try to convert large images (>3MB) and the conversion time increases, the base64 version is empty.
This might be is caused because the result is shown before the toDataURL() function is completed.
I need to show the result after all the needed processing has ended, for testing purposes.
Here's my code:
var convertToBase64 = function(url, callback)
{
var image = new Image();
image.onload = function ()
{
//create canvas and draw image...
var imageData = canvas.toDataURL('image/png');
callback(imageData);
};
image.src = url;
};
convertToBase64('img/circle.png', function(imageData)
{
window.open(imageData);
});
Even though i'm using image.onload() with a callback, i'm unable to show the result after the toDataURL() has been processed.
What am i doing wrong?
UPDATE: I tried both the solutions below and they didn't work. I'm using AngularJS and Electron in this project. Any way i can force the code to be synchronous? Or maybe some solution using Promises?
UPDATE #2: #Kaiido pointed out that toDataURL() is in fact synchronous and this issue is more likely due to maximum URI length. Since i'm using Electron and the image preview was for testing purposes only, i'm going to save the file in a folder and analise it from there.
Your code seems absolutely fine. Not sure why isn't working you. Maybe, there are some issues with your browser. Perhaps try using a different one. Also you could use a custom event, which gets triggered when the image conversion is competed.
// using jQuery for custom event
function convertToBase64(url) {
var image = new Image();
image.src = url;
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
var imageData = canvas.toDataURL();
$(document).trigger('conversionCompleted', imageData);
};
};
convertToBase64('4mb.jpg');
$(document).on('conversionCompleted', function(e, d) {
window.open(d);
});
This approach might work for you. It shows the image onscreen using the native html element, then draws it to a canvas, then converts the canvas to Base64, then clears the canvas and draws the converted image onto the canvas. You can then scroll between the top image (original) and the bottom image (converted). I tried it on large images and it takes a second or two for the second image to draw but it seems to work...
Html is here:
<img id="imageID">
<canvas id="myCanvas" style="width:400;height:400;">
</canvas>
Script is here:
var ctx;
function convertToBase64(url, callback)
{
var image = document.getElementById("imageID");
image.onload = function() {
var canvas = document.getElementById("myCanvas");
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx = canvas.getContext("2d");
ctx.drawImage(image,0,0);
var imageData = canvas.toDataURL('image/png');
ctx.fillStyle ="#FFFFFF";
ctx.fillRect(0,0,canvas.width,canvas.height);
callback(imageData);
};
image.src = url;
};
var imagename = 'images/bigfiletest.jpg';
window.onload = function () {
convertToBase64(imagename, function(imageData) {
var myImage = new Image();
myImage.src = imageData;
ctx.drawImage(myImage,0,0);
});
}
Note that I also tried it without the callback and it worked fine as well...

Trying to display image in an HTML5 canvas

I've tried all code variations that are online. I just want to display an image on a canvas. I've tried code from this site.
window.onLoad=function(){
function draw(){
var ctx = document.getElementById("canvas1").getContext("2d");
var img = new Image();
img.src = 'images/ball.png';
img.onload = function(){
ctx.drawImage(img,0,0);
};
};
};
It's not the file path that's a problem, that has been tested without the images folder. There are no errors in the console. Thanks.
One search in google and there you go with complete jsfiddle example:
// Grab the Canvas and Drawing Context
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Create an image element
var img = document.createElement('IMG');
// When the image is loaded, draw it
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
// Specify the src to load the image
img.src = "http://i.imgur.com/gwlPu.jpg";
http://jsfiddle.net/jimrhoskins/Sv87G/

canvas to image shows as no image (blank)

I'm working on converting a canvas to an image using dataurl. I have the following code that outputs no error in console. Seems to work somewhat, but when i access the dataurl it shows a blank image.
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
var myImage = context.drawImage(imageObj, 0, 0);
var myImg = canvas.toDataURL("image/png");
document.getElementById("canvasimg").setAttribute("src", myImg);
};
imageObj.src = "http://img801.imageshack.us/img801/5641/3cc67ca1a74049ce99bc92b.png";
};
<canvas id="myCanvas" width="578" height="400"></canvas>
<img id="canvasimg" alt="" src="">
Look at what you are doing. You are drawing the image when the image loads, but you are converting it to a data url before the image has been drawn! Move that toDataURL call and the setAttribute call INSIDE the onload function.
Testing the code you have posted, I get a Security Error raised. Which is to be expected. The canvas has a clean-origin flag, and once that flag is false, you can't pull data out of it.
Here's a more detailed, related question
Documentation linked to in the answer

Display Image using canvas in JavaScript/jQuery

I have the following code :
function createImage(source) {
var pastedImage = new Image();
pastedImage.onload = function() {
document.write('<br><br><br>Image: <img src="'+pastedImage.src+'" height="700" width="700"/>');
}
pastedImage.src = source;
}
Here I am displaying the image through html image tag which I wrote in document.write and provide appropriate height and width to image.
My question is can it possible to displaying image into the canvas instead of html img tag? So that I can drag and crop that image as I want?
But how can I display it in canvas?
Further I want to implement save that image using PHP but for now let me know about previous issue.
Try This
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image(); // Create new img element
img.onload = function(){
// execute drawImage statements here This is essential as it waits till image is loaded before drawing it.
ctx.drawImage(img , 0, 0);
};
img.src = 'myImage.png'; // Set source path
Make sure the image is hosted in same domain as your site. Read this for Javascript Security Restrictions Same Origin Policy.
E.g. If your site is http://example.com/
then the Image should be hosted on http://example.com/../myImage.png
if you try http://facebook.com/..image/ or something then it will throw security error.
Use
CanvasRenderingContext2D.drawImage.
function createImage(source) {
var ctx = document.getElementById('canvas').getContext('2d');
var pastedImage = new Image();
pastedImage.onload = function(){
ctx.drawImage(pastedImage, 0, 0);
};
pastedImage = source;
}
Also MDN seems to be have nice examples.

Categories