310

UPD TypeScript version is also available in answers

Now I'm getting File object by this line:

file = document.querySelector('#files > input[type="file"]').files[0]

I need to send this file via json in base 64. What should I do to convert it to base64 string?

Vassily
  • 4,677
  • 4
  • 30
  • 59

11 Answers11

386

Try the solution using the FileReader class:

function getBase64(file) {
   var reader = new FileReader();
   reader.readAsDataURL(file);
   reader.onload = function () {
     console.log(reader.result);
   };
   reader.onerror = function (error) {
     console.log('Error: ', error);
   };
}

var file = document.querySelector('#files > input[type="file"]').files[0];
getBase64(file); // prints the base64 string

Notice that .files[0] is a File type, which is a sublcass of Blob. Thus it can be used with FileReader.
See the complete working example.

Dmitri Pavlutin
  • 16,530
  • 7
  • 35
  • 38
  • 2
    read more about FileReader API: https://developer.mozilla.org/en-US/docs/Web/API/FileReader and browser support: http://caniuse.com/#feat=filereader – Lukas Liesis Jun 09 '17 at 19:16
  • 13
    I tried to use `return reader.result` from the `getBase64()` function (rather than using `console.log(reader.result)`) because i want to capture the base64 as a variable (and then send it to Google Apps Script). I called the function with: `var my_file_as_base64 = getBase64(file)` and then tried to print to console with `console.log(my_file_as_base64 )` and just got `undefined`. How can I properly assign the base64 to a variable? – user1063287 Nov 09 '17 at 05:35
  • 2
    I made a question out of the above comment if anyone can answer. https://stackoverflow.com/questions/47195119/how-to-capture-filereader-base64-as-variable – user1063287 Nov 10 '17 at 05:21
  • I need to open this Base64 file in browser with the same file name, i am opening it using window.open(url, '_blank') which is working fine, how can i give file name to that ? please help. – Munish Sharma Apr 26 '18 at 08:14
  • Thanks! I think this is not explained very well on https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL – johey May 12 '20 at 15:11
320

Modern ES6 way (async/await)

const toBase64 = file => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
});

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   console.log(await toBase64(file));
}

Main();

UPD:

If you want to catch errors

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   try {
      const result = await toBase64(file);
      return result
   } catch(error) {
      console.error(error);
      return;
   }
   //...
}
ofhouse
  • 2,351
  • 31
  • 38
  • 15
    This code is incorrect. If you `await` a function that returns a rejected Promise, you won't get an Error returned by the call; it will be thrown and you will need to catch it. – Dancrumb Feb 20 '20 at 00:30
  • 1
    Great example of use of the async functions and promises – Thiago Frias Apr 30 '20 at 03:52
  • 4
    I actually tried this snippet trying to convert a image on a and got an error. : Users.js:41 Uncaught (in promise) TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'. – nishi Sep 13 '20 at 03:56
153

If you're after a promise-based solution, this is @Dmitri's code adapted for that:

function getBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
  });
}

var file = document.querySelector('#files > input[type="file"]').files[0];
getBase64(file).then(
  data => console.log(data)
);
Chong Lip Phang
  • 7,739
  • 5
  • 56
  • 83
joshua.paling
  • 13,357
  • 4
  • 43
  • 59
  • I need to open this Base64 file in browser with the same file name, i am opening it using window.open(url, '_blank') which is working fine, how can i give file name to that ? please help. – Munish Sharma Apr 26 '18 at 08:16
83

Building up on Dmitri Pavlutin and joshua.paling answers, here's an extended version that extracts the base64 content (removes the metadata at the beginning) and also ensures padding is done correctly.

function getBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      let encoded = reader.result.toString().replace(/^data:(.*,)?/, '');
      if ((encoded.length % 4) > 0) {
        encoded += '='.repeat(4 - (encoded.length % 4));
      }
      resolve(encoded);
    };
    reader.onerror = error => reject(error);
  });
}
Arnaud P
  • 10,957
  • 6
  • 55
  • 64
  • 2
    Chrome 69, the first replace is to catch empty file, second replace is missing comma - encoded = reader.result.replace("data:", "").replace(/^.*;base64,/, ""); – user3333134 Sep 27 '18 at 13:37
  • My word, I did miss that coma indeed. What is incredible is that it didn't seem to bother my backend at all, I was still able to upload excel files successfully o_O. I've fixed the regex to take your empty file use case into account as well. Thanks. – Arnaud P Oct 11 '18 at 08:42
  • 4
    I've got an even easier version : `resolve(reader.result.replace(/^.*,/, ''));`. Since coma `,` is outside base64 alphabet we can strip anything that comes up until and including the coma. https://stackoverflow.com/a/13195218/1935128 – Johnride Jul 28 '19 at 13:01
  • Ok thanks for the heads up, although according to the regex I wrote here (I'd need to experiment again to be sure), there may just be `data:`, without any comma, so I'll keep that first part as is. I've updated the answer accordingly. – Arnaud P Aug 02 '19 at 22:09
  • 1
    @ArnaudP Typescript error: Property 'replace' does not exist on type 'string | ArrayBuffer'. – Romel Gomez Aug 22 '19 at 16:05
  • @RomelGomez yes this code is `js` so there is no compiler to bother you about types. In my `ts` code however, I did add `.toString()` before `.replace(...)`. Not sure it is actually necessary, but I'll update my answer just in case. Thx. – Arnaud P Aug 23 '19 at 14:27
  • this saved me tons of trouble thank you so much – Nyuu Apr 28 '22 at 22:48
14

JavaScript btoa() function can be used to convert data into base64 encoded string

<div>
    <div>
        <label for="filePicker">Choose or drag a file:</label><br>
        <input type="file" id="filePicker">
    </div>
    <br>
    <div>
        <h1>Base64 encoded version</h1>
        <textarea id="base64textarea" 
                  placeholder="Base64 will appear here" 
                  cols="50" rows="15"></textarea>
    </div>
</div>
var handleFileSelect = function(evt) {
    var files = evt.target.files;
    var file = files[0];

    if (files && file) {
        var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var binaryString = readerEvt.target.result;
            document.getElementById("base64textarea").value = btoa(binaryString);
        };

        reader.readAsBinaryString(file);
    }
};

