251

I need to upload an image to NodeJS server to some directory. I am using connect-busboy node module for that.

I had the dataURL of the image that I converted to blob using the following code:

dataURLToBlob: function(dataURL) {
    var BASE64_MARKER = ';base64,';
    if (dataURL.indexOf(BASE64_MARKER) == -1) {
        var parts = dataURL.split(',');
        var contentType = parts[0].split(':')[1];
        var raw = decodeURIComponent(parts[1]);
        return new Blob([raw], {type: contentType});
    }
    var parts = dataURL.split(BASE64_MARKER);
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;
    var uInt8Array = new Uint8Array(rawLength);
    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }
    return new Blob([uInt8Array], {type: contentType});
}

I need a way to convert the blob to a file to upload the image.

Could somebody help me with it?

Evgenia Karunus
  • 10,715
  • 5
  • 56
  • 70
skip
  • 12,193
  • 32
  • 113
  • 153
  • 4
    Files are Blobs, just tack on the meta properties and you're good to go. – dandavis Nov 26 '14 at 21:59
  • 1
    The default for a blob when uploading it is `blob`. So, I first extracted the name of the file I was cropping and then gave the same `filename` so the cropped file while uploading it to server by doing `form.append("blob",blob, filename);`. – skip Nov 26 '14 at 23:21
  • @skip did my answer below help out? Is so, please mark it as the correct answer. – Chris Barr May 14 '15 at 14:22

9 Answers9

402

You can use the File constructor:

var file = new File([myBlob], "name");

As per the w3 specification this will append the bytes that the blob contains to the bytes for the new File object, and create the file with the specified name http://www.w3.org/TR/FileAPI/#dfn-file

Rikard
  • 3,828
  • 1
  • 24
  • 39
Joshua P Nixon
  • 4,137
  • 1
  • 12
  • 3
  • 2
    This is what I was looking for, the one difference is the first argument is actually an array so I used it as: var file = new File([myBlob], "name"); – Michaeldcooney Oct 28 '15 at 22:30
  • 2
    Yes. I am looking for this solution too. Stamplay server can not get the file name from blob object. So I need to convert it back to file. But Safari do not support file API... back to 0 now :( – Hugh Hou Jan 25 '16 at 16:14
  • Exactly what I was looking for. Thanks for this. Other solutions keep the file name to be 'bolb' whatever I changes it to, but your solution is keeping my file name. – Mohy Eldeen Mar 14 '16 at 21:46
  • 4
    File constructors do not work e.g. in PhantomJS: `TypeError: FileConstructor is not a constructor (evaluating 'new File([''], 'file.pdf', {'size': 1000, 'type': 'application/pdf'})')` – bkimminich Oct 04 '16 at 14:28
  • 8
    Edge has currently (2017-10-04) a bug that prevents the usage of this constructor. https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9551546/ – Rik Martins Oct 04 '17 at 14:31
  • 33
    Be sure to add file type, otherwise it will not work properly. new File([myBlob], "name", { type: "image/jpeg", }); – BernardA Aug 07 '18 at 16:03
  • this is throwing ` ReferenceError: File is not defined` for me – fIwJlxSzApHEZIl Nov 16 '18 at 23:18
  • dumb way `fd = new FormData; fd.append('f', new Blob, "name"), fd.get('f')` :) – Endless Feb 02 '20 at 10:15
  • IE11 is not supporting new File() constructor, is there any alternative to convert a blob to File type ? assigning a filename and lastdateModified to blob is not working. – Vamsi Jul 21 '21 at 15:52
  • You can add image name using timestamp like this. var file = new File([blobImage], `${Date.now()}.png`); – Muzammal Hussain Jun 14 '22 at 17:18
215

This function converts a Blob into a File and it works great for me.

Vanilla JavaScript

function blobToFile(theBlob, fileName){
  //A Blob() is almost a File() - it's just missing the two properties below which we will add
  theBlob.lastModifiedDate = new Date();
  theBlob.name = fileName;
  return theBlob;
}

TypeScript (with proper typings)

public blobToFile = (theBlob: Blob, fileName:string): File => {
  const b: any = theBlob;
  //A Blob() is almost a File() - it's just missing the two properties below which we will add
  b.lastModifiedDate = new Date();
  b.name = fileName;
    
  //Cast to a File() type
  return theBlob as File;
}

Usage

const myBlob = new Blob();

//do stuff here to give the blob some data...

