363

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
  • 5,263
  • 4
  • 33
  • 63

15 Answers15

437

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
  • 18,122
  • 8
  • 37
  • 41
  • 4
    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
  • 20
    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
415

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 = reject;
});

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;
   }
   //...
}
  • 20
    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
  • 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
  • thanks one more question how can I set the content type only image – SHAHEEREZ Dec 19 '22 at 12:26
  • @SHAHEEREZ You need to specify content type in an form input, not in a code. `` – Дмитрий Васильев Apr 21 '23 at 06:33
162

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
  • 8,755
  • 5
  • 65
  • 100
joshua.paling
  • 13,762
  • 4
  • 45
  • 60
  • 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
97

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
  • 12,022
  • 7
  • 56
  • 67
  • 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
22

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,656
  • 3
  • 30
  • 39
  • 2
    reader.result can possibly be null and will through a typescript error. This code handles that case: `reader.onload = () => resolve(reader.result ? reader.result.toString() : '')` – rahul Oct 23 '21 at 15:26
  • 2
    To prevent `Object is possibly 'null'` error you can use optional chaining operator like this `reader.onload = () => resolve(reader.result?.toString() || '');` – Oleksandr Danylchenko Dec 06 '21 at 21:01
  • Thank you, I updated the code :) – Cyber Progs Dec 08 '21 at 16:34
15

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
  • 24,677
  • 9
  • 99
  • 108
Pranav Maniar
  • 1,545
  • 10
  • 22
10

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(getFile));
    }

    //take a single JavaScript File object
    function getFile(file) {
        const 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,
                    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
  • 993
  • 1
  • 9
  • 16
4
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
  • 482
  • 1
  • 7
  • 14
2

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);
  
}
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]);
    }
}
Miguelio
  • 29
  • 1
  • 4
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,211
  • 1
  • 24
  • 48
0

This page is the first match when searching for how to convert a file object to a string. If you are not concerned about base64, the answer to that questions is as simple as:

    str = await file.text()
run_the_race
  • 1,344
  • 2
  • 36
  • 62
0

Extending on the above solutions by adding, with a use case where I required the ability to iterate through multiple fields on a form and get their values and with one being a file, it caused problems with he async requirements

Solved it like this:

    async collectFormData() {
        // Create the file parsing promise
        const toBase64 = file => new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = error => reject(error);
        });
    
        
        let form_vals = []
        let els = [] // Form elements collection

        // This is separate because wrapping the await in a callback
        // doesn't work 
        $(`.form-field`).each(function (e) {
            els.push(this) // add to the collection of form fields
        })

        // Loop through the fields to collect information 
        for (let elKey in els) {
            let el = els[elKey]

            // If the field is input of type file. call the base64 parser
            if ($(el).attr('type') == 'file') {
                // Get a reference to the file
                const file = el.files[0];

                form_vals.push({
                    "key": el.id,
                    "value": await toBase64(file)
                })

        }


        // TODO: The rest of your code here form_vals will now be 
        // populated in time for a server post
    }

This is purely to solve the problem of dealing with multiple fields in a smoother way

Illegal Operator
  • 656
  • 6
  • 14
0
const file_to_base64 = async (a_file: File) => {
  let a_function = 
    (file: File) => new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => {
        let base64_string = String(reader.result).split(",")[1]
        resolve(base64_string)
      };
      reader.onerror = error => reject(error);
    })
    return (await a_function(a_file) as string)
}
yingshao xo
  • 244
  • 7
  • 11
-1

This works

// fileObj: File
const base64 = window.URL.createObjectURL(fileObj);

// You can use it with <img src={base64} />
Chinmaya Pati
  • 357
  • 3
  • 7