if (window.File && window.FileReader && window.FileList && window.Blob) {
    document.getElementById('filePicker')
            .addEventListener('change', handleFileSelect, false);
} else {
    alert('The File APIs are not fully supported in this browser.');
}
lepe
  • 23,582
  • 9
  • 92
  • 102
Pranav Maniar
  • 1,525
  • 10
  • 20
13

TypeScript version

const file2Base64 = (file:File):Promise<string> => {
    return new Promise<string> ((resolve,reject)=> {
         const reader = new FileReader();
         reader.readAsDataURL(file);
         reader.onload = () => resolve(reader.result?.toString() || '');
         reader.onerror = error => reject(error);
     })
    }
Cyber Progs
  • 3,240
  • 3
  • 27
  • 36
8

Here are a couple functions I wrote to get a file in a json format which can be passed around easily:

    //takes an array of JavaScript File objects
    function getFiles(files) {
        return Promise.all(files.map(file => getFile(file)));
    }

    //take a single JavaScript File object
    function getFile(file) {
        var reader = new FileReader();
        return new Promise((resolve, reject) => {
            reader.onerror = () => { reader.abort(); reject(new Error("Error parsing file"));}
            reader.onload = function () {

                //This will result in an array that will be recognized by C#.NET WebApi as a byte[]
                let bytes = Array.from(new Uint8Array(this.result));

                //if you want the base64encoded file you would use the below line:
                let base64StringFile = btoa(bytes.map((item) => String.fromCharCode(item)).join(""));

                //Resolve the promise with your custom file structure
                resolve({ 
                    bytes: bytes,
                    base64StringFile: base64StringFile,
                    fileName: file.name, 
                    fileType: file.type
                });
            }
            reader.readAsArrayBuffer(file);
        });
    }

    //using the functions with your file:

    file = document.querySelector('#files > input[type="file"]').files[0]
    getFile(file).then((customJsonFile) => {
         //customJsonFile is your newly constructed file.
         console.log(customJsonFile);
    });

    //if you are in an environment where async/await is supported

    files = document.querySelector('#files > input[type="file"]').files
    let customJsonFiles = await getFiles(files);
    //customJsonFiles is an array of your custom files
    console.log(customJsonFiles);
tkd_aj
  • 843
  • 1
  • 9
  • 14
3
const fileInput = document.querySelector('input');

fileInput.addEventListener('change', (e) => {

// get a reference to the file
const file = e.target.files[0];

// encode the file using the FileReader API
const reader = new FileReader();
reader.onloadend = () => {

    // use a regex to remove data url part
    const base64String = reader.result
        .replace('data:', '')
        .replace(/^.+,/, '');

    // log to console
    // logs wL2dvYWwgbW9yZ...
    console.log(base64String);
};
reader.readAsDataURL(file);});
Om Fuke
  • 253
  • 1
  • 3
  • 10
1
onInputChange(evt) {
    var tgt = evt.target || window.event.srcElement,
    files = tgt.files;
    if (FileReader && files && files.length) {
        var fr = new FileReader();
        fr.onload = function () {
            var base64 = fr.result;
            debugger;
        }
        fr.readAsDataURL(files[0]);
    }
}
1

I have used this simple method and it's worked successfully

 function  uploadImage(e) {
  var file = e.target.files[0];
    let reader = new FileReader();
    reader.onload = (e) => {
    let image = e.target.result;
    console.log(image);
    };
  reader.readAsDataURL(file);
  
}
0

Convert any file to base64 using this way -

_fileToBase64(file: File) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result.toString().substr(reader.result.toString().indexOf(',') + 1));
    reader.onerror = error => reject(error);
  });
}
Gust van de Wal
  • 5,052
  • 1
  • 20
  • 45