File image onloaded is not called after calling readAsDataURL on large images - javascript

I am trying to read an image file and resize and upload it in Ionic2 on Android. My code works for small size images, but for images that are more than 3MB, the onloaded function is never called.
I really appreciate any help or insight as to why.
makeFileIntoBlob(_imagePath) {
return new Promise((resolve, reject) => {
window.resolveLocalFileSystemURL( _imagePath, fileEntry => {
fileEntry.file(file => {
var reader = new FileReader();
console.log('Reading the file!');
reader.onloadend = (e: any) => {
var img = document.createElement("img");
img.onload = () => {
//---> Only get here for small images!
var resizedImg = this.imgResizerSrvc.resize(img, 480, 480);
var imgBlob: any = this.dataURLtoBlob(resizedImg);
imgBlob.name = 'sample.jpg';
console.log('makeFileIntoBlob resolved!');
resolve(imgBlob);
}
//Will trigger img.onloadend
alert("about to trigger");
img.src = e.target.result; //----> This call only triggeres reader.onloadend for small images
alert("Done trigger");
};
reader.readAsDataURL(file);
});
});
});
}
As an alternative, I have also tried reading the file using the following:
img.src = (window.URL ? URL : window.webkitURL).createObjectURL( file );
or
img.src = (window.URL || window.webkitURL || window || {}).createObjectURL( file );
but none of these trigger img.onloaded().

There could be a limitation on the .length of the data URI
Length limitations
Although Firefox supports data URIs of essentially
unlimited length, browsers are not required to support any particular
maximum length of data. For example, the Opera 11 browser limited data
URIs to around 65000 characters.
You could use URL.createObjectURL() called on file, without using FileReader(), pass Blob created by .imgResizerSrvc.resize to File() to set the .name of the create File object.
makeFileIntoBlob(_imagePath) {
return new Promise((resolve, reject) => {
window.resolveLocalFileSystemURL(_imagePath, fileEntry => {
fileEntry.file(file => {
var component = /* reference to ionic2 component */ ;
var img = document.createElement("img");
img.onload = () => {
var resizedImg = component.imgResizerSrvc.resize(this, 480, 480);
var imgBlob = new File([resizedImg], "sample.jpg", {
type: "image/jpeg"
});
resolve(imgBlob);
};
img.src = URL.createObjectURL(file);
});
});
});
}

Related

I'm trying to get the height of the image from base64

I'm trying to get the height of the image from base64. Here's my code,
let reader = new FileReader()
reader.readAsDataURL(file);
reader.onloadend = function() {
let img = document.createElement('img');
img.src = reader.result; //data:image/png;base64,...
console.log(img.height);
}
and looking on log it return 0.
How to get the height of the image in that way?
Full code
function handleDrop(e) {
var dt = e.dataTransfer
var files = dt.files
handleFiles(files)
}
function handleFiles(files) {
files = [...files]
files.forEach(previewFile)
}
function previewFile(file) {
let reader = new FileReader()
reader.readAsDataURL(file);
reader.onload = function() {
let img = document.createElement('img');
let div = document.createElement('div');
img.src = reader.result;
div.appendChild(img);
document.getElementById('gallery').appendChild(div);
}
}
dropArea.addEventListener('drop', handleDrop, false)
Where-possible you should use createObjectURL instead of using data:-URIs in scripts because a data:-URI requires serializing the entire object into memory as a string with 1/3rd extra memory usage (so if you have a 1MB-sized image, you now need an additional 1.33MB just for the data: URI string, whereas an object URL is usually just a short GUID).
Creating data URIs is also synchronous and blocks the UI thread - you can easily freeze a Chrome tab by creating a data: URI from a large image or video.
Whereas createObjectURL is very, very cheap - the only catch is you need to watch the lifetime of the URL and make sure you use revokeObjectURL.
Change your code to this.
Note that FileReader is not needed at all.
async function printImageDimensions( file ) {
if( !file ) return;
if( !( file instanceof File ) ) return;
//
const img = document.createElement( 'img' );
const objUrl = URL.createObjectURL( file );
try {
const dim = await loadImageAsync( img, objUrl );
console.log( "Width: %d, Height: %d", dim.w, dim.h );
}
finally {
URL.revokeObjectURL( objUrl );
}
}
function loadImageAsync( img, url ) {
return new Promise( ( resolve, reject ) => {
function onLoad() {
const ret = { w: img.naturalWidth, h: img.naturalHeight };
resolve( ret );
}
function onError() {
reject( "Load failed." );
}
img.addEventListener( 'load', onLoad );
img.addEventListener( 'error', onError );
img.src = url;
} );
}

