I am trying to generate an image out of the contents of a div. Unfortunately it is not working for me. The reason why I want to do that is because I want to send the generated image to a printer as a base64 string.
Anyway, below is my code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = "data:image/svg+xml," +
"<svg xmlns='http://www.w3.org/2000/svg' width='300' height='250'>" +
"<foreignObject width='100%' height='100%'>" +
document.getElementById('receipt_wrapper').innerHTML +
"</foreignObject>" +
"</svg>";
var img = new Image();
img.src = data;
img.onload = function () { ctx.drawImage(img, 0, 0); };
var dataURL = canvas.toDataURL("image/png");
var imgBase64 = dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
if (window.Android != undefined) {
Android.print(image);
}
Nothing is showing up in the canvas. What is wrong with my code?
P.S: I'm running this code inside an Android device.
That method no longer works on modern browsers.
Using svg's foreignObject to capture webpage content is no longer allowed because of cross-domain security implemented by modern browsers.
If your receipt is simple html and does not include cross domain images you might take a look at html2canvas for content capturing on the client-side:
http://html2canvas.hertzen.com/
Alternatively, you could also use a "headless browser" like phantomJS if you want to capture webpage content on the server:
http://phantomjs.org/
Related
I have lightbox gallery with download button on each image. I have no problem with the download on chrome but I have problems with IE. That is why I am doing it with canvas like this:
if (browser() === 'IE') {
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
var img = $('.lb-image')[0];
imgWidth = $(img).prop('naturalWidth');
imgHeight = $(img).prop('naturalHeight');
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.drawImage(img, 0, 0, imgWidth,imgHeight,0, 0, canvas.width, canvas.height);
window.navigator.msSaveBlob(canvas.msToBlob(), imgName);
Yesterday I saw that when you download a picture through IE browser, the image size is larger than the uploaded one or if it is downloaded via chrome. I inspected the images info and I saw that the only difference is the bit depth. It is larger on the IE's canvas downloaded image.
How can I manually set the bit depth or is there a better approach ?
Drawing an Image on a canvas will convert this Image from whatever format to raw 24bits of RGB + 8bits Alpha (8bits depth). Currently there is no official option to set it yourself.
All you can do is to choose which compression (jpeg, png, webp) will be used when exporting the canvas, but this compression is made on this 8bits depth raw data anyway. So whatever you do, drawing on a canvas is loosy and the result will have nothing to do with the original Image file anymore.
But anyway, your workaround is not the correct one.
Your original problem is that you want to enable the <a href="someURL" download="myFile.png"> in IE.
Instead of drawing the image on a canvas, request it through ajax as an Blob. Then you'll be able to use navigator.msSaveBlob easily :
if (browser() === 'IE') {
var xhr = new XMLHttpRequest();
xhr.open('get', img.src);
xhr.responseType = 'blob';
xhr.onload = function(){
window.navigator.msSaveBlob(xhr.response, imgName);
}
xhr.send();
}
With this code, what you will download through msSaveBlob is the real file stored on the server, just like <a download>.
Important note
This will obviously work only with same-origin resources, just like <a download> and even like the canvas workaround.
I want a valid string of base64 from imageuri. I have use below code for this but it's getting black image after uploading it to the server.
function encodeImageUri(imageUri)
{
var c=document.createElement('canvas');
var ctx=c.getContext("2d");
var img=new Image();
img.onload = function(){
c.width=this.width;
c.height=this.height;
ctx.drawImage(img, 0,0);
};
img.src=imageUri;
var dataURL = c.toDataURL("image/jpeg");
return dataURL;
}
I have also tried other options but not getting solid solution to get the valid base64 imagedata. I don't want to upload image using file-transfer method. I want to convert the imageuri in simple base64 string. Please suggest me specific answer for the same.
Thanks
Please note that I've not tested this within PhoneGap.
It's possible you're being caught out by the image being loaded asynchronously; you're encoding it into a string before it's actually loaded and processed in full.
There are various ways of handling this; one possibility is to move to using a success() method to handle the return value, which will be called once the image has loaded and been drawn:
function encodeImageUri(imageUri, success)
{
var c=document.createElement('canvas');
var ctx=c.getContext("2d");
var img=new Image();
img.onload = function(){
c.width=this.width;
c.height=this.height;
ctx.drawImage(img, 0,0);
success(c.toDataURL("image/jpeg"));
};
img.src=imageUri;
}
You will then need to call encodeImageUri with a function that will handle the end result, for example:
encodeImageUri(" < url > ", function (data) {
console.log(data);
});
Depending upon the security model PhoneGap uses, you may have to look out for CORS-related issues (see Tainted canvases may not be exported).
I am trying to export an SVG created in the browser (a d3.js chart) as a PNG using methods based from https://github.com/exupero/saveSvgAsPng and http://techslides.com/save-svg-as-an-image. The SVG is converted to a data URI and rendered as an image in a canvas, which is converted to a PNG data URI. This URI is downloaded as a file using an anchor tag. I have been able to confirm this to work in current versions of FF, Chrome, and Safari; however, triggering the download on the anchor tag causes Edge to either hang (with only a doctype warning in the console) or crash completely. Is there anyway to get this to work in Edge or is the anchor download with data URI not fully supported yet?
Code created from the sources above:
//this gets the svg and inlines all styles. It has a property "source" as well as width and height of the SVG.
var svgDownload = getElementChildrenAndStyles(svgID);
var image = new Image();
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = svgDownload.width;
canvas.height = svgDownload.height;
var ctx = canvas.getContext('2d');
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(image, 0, 0);
var a = document.createElement("a");
a.download = "chart.png";
try {
console.log("converting canvas");
a.href = canvas.toDataURL("image/png");
console.log("canvas converted. triggering download");
document.body.appendChild(a);
a.addEventListener("click", function(e) {
a.parentNode.removeChild(a);
});
a.click();
}
catch (e){
//error handling
}
};
try {
console.log("making image source url");
//both methods of creating the image source here work in most browsers except Edge
//image.src = "data:image/svg+xml;base64," + btoa( svgDownload.source.join() );
image.src = window.URL.createObjectURL(new Blob(svgDownload.source, {"type": 'image/svg+xml;base64'}));
console.log("image source set");
}
catch (e){
//error handling
}
Realise this is an old question but for others that end up here: Edge and IE don't support dataURL as the href of an anchor tag. It will accept it as the source of an img tag though. The best solution I've been able to come up with is to use download.js to download the file. However, the next problem you will hit is when you set the src of an image tag to SVG to do the rendering of the PNG, the "load" event won't fire in Edge for that Image object. Haven't got a way around that just yet.
Im having trouble figuring out why two different svg's would cause my javascript to work in one instance, but not in the other. I have only swapped out the svg elements in both examples, one works, one does not. Here is the code in two jsFiddles. The working example I got from here.
Ultimately, my goal is to save the current svg element of the floor plan, and insert the converted png as an inline img inside a rich text area. As if you took a cropped screenshot of the floor plan, and pasted it into a rich text area like you see in helpdesk sites. Im just having trouble converting to png.
Working: JsFiddle
Not Working: JsFiddle
Here is the js, i cant add the svg code or it will put me over the character limit of Stackoverflow.
var svgString = new XMLSerializer().serializeToString(document.querySelector('#svg2'));
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;
Edit:
I have since settled on this code omitting the png/canvas conversions, and trying to place the serialized string of the svg, directly to the rich text area, but it gets an error in IE, Non-default namespace declarations must not have an empty URI. Line: 1, column142
var svgString = new XMLSerializer().serializeToString(document.querySelector('#svg2'));
var img = new Image();
var url = "data:image/svg+xml; charset=utf8, "+encodeURIComponent(svgString);
img.onload = function() {
document.querySelector('.ze_body').innerHTML = '<img src="'+url+'"/>';
};
img.src = url;
Also i think it would help if i showed more of the structure of how this rich text area currently sits. This is not our doing, its a product we use, and im just trying to get maps to paste into the description area so it can live with the ticket. Only access we have is js triggered from rules in the form.
Screenshot of ze_body element as it stands in the DOM
It comes from your namespace declaration :
Change xmlns:NS1="" NS1:xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:NS2="" NS2:xmlns:cc="http://creativecommons.org/ns#" xmlns:NS3="" NS3:xmlns:dc="http://purl.org/dc/elements/1.1/"
to xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> and it should work.
Also note that since you are using XMLSerializer().serializeToString(), you don't need to create a blob and an objectURL, you can only pass data:image/svg+xml; charset=utf8, " and the encodeURIComponent(svgString) as the url of your image. (fiddle).
ps: You can read about namespace declaration here.
In Javascript you have the ByteArray type and some views on it as described here:
https://developer.mozilla.org/en-US/docs/JavaScript/Typed_arrays
is it possible to store image data in such bytes and if yes, how can i display such an image? png or jpg?
Yes, you can store an image using the typed arrays.
Im not sure what you want actually.
If you want to create an HTMLImageElement from a ByteArray, you can do something similar as cited in here and here.
If you want to get the bytes from an Image, that would be trickier. You can draw the ImageElement to HTML canvas, and them get the URI back using toDataURL.
I just tried to get the data using canvas and it worked.
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
myCanvas.width = img.width;
myCanvas.height = img.height;
ctx.drawImage(img,0,0); // Or at whatever offset you like
alert(myCanvas.toDataURL());
};
img.src = "logo4w.png";
Although, the method toDataURL() do not allow you to perform this operation if the image you draw on canvas comes from outside the website domain.