400

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?

16 Answers 16

473

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;
   }
   //...
}
Sign up to request clarification or add additional context in comments.

4 Comments

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.
I actually tried this snippet trying to convert a image on a <input type='file' /> and got an error. : Users.js:41 Uncaught (in promise) TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
thanks one more question how can I set the content type only image
@SHAHEEREZ You need to specify content type in an form input, not in a code. <input type="file" accept="image/png, image/jpeg">
465

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.

5 Comments

read more about FileReader API: developer.mozilla.org/en-US/docs/Web/API/FileReader and browser support: caniuse.com/#feat=filereader
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?
I made a question out of the above comment if anyone can answer. stackoverflow.com/questions/47195119/…
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.
Thanks! I think this is not explained very well on developer.mozilla.org/en-US/docs/Web/API/FileReader/…
167

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)
);

1 Comment

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.
109

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

6 Comments

Chrome 69, the first replace is to catch empty file, second replace is missing comma - encoded = reader.result.replace("data:", "").replace(/^.*;base64,/, "");
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.
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. stackoverflow.com/a/13195218/1935128
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.
@ArnaudP Typescript error: Property 'replace' does not exist on type 'string | ArrayBuffer'.
|
31

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

3 Comments

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() : '')
To prevent Object is possibly 'null' error you can use optional chaining operator like this reader.onload = () => resolve(reader.result?.toString() || '');
Thank you, I updated the code :)
17

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.');
}

5 Comments

btoa works only with string. How to use it with file?
you will have to read file first and then pass it to this function.. Something like jsfiddle.net/eliseosoto/JHQnk
@PranavManiar Your fiddle no longer works. Can you update the link?
This was the only solution that worked for me
Just update the value by ...value = btoa(binaryString) to ...value = "data:image/jpeg;base64," + btoa(binaryString). And point to type which written as jpeg. You may check filetype from file.type.
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);
    

1 Comment

Promise all, based in a array.map works great! At least for me.
6
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);});

1 Comment

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

Comments

2
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)
}

Comments

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]);
    }
}

Comments

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

Comments

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()

Comments

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

Comments

0

Here's another alternative which is a bit easier to read than the accepted FileReader answer

const file = document.querySelector('#myfile').files[0];
const arrayBuffer = await file.arrayBuffer();
const base64Data = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

I suppose if you wanted to catch errors from awaiting the arrayBuffer you could do the following:

async function returnImageAsBase64() {
   const file = document.querySelector('#myfile').files[0];
   try {
      const arrayBuf = await file.arrayBuffer();
      const base64Data = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
      return base64Data;
   } catch(error) {
      console.error(error);
      return;
   }
}

Comments

-1

This works

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

// You can use it with <img src={base64} />

1 Comment

This would provide you with a blob, not base64

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.