How to issue a post to a json rest api with a base64 encoded html input from a SPA [duplicate]

I need to convert my image to a Base64 string so that I can send my image to a server.
Is there any JavaScript file for this? Else, how can I convert it?
There are multiple approaches you can choose from:
1. Approach: FileReader
Load the image as blob via XMLHttpRequest and use the FileReader API (readAsDataURL()) to convert it to a dataURL:
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0', function(dataUrl) {
console.log('RESULT:', dataUrl)
})
This code example could also be implemented using the WHATWG fetch API:
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}))
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0')
.then(dataUrl => {
console.log('RESULT:', dataUrl)
})
These approaches:
have better compression
work for other file types as well
Browser Support:
http://caniuse.com/#feat=filereader
http://caniuse.com/#feat=fetch
2. Approach: Canvas (for legacy browsers)
Load the image into an Image-Object, paint it to a nontainted canvas and convert the canvas back to a dataURL.
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
toDataURL(
'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
function(dataUrl) {
console.log('RESULT:', dataUrl)
}
)
In detail
Supported input formats:
image/png, image/jpeg, image/jpg, image/gif, image/bmp, image/tiff, image/x-icon, image/svg+xml, image/webp, image/xxx
Supported output formats:
image/png, image/jpeg, image/webp(chrome)
Browser Support:
http://caniuse.com/#feat=canvas
Internet Explorer 10 (Internet Explorer 10 just works with same origin images)
3. Approach: Images from the local file system
If you want to convert images from the users file system you need to take a different approach.
Use the FileReader API:
function encodeImageFileAsURL(element) {
var file = element.files[0];
var reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
<input type="file" onchange="encodeImageFileAsURL(this)" />
You can use the HTML5 <canvas> for it:
Create a canvas, load your image into it and then use toDataURL() to get the Base64 representation (actually, it's a data: URL, but it contains the Base64-encoded image).
This snippet can convert your string, image and even video file to Base64 string data.
<input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" />
<div id="imgTest"></div>
<script type='text/javascript'>
function encodeImageFileAsURL() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: base64
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("imgTest").innerHTML = newImage.outerHTML;
alert("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
console.log("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
}
fileReader.readAsDataURL(fileToLoad);
}
}
</script>
Basically, if your image is
<img id='Img1' src='someurl'>
then you can convert it like
var c = document.createElement('canvas');
var img = document.getElementById('Img1');
c.height = img.naturalHeight;
c.width = img.naturalWidth;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL();
Here is what I did:
// Author James Harrington 2014
function base64(file, callback){
var coolFile = {};
function readerOnload(e){
var base64 = btoa(e.target.result);
coolFile.base64 = base64;
callback(coolFile)
};
var reader = new FileReader();
reader.onload = readerOnload;
var file = file[0].files[0];
coolFile.filetype = file.type;
coolFile.size = file.size;
coolFile.filename = file.name;
reader.readAsBinaryString(file);
}
And here is how you use it
base64( $('input[type="file"]'), function(data){
console.log(data.base64)
})
I found that the safest and reliable way to do it is to use FileReader().
Demo: Image to Base64
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
var selectedfile = document.getElementById("myinput").files;
if (selectedfile.length > 0) {
var imageFile = selectedfile[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result;
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("dummy").innerHTML = newImage.outerHTML;
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
UPDATE - THE SAME CODE WITH COMMENTS FOR #AnniekJ REQUEST:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
// Get the file objects that was selected by the user from myinput - a file picker control
var selectedfile = document.getElementById("myinput").files;
// Check that the user actually selected file/s from the "file picker" control
// Note - selectedfile is an array, hence we check it`s length, when length of the array
// is bigger than 0 than it means the array containes file objects
if (selectedfile.length > 0) {
// Set the first file object inside the array to this variable
// Note: if multiple files are selected we can itterate on all of the selectedfile array using a for loop - BUT in order to not make this example complicated we only take the first file object that was selected
var imageFile = selectedfile[0];
// Set a filereader object to asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.
var fileReader = new FileReader();
// We declare an event of the fileReader class (onload event) and we register an anonimous function that will be executed when the event is raised. it is "trick" we preapare in order for the onload event to be raised after the last line of this code will be executed (fileReader.readAsDataURL(imageFile);) - please read about events in javascript if you are not familiar with "Events"
fileReader.onload = function(fileLoadedEvent) {
// AT THIS STAGE THE EVENT WAS RAISED
// Here we are getting the file contents - basiccaly the base64 mapping
var srcData = fileLoadedEvent.target.result;
// We create an image html element dinamically in order to display the image
var newImage = document.createElement('img');
// We set the source of the image we created
newImage.src = srcData;
// ANOTHER TRICK TO EXTRACT THE BASE64 STRING
// We set the outer html of the new image to the div element
document.getElementById("dummy").innerHTML = newImage.outerHTML;
// Then we take the inner html of the div and we have the base64 string
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
// This line will raise the fileReader.onload event - note we are passing the file object here as an argument to the function of the event
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
If you have a file object, this simple function will work:
function getBase64 (file, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(file);
}
Usage example:
getBase64(fileObjectFromInput, function(base64Data){
console.log("Base64 of file is", base64Data); // Here you can have your code which uses Base64 for its operation, // file to Base64 by oneshubh
});
I ended up using a function that returns a Promise.
const getImg64 = async() => {
const convertImgToBase64URL = (url) => {
console.log(url)
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = () => {
let canvas = document.createElement('CANVAS')
const ctx = canvas.getContext('2d')
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL();
canvas = null;
resolve(dataURL)
}
img.src = url;
})
}
//for the demonstration purposes I used proxy server to avoid cross origin error
const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
const image = await convertImgToBase64URL(proxyUrl+'https://image.shutterstock.com/image-vector/vector-line-icon-hello-wave-260nw-1521867944.jpg')
console.log(image)
}
getImg64()
You can use this approach in any async function. Then you can just await for the converted image and continue with instructions.
uploadProfile(e) {
let file = e.target.files[0];
let reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
Here is the way you can do with Javascript Promise.
const getBase64 = (file) => new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject('Error: ', error);
})
Now, use it in event handler.
const _changeImg = (e) => {
const file = e.target.files[0];
let encoded;
getBase64(file)
.then((result) => {
encoded = result;
})
.catch(e => console.log(e))
}
You could use FileAPI, but it's pretty much unsupported.
As far as I know, an image can be converted into a Base64 string either by FileReader() or storing it in the canvas element and then use toDataURL() to get the image. I had the similar kind of problem you can refer this.
Convert an image to canvas that is already loaded
Try this code:
For a file upload change event, call this function:
$("#fileproof").on('change', function () {
readImage($(this)).done(function (base64Data) { $('#<%=hfimgbs64.ClientID%>').val(base64Data); });
});
function readImage(inputElement) {
var deferred = $.Deferred();
var files = inputElement.get(0).files;
if (files && files[0]) {
var fr = new FileReader();
fr.onload = function (e) {
deferred.resolve(e.target.result);
};
fr.readAsDataURL(files[0]);
} else {
deferred.resolve(undefined);
}
return deferred.promise();
}
Store Base64 data in hidden filed to use.
document.querySelector('input').onchange = e => {
const fr = new FileReader()
fr.onloadend = () => document.write(fr.result)
fr.readAsDataURL(e.target.files[0])
}
<input type="file">
Needed to leverage reader to convert blob to base64, prefer to use async-await syntax so I chose to extract reader logic into helper like this:
//* Convert resBlob to base64
export const blobToData = (blob: Blob) => {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
and calling it using await in main code:
//* Convert resBlob to dataUrl and resolve
const resData = await blobToData(resBlob)
In the case you are facing cors origin error, there is a simple proxy called cors-fix that loads the image on server and return it as buffer array.
Therefore, we can use fetch to get the image data and filereader to convert it to dataUrl, as described by #HaNdTriX.
function toDataUrl(url) {
fetch(`https://cors-fix.web.app/v1?url=${url}`)
.then(data => data.blob().then(blob => {
const reader = new FileReader();
reader.onloadend = () => {
console.log(reader.result);
};
reader.onerror = () => {
console.log('reader error');
};
reader.readAsDataURL(blob);
}));
}
Well, if you are using Dojo Toolkit, it gives us a direct way to encode or decode into Base64.
Try this:
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a Base64-encoded string:
var bytes = dojox.encoding.base64.decode(str);
You can also simply extract base-64 only part of the URL by ding this:
var Base64URL = canvas.toDataURL('image/webp')
var Base64 = Base64URL.split(",")[1] //Returns the base64 part
Assuming that you are doing this in a browser:
With await:
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' });
return window.URL.createObjectURL(response.data);
With promise
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' })
.then((response) => {
const dataUrl = window.URL.createObjectURL(response.data);
// do something with your url
});
This is very simple.
1> Just call the function and pass your image.
2> Save the return value and use wherever required.
//call like this
const convertedFile = await imageToBase64(fileObj);
console.log("convertedFile",convertedFile);
//this is the required function
async function imageToBase64(image) {
const reader = new FileReader();
reader.readAsDataURL(image);
const data= await new Promise((resolve, reject) => {
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
return data;
}
export default imageToBase64;

Angular 2 - Image to base64 [duplicate]

I need to convert my image to a Base64 string so that I can send my image to a server.
Is there any JavaScript file for this? Else, how can I convert it?
There are multiple approaches you can choose from:
1. Approach: FileReader
Load the image as blob via XMLHttpRequest and use the FileReader API (readAsDataURL()) to convert it to a dataURL:
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0', function(dataUrl) {
console.log('RESULT:', dataUrl)
})
This code example could also be implemented using the WHATWG fetch API:
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}))
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0')
.then(dataUrl => {
console.log('RESULT:', dataUrl)
})
These approaches:
have better compression
work for other file types as well
Browser Support:
http://caniuse.com/#feat=filereader
http://caniuse.com/#feat=fetch
2. Approach: Canvas (for legacy browsers)
Load the image into an Image-Object, paint it to a nontainted canvas and convert the canvas back to a dataURL.
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
toDataURL(
'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
function(dataUrl) {
console.log('RESULT:', dataUrl)
}
)
In detail
Supported input formats:
image/png, image/jpeg, image/jpg, image/gif, image/bmp, image/tiff, image/x-icon, image/svg+xml, image/webp, image/xxx
Supported output formats:
image/png, image/jpeg, image/webp(chrome)
Browser Support:
http://caniuse.com/#feat=canvas
Internet Explorer 10 (Internet Explorer 10 just works with same origin images)
3. Approach: Images from the local file system
If you want to convert images from the users file system you need to take a different approach.
Use the FileReader API:
function encodeImageFileAsURL(element) {
var file = element.files[0];
var reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
<input type="file" onchange="encodeImageFileAsURL(this)" />
You can use the HTML5 <canvas> for it:
Create a canvas, load your image into it and then use toDataURL() to get the Base64 representation (actually, it's a data: URL, but it contains the Base64-encoded image).
This snippet can convert your string, image and even video file to Base64 string data.
<input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" />
<div id="imgTest"></div>
<script type='text/javascript'>
function encodeImageFileAsURL() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: base64
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("imgTest").innerHTML = newImage.outerHTML;
alert("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
console.log("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
}
fileReader.readAsDataURL(fileToLoad);
}
}
</script>
Basically, if your image is
<img id='Img1' src='someurl'>
then you can convert it like
var c = document.createElement('canvas');
var img = document.getElementById('Img1');
c.height = img.naturalHeight;
c.width = img.naturalWidth;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL();
Here is what I did:
// Author James Harrington 2014
function base64(file, callback){
var coolFile = {};
function readerOnload(e){
var base64 = btoa(e.target.result);
coolFile.base64 = base64;
callback(coolFile)
};
var reader = new FileReader();
reader.onload = readerOnload;
var file = file[0].files[0];
coolFile.filetype = file.type;
coolFile.size = file.size;
coolFile.filename = file.name;
reader.readAsBinaryString(file);
}
And here is how you use it
base64( $('input[type="file"]'), function(data){
console.log(data.base64)
})
I found that the safest and reliable way to do it is to use FileReader().
Demo: Image to Base64
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
var selectedfile = document.getElementById("myinput").files;
if (selectedfile.length > 0) {
var imageFile = selectedfile[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result;
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("dummy").innerHTML = newImage.outerHTML;
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
UPDATE - THE SAME CODE WITH COMMENTS FOR #AnniekJ REQUEST:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
// Get the file objects that was selected by the user from myinput - a file picker control
var selectedfile = document.getElementById("myinput").files;
// Check that the user actually selected file/s from the "file picker" control
// Note - selectedfile is an array, hence we check it`s length, when length of the array
// is bigger than 0 than it means the array containes file objects
if (selectedfile.length > 0) {
// Set the first file object inside the array to this variable
// Note: if multiple files are selected we can itterate on all of the selectedfile array using a for loop - BUT in order to not make this example complicated we only take the first file object that was selected
var imageFile = selectedfile[0];
// Set a filereader object to asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.
var fileReader = new FileReader();
// We declare an event of the fileReader class (onload event) and we register an anonimous function that will be executed when the event is raised. it is "trick" we preapare in order for the onload event to be raised after the last line of this code will be executed (fileReader.readAsDataURL(imageFile);) - please read about events in javascript if you are not familiar with "Events"
fileReader.onload = function(fileLoadedEvent) {
// AT THIS STAGE THE EVENT WAS RAISED
// Here we are getting the file contents - basiccaly the base64 mapping
var srcData = fileLoadedEvent.target.result;
// We create an image html element dinamically in order to display the image
var newImage = document.createElement('img');
// We set the source of the image we created
newImage.src = srcData;
// ANOTHER TRICK TO EXTRACT THE BASE64 STRING
// We set the outer html of the new image to the div element
document.getElementById("dummy").innerHTML = newImage.outerHTML;
// Then we take the inner html of the div and we have the base64 string
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
// This line will raise the fileReader.onload event - note we are passing the file object here as an argument to the function of the event
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
If you have a file object, this simple function will work:
function getBase64 (file, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(file);
}
Usage example:
getBase64(fileObjectFromInput, function(base64Data){
console.log("Base64 of file is", base64Data); // Here you can have your code which uses Base64 for its operation, // file to Base64 by oneshubh
});
I ended up using a function that returns a Promise.
const getImg64 = async() => {
const convertImgToBase64URL = (url) => {
console.log(url)
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = () => {
let canvas = document.createElement('CANVAS')
const ctx = canvas.getContext('2d')
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL();
canvas = null;
resolve(dataURL)
}
img.src = url;
})
}
//for the demonstration purposes I used proxy server to avoid cross origin error
const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
const image = await convertImgToBase64URL(proxyUrl+'https://image.shutterstock.com/image-vector/vector-line-icon-hello-wave-260nw-1521867944.jpg')
console.log(image)
}
getImg64()
You can use this approach in any async function. Then you can just await for the converted image and continue with instructions.
uploadProfile(e) {
let file = e.target.files[0];
let reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
Here is the way you can do with Javascript Promise.
const getBase64 = (file) => new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject('Error: ', error);
})
Now, use it in event handler.
const _changeImg = (e) => {
const file = e.target.files[0];
let encoded;
getBase64(file)
.then((result) => {
encoded = result;
})
.catch(e => console.log(e))
}
You could use FileAPI, but it's pretty much unsupported.
As far as I know, an image can be converted into a Base64 string either by FileReader() or storing it in the canvas element and then use toDataURL() to get the image. I had the similar kind of problem you can refer this.
Convert an image to canvas that is already loaded
Try this code:
For a file upload change event, call this function:
$("#fileproof").on('change', function () {
readImage($(this)).done(function (base64Data) { $('#<%=hfimgbs64.ClientID%>').val(base64Data); });
});
function readImage(inputElement) {
var deferred = $.Deferred();
var files = inputElement.get(0).files;
if (files && files[0]) {
var fr = new FileReader();
fr.onload = function (e) {
deferred.resolve(e.target.result);
};
fr.readAsDataURL(files[0]);
} else {
deferred.resolve(undefined);
}
return deferred.promise();
}
Store Base64 data in hidden filed to use.
document.querySelector('input').onchange = e => {
const fr = new FileReader()
fr.onloadend = () => document.write(fr.result)
fr.readAsDataURL(e.target.files[0])
}
<input type="file">
Needed to leverage reader to convert blob to base64, prefer to use async-await syntax so I chose to extract reader logic into helper like this:
//* Convert resBlob to base64
export const blobToData = (blob: Blob) => {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
and calling it using await in main code:
//* Convert resBlob to dataUrl and resolve
const resData = await blobToData(resBlob)
In the case you are facing cors origin error, there is a simple proxy called cors-fix that loads the image on server and return it as buffer array.
Therefore, we can use fetch to get the image data and filereader to convert it to dataUrl, as described by #HaNdTriX.
function toDataUrl(url) {
fetch(`https://cors-fix.web.app/v1?url=${url}`)
.then(data => data.blob().then(blob => {
const reader = new FileReader();
reader.onloadend = () => {
console.log(reader.result);
};
reader.onerror = () => {
console.log('reader error');
};
reader.readAsDataURL(blob);
}));
}
Well, if you are using Dojo Toolkit, it gives us a direct way to encode or decode into Base64.
Try this:
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a Base64-encoded string:
var bytes = dojox.encoding.base64.decode(str);
You can also simply extract base-64 only part of the URL by ding this:
var Base64URL = canvas.toDataURL('image/webp')
var Base64 = Base64URL.split(",")[1] //Returns the base64 part
Assuming that you are doing this in a browser:
With await:
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' });
return window.URL.createObjectURL(response.data);
With promise
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' })
.then((response) => {
const dataUrl = window.URL.createObjectURL(response.data);
// do something with your url
});
This is very simple.
1> Just call the function and pass your image.
2> Save the return value and use wherever required.
//call like this
const convertedFile = await imageToBase64(fileObj);
console.log("convertedFile",convertedFile);
//this is the required function
async function imageToBase64(image) {
const reader = new FileReader();
reader.readAsDataURL(image);
const data= await new Promise((resolve, reject) => {
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
return data;
}
export default imageToBase64;

How to resize image without losing EXIF data? [duplicate]

How can I resize an image (using an HTML5 canvas element) and keep the EXIF information from the original image? I can extract EXIF info from from original image but I don't know how to copy it to the resized image.
This is how I retrieve the resized image data to send to the server-side code:
canvas.toDataURL("image/jpeg", 0.7);
For EXIF retrieval, I'm using the exif.js library.
Working solution: ExifRestorer.js
Usage with HTML5 image resize:
function dataURItoBlob(dataURI)
{
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
And main code, taken as part of HTML5 resizer from this page: https://github.com/josefrichter/resize/blob/master/public/preprocess.js (but slightly modified)
var reader = new FileReader();
//reader.readAsArrayBuffer(file); //load data ... old version
reader.readAsDataURL(file); //load data ... new version
reader.onload = function (event) {
// blob stuff
//var blob = new Blob([event.target.result]); // create blob... old version
var blob = dataURItoBlob(event.target.result); // create blob...new version
window.URL = window.URL || window.webkitURL;
var blobURL = window.URL.createObjectURL(blob); // and get it's URL
// helper Image object
var image = new Image();
image.src = blobURL;
image.onload = function() {
// have to wait till it's loaded
var resized = ResizeImage(image); // send it to canvas
resized = ExifRestorer.restore(event.target.result, resized); //<= EXIF
var newinput = document.createElement("input");
newinput.type = 'hidden';
newinput.name = 'html5_images[]';
newinput.value = resized; // put result from canvas into new hidden input
form.appendChild(newinput);
};
};
You can use copyExif.js.
This module is more efficient than Martin's solution and uses only Blob and ArrayBuffer without Base64 encoder/decoder.
Besides, there is no need to use exif.js if you only want to keep EXIF. Just copy the entire APP1 marker from the original JPEG to the destination canvas blob and it would just work. It is also how copyExif.js does.
Usage
demo: https://codepen.io/tonytonyjan/project/editor/XEkOkv
<input type="file" id="file" accept="image/jpeg" />
import copyExif from "./copyExif.js";
document.getElementById("file").onchange = async ({ target: { files } }) => {
const file = files[0],
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
ctx.drawImage(await blobToImage(file), 0, 0, canvas.width, canvas.height);
canvas.toBlob(
async blob =>
document.body.appendChild(await blobToImage(await copyExif(file, blob))),
"image/jpeg"
);
};
const blobToImage = blob => {
return new Promise(resolve => {
const reader = new FileReader(),
image = new Image();
image.onload = () => resolve(image);
reader.onload = ({ target: { result: dataURL } }) => (image.src = dataURL);
reader.readAsDataURL(blob);
});
};
It looks my code is used in 'ExifRestorer.js'...
I've try resizing image by canvas. And I felt that resized image is bad quality. If you felt so, too, try my code. My code resizes JPEG by bilinear interpolation. Of course it doesn't lose exif.
https://github.com/hMatoba/JavaScript-MinifyJpegAsync
function post(data) {
var req = new XMLHttpRequest();
req.open("POST", "/jpeg", false);
req.setRequestHeader('Content-Type', 'image/jpeg');
req.send(data.buffer);
}
function handleFileSelect(evt) {
var files = evt.target.files;
for (var i = 0, f; f = files[i]; i++){
var reader = new FileReader();
reader.onloadend = function(e){
MinifyJpegAsync.minify(e.target.result, 1280, post);
};
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
Canvas generates images with 20 bytes header (before jpeg data segments start). You can slice head with exif segments from original file and replace first 20 bytes in resized one.

JavaScript/jQuery - Convert Image to Base64 [duplicate]

I need to convert my image to a Base64 string so that I can send my image to a server.
Is there any JavaScript file for this? Else, how can I convert it?
There are multiple approaches you can choose from:
1. Approach: FileReader
Load the image as blob via XMLHttpRequest and use the FileReader API (readAsDataURL()) to convert it to a dataURL:
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0', function(dataUrl) {
console.log('RESULT:', dataUrl)
})
This code example could also be implemented using the WHATWG fetch API:
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}))
toDataURL('https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0')
.then(dataUrl => {
console.log('RESULT:', dataUrl)
})
These approaches:
have better compression
work for other file types as well
Browser Support:
http://caniuse.com/#feat=filereader
http://caniuse.com/#feat=fetch
2. Approach: Canvas (for legacy browsers)
Load the image into an Image-Object, paint it to a nontainted canvas and convert the canvas back to a dataURL.
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
toDataURL(
'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
function(dataUrl) {
console.log('RESULT:', dataUrl)
}
)
In detail
Supported input formats:
image/png, image/jpeg, image/jpg, image/gif, image/bmp, image/tiff, image/x-icon, image/svg+xml, image/webp, image/xxx
Supported output formats:
image/png, image/jpeg, image/webp(chrome)
Browser Support:
http://caniuse.com/#feat=canvas
Internet Explorer 10 (Internet Explorer 10 just works with same origin images)
3. Approach: Images from the local file system
If you want to convert images from the users file system you need to take a different approach.
Use the FileReader API:
function encodeImageFileAsURL(element) {
var file = element.files[0];
var reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
<input type="file" onchange="encodeImageFileAsURL(this)" />
You can use the HTML5 <canvas> for it:
Create a canvas, load your image into it and then use toDataURL() to get the Base64 representation (actually, it's a data: URL, but it contains the Base64-encoded image).
This snippet can convert your string, image and even video file to Base64 string data.
<input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" />
<div id="imgTest"></div>
<script type='text/javascript'>
function encodeImageFileAsURL() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: base64
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("imgTest").innerHTML = newImage.outerHTML;
alert("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
console.log("Converted Base64 version is " + document.getElementById("imgTest").innerHTML);
}
fileReader.readAsDataURL(fileToLoad);
}
}
</script>
Basically, if your image is
<img id='Img1' src='someurl'>
then you can convert it like
var c = document.createElement('canvas');
var img = document.getElementById('Img1');
c.height = img.naturalHeight;
c.width = img.naturalWidth;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, c.width, c.height);
var base64String = c.toDataURL();
Here is what I did:
// Author James Harrington 2014
function base64(file, callback){
var coolFile = {};
function readerOnload(e){
var base64 = btoa(e.target.result);
coolFile.base64 = base64;
callback(coolFile)
};
var reader = new FileReader();
reader.onload = readerOnload;
var file = file[0].files[0];
coolFile.filetype = file.type;
coolFile.size = file.size;
coolFile.filename = file.name;
reader.readAsBinaryString(file);
}
And here is how you use it
base64( $('input[type="file"]'), function(data){
console.log(data.base64)
})
I found that the safest and reliable way to do it is to use FileReader().
Demo: Image to Base64
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
var selectedfile = document.getElementById("myinput").files;
if (selectedfile.length > 0) {
var imageFile = selectedfile[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result;
var newImage = document.createElement('img');
newImage.src = srcData;
document.getElementById("dummy").innerHTML = newImage.outerHTML;
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
UPDATE - THE SAME CODE WITH COMMENTS FOR #AnniekJ REQUEST:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input id="myinput" type="file" onchange="encode();" />
<div id="dummy">
</div>
<div>
<textarea style="width:100%;height:500px;" id="txt">
</textarea>
</div>
<script>
function encode() {
// Get the file objects that was selected by the user from myinput - a file picker control
var selectedfile = document.getElementById("myinput").files;
// Check that the user actually selected file/s from the "file picker" control
// Note - selectedfile is an array, hence we check it`s length, when length of the array
// is bigger than 0 than it means the array containes file objects
if (selectedfile.length > 0) {
// Set the first file object inside the array to this variable
// Note: if multiple files are selected we can itterate on all of the selectedfile array using a for loop - BUT in order to not make this example complicated we only take the first file object that was selected
var imageFile = selectedfile[0];
// Set a filereader object to asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.
var fileReader = new FileReader();
// We declare an event of the fileReader class (onload event) and we register an anonimous function that will be executed when the event is raised. it is "trick" we preapare in order for the onload event to be raised after the last line of this code will be executed (fileReader.readAsDataURL(imageFile);) - please read about events in javascript if you are not familiar with "Events"
fileReader.onload = function(fileLoadedEvent) {
// AT THIS STAGE THE EVENT WAS RAISED
// Here we are getting the file contents - basiccaly the base64 mapping
var srcData = fileLoadedEvent.target.result;
// We create an image html element dinamically in order to display the image
var newImage = document.createElement('img');
// We set the source of the image we created
newImage.src = srcData;
// ANOTHER TRICK TO EXTRACT THE BASE64 STRING
// We set the outer html of the new image to the div element
document.getElementById("dummy").innerHTML = newImage.outerHTML;
// Then we take the inner html of the div and we have the base64 string
document.getElementById("txt").value = document.getElementById("dummy").innerHTML;
}
// This line will raise the fileReader.onload event - note we are passing the file object here as an argument to the function of the event
fileReader.readAsDataURL(imageFile);
}
}
</script>
</body>
</html>
If you have a file object, this simple function will work:
function getBase64 (file, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(file);
}
Usage example:
getBase64(fileObjectFromInput, function(base64Data){
console.log("Base64 of file is", base64Data); // Here you can have your code which uses Base64 for its operation, // file to Base64 by oneshubh
});
I ended up using a function that returns a Promise.
const getImg64 = async() => {
const convertImgToBase64URL = (url) => {
console.log(url)
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = () => {
let canvas = document.createElement('CANVAS')
const ctx = canvas.getContext('2d')
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL();
canvas = null;
resolve(dataURL)
}
img.src = url;
})
}
//for the demonstration purposes I used proxy server to avoid cross origin error
const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
const image = await convertImgToBase64URL(proxyUrl+'https://image.shutterstock.com/image-vector/vector-line-icon-hello-wave-260nw-1521867944.jpg')
console.log(image)
}
getImg64()
You can use this approach in any async function. Then you can just await for the converted image and continue with instructions.
uploadProfile(e) {
let file = e.target.files[0];
let reader = new FileReader();
reader.onloadend = function() {
console.log('RESULT', reader.result)
}
reader.readAsDataURL(file);
}
Here is the way you can do with Javascript Promise.
const getBase64 = (file) => new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject('Error: ', error);
})
Now, use it in event handler.
const _changeImg = (e) => {
const file = e.target.files[0];
let encoded;
getBase64(file)
.then((result) => {
encoded = result;
})
.catch(e => console.log(e))
}
You could use FileAPI, but it's pretty much unsupported.
As far as I know, an image can be converted into a Base64 string either by FileReader() or storing it in the canvas element and then use toDataURL() to get the image. I had the similar kind of problem you can refer this.
Convert an image to canvas that is already loaded
Try this code:
For a file upload change event, call this function:
$("#fileproof").on('change', function () {
readImage($(this)).done(function (base64Data) { $('#<%=hfimgbs64.ClientID%>').val(base64Data); });
});
function readImage(inputElement) {
var deferred = $.Deferred();
var files = inputElement.get(0).files;
if (files && files[0]) {
var fr = new FileReader();
fr.onload = function (e) {
deferred.resolve(e.target.result);
};
fr.readAsDataURL(files[0]);
} else {
deferred.resolve(undefined);
}
return deferred.promise();
}
Store Base64 data in hidden filed to use.
document.querySelector('input').onchange = e => {
const fr = new FileReader()
fr.onloadend = () => document.write(fr.result)
fr.readAsDataURL(e.target.files[0])
}
<input type="file">
Needed to leverage reader to convert blob to base64, prefer to use async-await syntax so I chose to extract reader logic into helper like this:
//* Convert resBlob to base64
export const blobToData = (blob: Blob) => {
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
and calling it using await in main code:
//* Convert resBlob to dataUrl and resolve
const resData = await blobToData(resBlob)
In the case you are facing cors origin error, there is a simple proxy called cors-fix that loads the image on server and return it as buffer array.
Therefore, we can use fetch to get the image data and filereader to convert it to dataUrl, as described by #HaNdTriX.
function toDataUrl(url) {
fetch(`https://cors-fix.web.app/v1?url=${url}`)
.then(data => data.blob().then(blob => {
const reader = new FileReader();
reader.onloadend = () => {
console.log(reader.result);
};
reader.onerror = () => {
console.log('reader error');
};
reader.readAsDataURL(blob);
}));
}
Well, if you are using Dojo Toolkit, it gives us a direct way to encode or decode into Base64.
Try this:
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a Base64-encoded string:
var bytes = dojox.encoding.base64.decode(str);
You can also simply extract base-64 only part of the URL by ding this:
var Base64URL = canvas.toDataURL('image/webp')
var Base64 = Base64URL.split(",")[1] //Returns the base64 part
Assuming that you are doing this in a browser:
With await:
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' });
return window.URL.createObjectURL(response.data);
With promise
import axios from 'axios'
const response = await axios.get(url, { responseType: 'blob' })
.then((response) => {
const dataUrl = window.URL.createObjectURL(response.data);
// do something with your url
});
This is very simple.
1> Just call the function and pass your image.
2> Save the return value and use wherever required.
//call like this
const convertedFile = await imageToBase64(fileObj);
console.log("convertedFile",convertedFile);
//this is the required function
async function imageToBase64(image) {
const reader = new FileReader();
reader.readAsDataURL(image);
const data= await new Promise((resolve, reject) => {
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
return data;
}
export default imageToBase64;

Categories