Read image from Url and save it in base64 in html / phonegap - javascript

I'm trying to read a URL (the resource of which is an image) and encode this image in base64 to save it in a database.
I've looked around Google and Stackoverflow and a lot of people say that it is impossible to save a base64 formatted image that you read from a URL.(Are they wrong?)
My steps are as follows:
I parse an XML file where there is a URL for the image. I'm trying to save this image in a base64 format in a DB.
Can anybody help me?

I can't readily put together an example of this, but it should be possible, assuming the image is coming from the same domain you are running the code on, or you can control the cross origin header for the image (or else you'll get a Cross-origin error).
Assuming this is the case, you can. Here is a JSFiddle where I encode the logo of JSFiddle: http://fiddle.jshell.net/5S6BY/ (since that logo is on the same domain as where the code is running, it works).
The trick is to draw it to a canvas, then convert that canvas to a base64.
Here is the code:
var url = "http://fiddle.jshell.net/img/logo.png";
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
var image = new Image();
image.crossOrigin = 'anonymous';
image.addEventListener('load', function() {
ctx.drawImage(image, 0, 0, image.width, image.height);
document.body.innerHTML = canvas.toDataURL();
});
image.src = url;
It's pretty straight forward. Load the image, draw the image to the canvas, then call canvas.toDataUrl() to get the base64 encoded version, which you can use to do whatever you want.

Related

chrome.browserAction.setIcon - Downloaded image

I want to make a Chrome addon, which displays ones Facebook picture.
Mine e.g. is this one.
I do get the final Url and the response of an XMLHttpRequest.
In response.response I have the image data, which starts with ����JFIF���Photoshop 3.08BIM�gO87swNzt0qHGr_stQXIz(bFBMD01000aa00100001d020000b6020000ec02000027030
I am trying to store and than display it. (I want to display this bigger on a different place as well). So I do not want to use path in chrome.browserAction.setIcon, but the Image itself.
I tried a lot of things (and will continue tomorrow). So far:
I need an ImageData Object
I need an ImageData Object smaller than <= 19 pixels.
I do know the size of the image from facebook (50x50)
Tomorrow I will continue with trying this. I forgot, that the Image is not base64 encoded yet, so the solution linked in this sentence was not able to work...
My problem is: How to create the ImageData-Object(s) required by chrome.browserAction.setIcon frim the icon above in JS. Using the "html5-canvas" tag, as ImageData is very close to a canvas.
As always, answers are highly appreciated.
Yours,
Florian
facebook graph API does send the proper Access-Control-Allow-Origin "*" in the header of the image's response.
So all you need is to set the crossorigin attribute of an <img> tag to 'anonymous', draw this image onto a canvas and use either the imageData you get from ctx.getImageData() or the dataURI you get from canvas.toDataURL().
var c = document.createElement('canvas');
var ctx = c.getContext('2d')
var img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function(){
c.width = this.width;
c.height = this.height;
ctx.drawImage(this, 0,0);
// either you do use the image data
var imagedata = ctx.getImageData(0,0,c.width, c.height);
snippet.log('imagedata length : '+imagedata.data.length);
// or the dataURL
var dataURL = c.toDataURL();
snippet.log(dataURL);
document.body.style.backgroundImage = 'url('+dataURL+')';
}
img.src = "https://graph.facebook.com/100004288501341/picture?type=square"
p{background-color: rgba(230, 230, 250,.7);}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

AngularJS save and display image from URL

I wish to create a simple function in angularJS so I can read image from URL. Simply I put image URL and it convert image of that URL to base64 and saves to DB as well it shows to that Image Canvas. I wish to read image of all type irrespective of only PNG.
I have tried few logics, from Google I found code where it takes dimensions of canvas first..
$scope.convertBase64 = function () {
console.log("Firing Function");
var canvas = $scope.imageURL;
canvas.width = $scope.imageURL.width;
canvas.height = $scope.imageURL.height;
var ctx = canvas.getContext("2d");
ctx.drawImage($scope.imageURL, 0, 0);
var dataURL = canvas.toDataURL("image/png");
$scope.imageURLBase = dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
return $scope.imageURLBase;
};
At same moment I wish to save image's base64 content. How to render using that base64 content anytime irrespective of canvas size using ng-source or else.

How to draw an inline svg (in DOM) to a canvas?

Well, I need some help about convert .svg file/image to .png file/image...
I have a .svg image displayed on my page. It is saved on my server (as a .png file). I need to convert it to a .png file on demand (on click on a button) and save the .png file on the server (I will do this with an .ajax request).
But the problem is the conversion.
I read many things about the html5 Canvas, which can probably help doing what I need to do now, but I can't find any clear solution to my problem, and, tbh, I do not understand everything I found... So I need some clear advices/help about the way I have to do it.
Here is the "html idea" template :
<html>
<body>
<svg id="mySvg" width="300px" height="300px">
<!-- my svg data -->
</svg>
<label id="button">Click to convert</label>
<canvas id="myCanvas"></canvas>
</body>
</html>
and some js :
<script>
$("body").on("click","#button",function(){
var svgText = $("#myViewer").outerHTML;
var myCanvas = document.getElementById("canvas");
var ctxt = myCanvas.getContext("2d");
});
</script>
Then, I need to draw the svg into the Canvas, get back the base64 data, and save it in a .png file on my server... but... how? I read about so many different solutions that I'm actually... lost... I'm working on a jsfiddle, but I'm actually... nowhere... http://jsfiddle.net/xfh7nctk/6/ ... Thanks for reading / help
For inline SVG you'll need to:
Convert the SVG string to a Blob
Get an URL for the Blob
Create an image element and set the URL as src
When loaded (onload) you can draw the SVG as an image on canvas
Use toDataURL() to get the PNG file from canvas.
For example:
function drawInlineSVG(ctx, rawSVG, callback) {
var svg = new Blob([rawSVG], {type:"image/svg+xml;charset=utf-8"}),
domURL = self.URL || self.webkitURL || self,
url = domURL.createObjectURL(svg),
img = new Image;
img.onload = function () {
ctx.drawImage(this, 0, 0);
domURL.revokeObjectURL(url);
callback(this);
};
img.src = url;
}
// usage:
drawInlineSVG(ctxt, svgText, function() {
console.log(canvas.toDataURL()); // -> PNG data-uri
});
Of course, console.log here is just for example. Store/transfer the string instead here. (I would also recommend adding an onerror handler inside the method).
Also remember to set canvas size using either the width and height attributes, or from JavaScript using properties.
I come long after since some other question raised from this one because the accepted answer may produce undesirable behavior.
#K3N solution is almost right, but I would go against the use of svgElement.outerHTML.
Instead, one should prefer new XMLSerializer().serializeToString(svgElement).
Also, the use of blob and of the URL API is not necessary and a simple dataURI has more compatibility accross browsers.
So a complete version of this would be :
function drawInlineSVG(svgElement, ctx, callback) {
var svgURL = new XMLSerializer().serializeToString(svgElement);
var img = new Image();
img.onload = function() {
ctx.drawImage(this, 0, 0);
callback();
}
img.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL);
}
// usage:
drawInlineSVG(document.querySelector('svg'), ctxt, function() {
console.log(canvas.toDataURL())
});