const myFile = blobToFile(myBlob, "my-image.png");
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
  • 3
    I think the cast should happen first so you don't need to use `any` in TypeScript. See [this](http://www.typescriptlang.org/play/#src=function%20blobToFile(theBlob%3A%20Blob%2C%20fileName%3A%20string)%3A%20File%20%7B%0A%09%2F%2FA%20Blob%20is%20almost%20a%20File%20-%20it's%20just%20missing%20the%20two%20properties%20below%0A%20%20%20%20var%20f%20%3D%20%3CFile%3EtheBlob%3B%0A%20%20%20%20f.lastModifiedDate%20%3D%20new%20Date()%3B%0A%20%20%20%20f.name%20%3D%20fileName%3B%0A%0A%20%20%20%20return%20f%3B%0A%7D) example. – styfle Apr 13 '16 at 18:53
  • 3
    This does not work for all purposes. Adding this "File" to an ajax call will not set the filename correctly. – Jacob Poul Richardt Aug 15 '16 at 12:29
  • 56
    This is not a good solution, the produced object still a blob. – czupe Nov 30 '17 at 17:07
  • @czupe It's been a while now, but if I recall correctly a file is a type of blob, so this should work – Chris Barr Nov 30 '17 at 17:08
  • 1
    Hey Chris, I did not want to be offended you. Just wanted point out the the object type will be Blob and not File :(. Maybe I just needed something else. – czupe Dec 07 '17 at 14:47
  • 4
    Just add `b.__proto__ = File.prototype`, and your solution becomes a dream that even tricks `b instanceOf File` to `true` – manuelnaranjo Mar 04 '18 at 22:01
  • Please note that `lastModifiedDate` is deprecated ( https://developer.mozilla.org/en-US/docs/Web/API/File/lastModifiedDate ), you should now use `lastModified`, setting `lastModified` throws an error in Firefox if the blob accidentally happens to be an instance of File already. – Rik Jul 08 '18 at 12:28
  • this throws error Cannot assign to read only property 'name' of object '[object File]' – Vugar Abdullayev Dec 22 '18 at 14:01
  • 7
    This should not be the accepted answer, https://stackoverflow.com/a/53205768/2557517 or https://stackoverflow.com/a/31663645/2557517 should be. – Kira May 24 '19 at 05:19
  • Thanks a lot for this. new File() does not work straightforward on Cordova. Didn't realize that a file was just a type of blob if it weren't for this answer. – Muz Nov 15 '19 at 04:15
  • 1
    @JacobPoulRichardt You're correct, but this can can be fixed by adding the file name to the formdata like this: formData.append("file", yourFileObj, yourFileObj.name); – Tim Gerhard Dec 24 '19 at 08:50
68

Joshua P Nixon's answer is correct but I had to set last modified date also. so here is the code.

var file = new File([blob], "file_name", {lastModified: 1534584790000});

1534584790000 is an unix timestamp for "GMT: Saturday, August 18, 2018 9:33:10 AM"

mili
  • 3,502
  • 1
  • 29
  • 29
  • 4
    Points for not breaking `instanceof` like the accepted answer – Matt Jensen May 15 '19 at 16:43
  • 2
    side note, if anyone is doing this and doesn't want to hard code that it was last modified in august 2018, you can always put `lastModified: Date.now()` and that'll return the current time in milliseconds! (just like how the example given is august 18 2018 at 9:33:10 in milliseconds) – Raphael Morgan Aug 11 '21 at 00:41
38

Typescript

public blobToFile = (theBlob: Blob, fileName:string): File => {       
    return new File(
        [theBlob as any], // cast as any
        fileName, 
        {
            lastModified: new Date().getTime(),
            type: theBlob.type 
        }
    )
}

Javascript

function blobToFile(theBlob, fileName){       
    return new File([theBlob], fileName, { lastModified: new Date().getTime(), type: theBlob.type })
}

Output

screenshot

File {name: "fileName", lastModified: 1597081051454, lastModifiedDate: Mon Aug 10 2020 19:37:31 GMT+0200 (Eastern European Standard Time), webkitRelativePath: "", size: 601887, …}
lastModified: 1597081051454
lastModifiedDate: Mon Aug 10 2020 19:37:31 GMT+0200 (Eastern European Standard Time) {}
name: "fileName"
size: 601887
type: "image/png"
webkitRelativePath: ""
__proto__: File
Ngatia Frankline
  • 2,897
  • 2
  • 20
  • 19
29

For me to work I had to explicitly provide the type although it is contained in the blob by doing so:

const file = new File([blob], 'untitled', { type: blob.type })
Alexandre Daubricourt
  • 3,323
  • 1
  • 34
  • 33
21

My modern variant:

function blob2file(blobData) {
  const fd = new FormData();
  fd.set('a', blobData, 'filename');
  return fd.get('a');
}
DAVID _
  • 617
  • 1
  • 7
  • 16
5
var blob = new Blob(["Hello, world!"], { type: "text/plain;charset=utf-8" });

var file = new File([blob], "name.txt");

Now you can upload as .txt file

Ronald Babu
  • 166
  • 1
  • 7
1

This problem was bugging me for hours. I was using Nextjs and trying to convert canvas to an image file.

I used the other guy's solution but the created file was empty.

So if this is your problem you should mention the size property in the file object.

new File([Blob], `my_image${new Date()}.jpeg`, {
  type: "image/jpeg",
  lastModified: new Date(),
  size: 2,
});

Just add the key the value it's not important.

S.Saderi
  • 4,755
  • 3
  • 21
  • 23
-4

I have used FileSaver.js to save the blob as file.

This is the repo : https://github.com/eligrey/FileSaver.js/

Usage:

import { saveAs } from 'file-saver';

var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
saveAs(blob, "hello world.txt");

saveAs("https://httpbin.org/image", "image.jpg");
mylnz
  • 354
  • 1
  • 5