How to convert file to base64 in JavaScript?
Asked Answered
A

15

381

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?

Absorptivity answered 29/3, 2016 at 9:49 Comment(0)
C
439

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;
   }
   //...
}
Codi answered 30/7, 2019 at 13:8 Comment(4)
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.Leishaleishmania
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'.Finny
thanks one more question how can I set the content type only imageDoralynn
@Doralynn You need to specify content type in an form input, not in a code. <input type="file" accept="image/png, image/jpeg">Kiowa
U
452

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.

Unrighteous answered 29/3, 2016 at 10:17 Comment(5)
read more about FileReader API: developer.mozilla.org/en-US/docs/Web/API/FileReader and browser support: caniuse.com/#feat=filereaderVladivostok
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?Reckless
I made a question out of the above comment if anyone can answer. #47195619Reckless
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.Monah
Thanks! I think this is not explained very well on developer.mozilla.org/en-US/docs/Web/API/FileReader/…Neurocoele
C
439

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;
   }
   //...
}
Codi answered 30/7, 2019 at 13:8 Comment(4)
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.Leishaleishmania
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'.Finny
thanks one more question how can I set the content type only imageDoralynn
@Doralynn You need to specify content type in an form input, not in a code. <input type="file" accept="image/png, image/jpeg">Kiowa
F
163

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)
);
Fore answered 9/10, 2017 at 6:12 Comment(1)
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.Monah
R
104

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);
  });
}
Recessional answered 13/9, 2018 at 9:48 Comment(7)
Chrome 69, the first replace is to catch empty file, second replace is missing comma - encoded = reader.result.replace("data:", "").replace(/^.*;base64,/, "");Expedition
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.Recessional
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://mcmap.net/q/88179/-range-of-valid-character-for-a-base-64-encodingDeliberate
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.Recessional
@ArnaudP Typescript error: Property 'replace' does not exist on type 'string | ArrayBuffer'.Alfons
@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.Recessional
this saved me tons of trouble thank you so muchViradis
A
26

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);
     })
    }
Ale answered 5/1, 2021 at 20:49 Comment(3)
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() : '')Browbeat
To prevent Object is possibly 'null' error you can use optional chaining operator like this reader.onload = () => resolve(reader.result?.toString() || '');Deepdyed
Thank you, I updated the code :)Ale
K
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.');
}
Kure answered 29/3, 2016 at 9:53 Comment(5)
btoa works only with string. How to use it with file?Absorptivity
you will have to read file first and then pass it to this function.. Something like jsfiddle.net/eliseosoto/JHQnkKure
@PranavManiar Your fiddle no longer works. Can you update the link?Transmarine
This was the only solution that worked for meGoldfinch
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.Abradant
A
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);
    
Alissaalistair answered 26/7, 2018 at 16:51 Comment(1)
Promise all, based in a array.map works great! At least for me.Ayres
E
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);});
Emergency answered 27/1, 2021 at 20:2 Comment(1)
refer thisEmergency
D
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);
  
}
Dehypnotize answered 5/1, 2021 at 7:14 Comment(0)
P
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]);
    }
}
Pontone answered 17/9, 2019 at 18:50 Comment(0)
S
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);
  });
}
Sharlenesharline answered 25/11, 2021 at 6:9 Comment(0)
C
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()
Cholecystitis answered 26/8, 2022 at 7:41 Comment(0)
K
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

Kazachok answered 29/10, 2022 at 15:2 Comment(0)
T
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)
}
Triform answered 1/5, 2023 at 1:23 Comment(0)
C
-1

This works

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

// You can use it with <img src={base64} />
Collaborative answered 22/7, 2022 at 7:29 Comment(1)
This would provide you with a blob, not base64Terris

© 2022 - 2024 — McMap. All rights reserved.