fabric.js - toDataURL shows blank page when there is image on canvas

I'm using fabric.js for my canvas application, toDataURL method works properly except when there is a image on canvas. When i add an image to canvas and call toDataURL it shows me a blank page.
//When i call it from chrome console
canvas.toDataURL();
//It returns a working data url with no problem.
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAGkCAYAAAAPPajHAAAgAElEQ…fpmwgogX1TrjoqP0FACewngtZh+iYCSmDflKuOyk8Q+H+CKCqUW0spTgAAAABJRU5ErkJggg=="
//When i execute same code in a .js file it returns a data url which shows a blank image.
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAGkCAYAAAAPPajHAAAKC0lEQ…sBAmEBAw6XJzoBA/YDBMICBhwuT3QCBuwHCIQFDDhcnugEHt/IAaW9dzALAAAAAElFTkSuQmCC"
It's interesting that it's working on chrome dev console but not works in .js file even if it's same code. I noticed that working data url finishes with '==' but other one not. However i don't know what this means.
You didn't give much to analyze but I'll go from there on my gut feeling.
The image you are using is probably violating Cross-Origin Resource Sharing (CORS) requirements. When this happens the canvas will return a blank image when you try to get the pixel data either by using canvas.toDataURL() or context.getImageData().
It basically happens when the image is not located on the same domain as the page or is loaded from the file:// protocol.
You can try to add the following to the image object before setting the source:
image.crossOrigin = 'anonymous';
image.src = '...';
From tag:
<img crossOrigin='anonymous' src='...' alt='' />
This will request permission from the server to use the image cross-origin. If the server allows you should be fine.
If not you will either have to copy the image to your own server so it loads from the same domain as your page, or create a proxy page that loads the image externally and serves it to your page from the proxy page (it sounds complicated but really isn't).
If the image does not show up at all on the canvas you are probably not using load callback which you need since image loading is asynchronous. If so just add:
image.onload = function() {
/// now you can draw the image to canvas
}
image.crossOrigin = 'anonymous';
image.src = '...';
The problem is solved. The point i missed is, i was calling toDataURL function before canvas is loaded, that's why it was showing me a blank page.
canvas.loadFromJSON(json,function(){
var dataURL = canvas.toDataURL();
});
This solved my problem when i gave toDataURL() function as a callback to loadFromJSON function.
But after a while i had a different issue about CORS when i tried to upload my images from s3 bucket and i solved this problem as upward solution.
I was facing the same issues when I was trying to generate images from the canvas using Fabricsjs and generate PDF from images using JSPDF so below is my case I also spend hours on this may this can help someone to save time.
Load the canvas from JSON that i.e
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(obj, object) {
//fabric.log(obj, object);
});
Canvas was drawing images all fine then I was generating the images from that canvas it was a case of multiple images in a single canvas and I was generating PDF based on each page of the canvas.
Instead of this
canvas.toDataURL('image/png', 0.1)
I used this and it starts returning me the propper images dataurl
var imgData = document.getElementById('canvas_0').toDataURL();
Below are snippets
$("#pdfSelector .canvas-container").each(function(index, value){ // canvas selector
html2canvas($("#canvas_"+index), { // html2canvas used to get images
onrendered: function(canvas) { // on successfully render of images
//var imgData = canvas.toDataURL('image/png', 0.1);
var imgData = document.getElementById('canvas_0').toDataURL();
const imgProps= doc.getImageProperties(imgData);
const pdfWidth = doc.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
doc.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight, 'page_'+index, 'FAST');
}
});
});

