I need to convert a dataURL to a File object in Javascript in order to send it over using AJAX. Is it possible? If yes, please tell me how.
-
cwallenpoole, its a big code,everything before it works fine as the images are appended to the body,just tell me what you need and i'll post it here – kapv89 Jul 27 '11 at 19:52
-
What is `formData` in your script/page? – Marc B Jul 27 '11 at 19:52
-
1Since you are using toDataURL it gets the canvas image as a b64 encoded string not a file.Since you are using "POST" that is why it is being stored in $_POST. "but that would be an ugly hack" it's not an ugly hack it's how the file is created. – scrappedcola Jul 27 '11 at 19:54
-
formdata has been initialized as the following in the block which contains these two functions, var formdata = new FormData(); – kapv89 Jul 27 '11 at 19:54
6 Answers
If you need to send it over ajax, then there's no need to use a File
object, only Blob
and FormData
objects are needed.
As I sidenote, why don't you just send the base64 string to the server over ajax and convert it to binary server-side, using PHP's base64_decode
for example? Anyway, the standard-compliant code from this answer works in Chrome 13 and WebKit nightlies:
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
//Old Code
//write the ArrayBuffer to a blob, and you're done
//var bb = new BlobBuilder();
//bb.append(ab);
//return bb.getBlob(mimeString);
//New Code
return new Blob([ab], {type: mimeString});
}
Then just append the blob to a new FormData object and post it to your server using ajax:
var blob = dataURItoBlob(someDataUrl);
var fd = new FormData(document.forms[0]);
var xhr = new XMLHttpRequest();
fd.append("myFile", blob);
xhr.open('POST', '/', true);
xhr.send(fd);
-
1Thanks for your answer, however, I have already made something like that and it works fine. Its a canvas based image resizer, watermarker and uploader. Waiting for a project to use it on – kapv89 Sep 01 '11 at 18:02
-
In Firefox, if there's no form, FormData should be created as: `new FormData();` Otherwise it will throw an exception. – Léon Pelletier Dec 18 '12 at 04:58
-
Why do you have a `callback` argument here? It seems you should remove it. – Scott Morrison Apr 16 '13 at 13:23
-
2Hi, just thought to mention I have a slightly modernized version available at http://www.nixtu.info/2013/06/how-to-upload-canvas-data-to-server.html . – Juho Vepsäläinen Jun 20 '13 at 17:51
-
Thanks for your help @bebraw I have read in your blog that ArrayBuffer is deprecated and it is recommended the use of DataView. It would be nice that you update your code. – ccsakuweb Feb 13 '14 at 11:03
-
@ccsakuweb Yeah. I'll do that in the near future. Thanks for poking. :) – Juho Vepsäläinen Feb 13 '14 at 13:30
-
@ccsakuweb Done. I made it use DataView now. In my tests it yielded same results so I guess it's ok. – Juho Vepsäläinen Feb 20 '14 at 12:26
-
5BlobBuilder is now deprecated and does not work anymore in Chrome ! – Lorenz Meyer May 13 '15 at 17:24
-
1This post uses deprecated elements such as BlobBuilder, see @cuixiping's answer for a working solution. – vish Jun 29 '15 at 05:38
-
2It's worth noting that the base64 encoding of a file is often substantially larger than the actual file, which means a lot more data is transmitted when using base64 as compared to `multipart/form-data`, which is what you get when you use `File`. – Sumit Aug 30 '18 at 17:39
-
1FWIW, the "write the bytes of the string to an ArrayBuffer" step can be `const ab = Uint8Array.from(byteString, ch => ch.charCodeAt(0)).buffer;`. – T.J. Crowder Apr 27 '20 at 09:52
-
I've shared the same experience in my post here https://alfilatov.com/posts/how-to-pass-file-into-an-iframe-and-convert-it-to-blob-for-further-ajax-request/ – Alex Filatov Nov 07 '20 at 04:50
-
-
Can anyone pinpoint what answer is being referenced in the comments? This ID now just references this question, and not an answer. This answer is also copy/pasted several times; none of which removing this now dead reference. – Geoffrey H. Aug 12 '22 at 19:57
-
1
The BlobBuilder is deprecated and should no longer be used. Use Blob instead of old BlobBuilder. The code is very clean and simple.
File object is inherit from Blob object. You can use both of them with FormData object.
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
use dataURLtoBlob() function to convert dataURL to blob and send ajax to server.
for example:
var dataurl = 'data:text/plain;base64,aGVsbG8gd29ybGQ=';
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("file", blob, "hello.txt");
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server.php', true);
xhr.onload = function(){
alert('upload complete');
};
xhr.send(fd);
Another way:
You can also use fetch to convert an url to a file object (file object has name/fileName property, this is different from blob object)
The code is very short and easy to use. (works in Chrome and Firefox)
//load src and convert to a File instance object
//work for any type of src, not only image src.
//return a promise that resolves with a File instance
function srcToFile(src, fileName, mimeType){
return (fetch(src)
.then(function(res){return res.arrayBuffer();})
.then(function(buf){return new File([buf], fileName, {type:mimeType});})
);
}
Usage example 1: Just convert to file object
srcToFile(
'data:text/plain;base64,aGVsbG8gd29ybGQ=',
'hello.txt',
'text/plain'
)
.then(function(file){
console.log(file);
})
Usage example 2: Convert to file object and upload to server
srcToFile(
'data:text/plain;base64,aGVsbG8gd29ybGQ=',
'hello.txt',
'text/plain'
)
.then(function(file){
console.log(file);
var fd = new FormData();
fd.append("file", file);
return fetch('/server.php', {method:'POST', body:fd});
})
.then(function(res){
return res.text();
})
.then(console.log)
.catch(console.error)
;