Canvas toDataUrl increases file size of image

When using toDataUrl() to set the source of an image tag I am finding that the image when saved is a great deal larger than the original image.
In the example below I am not specifying a second param for the toDataUrl function so the default quality is being used. This is resulting in an image much larger that the original image size. When specifying 1 for full quality the image generated is even larger.
Does anybody know why this is happening or how I can stop it?
// create image
var image = document.createElement('img');
// set src using remote image location
image.src = 'test.jpg';
// wait til it has loaded
image.onload = function (){
// set up variables
var fWidth = image.width;
var fHeight = image.height;
// create canvas
var canvas = document.createElement('canvas');
canvas.id = 'canvas';
canvas.width = fWidth;
canvas.height = fHeight;
var context = canvas.getContext('2d');
// draw image to canvas
context.drawImage(image, 0, 0, fWidth, fHeight, 0, 0, fWidth, fHeight);
// get data url
dataUrl = canvas.toDataURL('image/jpeg');
// this image when saved is much larger than the image loaded in
document.write('<img src="' + dataUrl + '" />');
}
Thank you :D
Here is an example, unfortunately the image cannot be cross domain and so I am having to just pull one of the jsfiddle images.
http://jsfiddle.net/ptSUd/
The image is 7.4kb, if you then save the image which is being output you will see that it is 10kb. The difference is more noticeable with more detailed images. If you set the toDataUrl quality to 1, the image is then 17kb.
I am also using FireFox 10 for this, when using Chrome the image sizes are still larger but not by as much.
The string returned by the toDataURL() method does not represent the original data.
I have just performed some extensive tests, which showed that the created data-URL depends on the browser (not on the operating system).
Environment - md5 sum - file size
Original file - c9eaf8f2aeb1b383ff2f1c68c0ae1085 - 4776 bytes
WinXP Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Firefox 10.0.2 - 4f184006e00a44f6f2dae7ba3982895e - 3909 bytes
The method of getting the data-URI does not matter, the following snippet was used to verify that the data-URI from a file upload are also different:
Test case: http://jsfiddle.net/Fkykx/
<input type="file" id="file"><script>
document.getElementById('file').onchange=function() {
var filereader = new FileReader();
filereader.onload = function(event) {
var img = new Image();
img.onload = function() {
var c = document.createElement('canvas'); // Create canvas
c.width = img.width;
c.height = img.height; c.getContext('2d').drawImage(img,0,0,img.width,img.height);
var toAppend = new Image;
toAppend.title = 'Imported via upload, drawn in a canvas';
toAppend.src = c.toDataURL('image/png');
document.body.appendChild(toAppend);
}
img.src = event.target.result; // Set src from upload, original byte sequence
img.title = 'Imported via file upload';
document.body.appendChild(img);
};
filereader.readAsDataURL(this.files[0]);
}
</script>
The size of the image is determined mostly by the quality of the encoder built into the browser. It has very little to do with the size of the original image. Once you draw anything onto a canvas all you have are pixels, you no longer have the original image. toDataURL does not magically reconstitute an image that was painted onto the canvas. If you want a file with the same size as the original image: use the original image.
Looks like kirilloid and Rob nailed it. I had this issue too and it appears to be a combo:
the dataURL uses base64 encoding which makes it around 1.37 X larger
each browser processes the toDataURL function differently
base64 encoded image size
I tested my thumbnail generator in win8.1 firefox and chrome and got dataURL string sizes:
firefox = 3.72kB
chrome = 3.24kB
My original image when converted to dataURL went from 32kB to 45kB.
I think the base64 part is the larger factor so I guess my plan now is to convert the dataURL back to a binary byte array before I store it on the server (probably on the client side because my server's lazy).

Categories