- 24,167
- 8
- 82
- 93
-
2I really enjoyed your answer as it's neat and clean, but I really can figure out the usage of ArrayBuffer in other answers. Would you please explain the usage if ArrayBuffer and why it's not used here? – Ali Sep 08 '15 at 14:15
-
In case you didn't check out the Mozilla Developer Network reference, fetch is an experimental feature and is not recommended for use in production code. Too bad, looks cool. – jocassid Jul 28 '19 at 01:01
-
To create a blob from a dataURL:
const response = await fetch(dataURL);
const blob = await response.blob();
To create a file from a blob:
const file = new File(
[blob],
"fileName.jpg",
{
type: "image/jpeg",
lastModified: new Date()
}
);
-
6No need for 2 awaits and nesting. `await fetch(src).then(it => it.blob())` – Steven Spungin Nov 04 '21 at 14:20
-
1@StevenSpungin Better yet, break the code onto two explicit lines, as I've done as an edit to the answer. Mixing `await` and `then` often leads to confusion and arguably isn't much better than nesting `await`s. We don't have to write it on one line. – ggorlen May 19 '23 at 22:23
-
You can still put the .then on another line, and it is also arguably better to not create an itermediate variable and const declaration. – Steven Spungin May 20 '23 at 00:03
If you really want to convert the dataURL into File
object.
You need to convert the dataURL into Blob
then convert the Blob
into File
.
The function is from answer by Matthew. (https://stackoverflow.com/a/7261048/13647044)
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
const blob = dataURItoBlob(url);
const resultFile = new File([blob], "file_name");
Other than that, you can have options on the File
Object initialised. Reference to File() constructor.
const resultFile = new File([blob], "file_name",{type:file.type,lastModified:1597081051454});
The type should be [MIME][1]
type(i.e. image/jpeg
) and last modified value in my example is equivalent to Mon Aug 10 2020 19:37:31 GMT+0200 (Eastern European Standard Time)

- 381
- 3
- 6
In Latest browsers:
const dataURLtoBlob = (dataURL) => {
fetch(dataURL)
.then(res => res.blob())
.then(blob => console.log(blob))
.catch(err => console.log(err))
}

- 21
- 1
-
Basically the same as [this answer](https://stackoverflow.com/a/65669404/6243352), except in a confusing function that only logs the blob to the console rather than return it. – ggorlen May 19 '23 at 22:27
After some research I arrived on this one:
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var dw = new DataView(ab);
for(var i = 0; i < byteString.length; i++) {
dw.setUint8(i, byteString.charCodeAt(i));
}
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], {type: mimeString});
}
module.exports = dataURItoBlob;

- 38,062
- 9
- 61
- 69