166

I want to convert Base64String extracted from file(ex: "AAAAA....~") to a javascript file object.

The javascript file object what I mean is like this code:

HTML:

<input type="file" id="selectFile" > 

JS:

$('#selectFile').on('change', function(e) {
  var file = e.target.files[0];

  console.log(file)
}

'file' variable is a javascript file object. So I want to convert a base64 string to the javascript file object like that.

I just want to get file object by decoding base64 string (encoded by other app from a file) without html file input form.

Thank you.

Dayamre
  • 1,907
  • 2
  • 13
  • 10

9 Answers9

314

Way 1: only works for dataURL, not for other types of url.

function dataURLtoFile(dataurl, filename) {
    var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[arr.length - 1]), 
        n = bstr.length, 
        u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {type:mime});
}

//Usage example:
var file = dataURLtoFile('data:text/plain;base64,aGVsbG8=','hello.txt');
console.log(file);

Way 2: works for any type of url, (http url, dataURL, blobURL, etc...)

// return a promise that resolves with a File instance
function urltoFile(url, filename, mimeType){
    if (url.startsWith('data:')) {
        var arr = url.split(','),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[arr.length - 1]), 
            n = bstr.length, 
            u8arr = new Uint8Array(n);
        while(n--){
            u8arr[n] = bstr.charCodeAt(n);
        }
        var file = new File([u8arr], filename, {type:mime || mimeType});
        return Promise.resolve(file);
    }
    return fetch(url)
        .then(res => res.arrayBuffer())
        .then(buf => new File([buf], filename,{type:mimeType}));
}

//Usage example:
urltoFile('data:text/plain;base64,aGVsbG8=', 'hello.txt','text/plain')
.then(function(file){ console.log(file);});
cuixiping
  • 24,167
  • 8
  • 82
  • 93
  • 7
    Warning, it seems to me that File object is only available on Firefox. Prefer Blob objects : https://developer.mozilla.org/en-US/docs/Web/API/Blob – TeChn4K Dec 19 '16 at 13:49
  • I use your **2nd way ** to upload pdf thumbnail but, it display black image when upload is done – Chetan Buddh Dec 23 '16 at 06:54
  • @ChetanBuddh That may be caused by other issues of your code. Can you paste your code in JSFiddle ? – cuixiping Jan 03 '17 at 13:00
  • In way 1, i am getting [object Object] not [object file]. How can i get [object file].@cuixiping – Edukondalu Thaviti Jun 27 '17 at 12:27
  • May i get your assistance please @cuixiping – Edukondalu Thaviti Jun 27 '17 at 13:11
  • @TeChn4K Use Blob instead of File for older browsers which doesn't support File as contructor. – cuixiping Jul 20 '17 at 03:04
  • @EdukondaluThaviti You can paste your code into jsfiddle and paste the link to me. – cuixiping Jul 20 '17 at 03:05
  • 1
    This does not work for the file of format `data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQA` Could you please let me know if this can be doable? @cuixiping – coderpc Apr 16 '20 at 01:18
  • @Pavan I tried your case and didn't find any exception. Maybe your browser is too old? you can take a look at the console. – cuixiping Apr 23 '20 at 03:36
  • option#1 worked for me. I am converting Image to base64 to compress the image and converting it back to image (file object) and sending it to backend server to store in amazon s3. Thanks for the code snippet. – Ahmed Aug 21 '20 at 10:32
  • @coderpc It works well for your example. Maybe your code has other issues. – cuixiping Nov 09 '20 at 01:40
  • @cuixiping I tired in my ionic angular application. in bowser it working fine but in my apk build it not working. "lastModified":null, "lastModifiedDate": null, "size": 0, –  Jan 22 '21 at 07:48
  • I'm getting 431 (Request Header Fields Too Large) when using fetch with base64 image strings, maybe because they are longggg... – Ammar Faris Sep 21 '22 at 10:08
  • Please use dataURLtoFile instead of fetch if the dataURL is long. – cuixiping May 18 '23 at 02:16
105
const url = 'data:image/png;base6....';
fetch(url)
  .then(res => res.blob())
  .then(blob => {
    const file = new File([blob], "File name",{ type: "image/png" })
  })

Base64 String -> Blob -> File.

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Preethi Kumar
  • 1,371
  • 1
  • 9
  • 16
  • 9
    Note: This is incompatible with most Content Security Policies, if you have one – MaxGabriel Mar 20 '19 at 00:11
  • @MaxGabriel could you please elaborate? – Rambatino Jan 04 '20 at 12:17
  • 2
    If you have a CSP with the connect-src attribute to whitelist what URLs your Javascript can load, it will reject it with the error: "Refused to connect to 'data:text/plain;base64,aGVsbG8gd29ybGQ=' because it violates the following Content Security Policy directive: "connect-src <...>". You can have your CSP whitelist data URLs, but MDN warns: "This is insecure; an attacker can also inject arbitrary data: URIs. Use this sparingly and definitely not for scripts." https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src – MaxGabriel Jan 04 '20 at 20:39
63

This is the latest async/await pattern solution.

export async function dataUrlToFile(dataUrl: string, fileName: string): Promise<File> {

    const res: Response = await fetch(dataUrl);
    const blob: Blob = await res.blob();
    return new File([blob], fileName, { type: 'image/png' });
}
Sampath
  • 63,341
  • 64
  • 307
  • 441
4

Here is the Typescript version of accepted answer above by @cuixiping, now using Buffer instead of atob()

I saw deprecation warnings using atob() from TypeScript, although it isn't fully deprecated. Only one overload is. However, I converted mine to use the deprecation warning suggestion of Buffer. It seems more clean since it requires no extra loop to convert each character.

  /***
   * Converts a dataUrl base64 image string into a File byte array
   * dataUrl example:
   * data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIsAAACLCAYAAABRGWr/AAAAAXNSR0IA...etc
   */
  dataUrlToFile(dataUrl: string, filename: string): File | undefined {
    const arr = dataUrl.split(',');
    if (arr.length < 2) { return undefined; }
    const mimeArr = arr[0].match(/:(.*?);/);
    if (!mimeArr || mimeArr.length < 2) { return undefined; }
    const mime = mimeArr[1];
    const buff = Buffer.from(arr[1], 'base64');
    return new File([buff], filename, {type:mime});
  }

at the top of the file you'll need an import to make the typings happy.

import { Buffer } from 'buffer';

No special npm packages are needed.

Michael Lang
  • 1,100
  • 11
  • 17
4
const file = new File([
  new Blob(["decoded_base64_String"])
], "output_file_name");

You could use a lib like this to decode and encode base64 to arrayBuffer.

Jnr
  • 1,504
  • 2
  • 21
  • 36
3

I had a very similar requirement (importing a base64 encoded image from an external xml import file. After using xml2json-light library to convert to a json object, I was able to leverage insight from cuixiping's answer above to convert the incoming b64 encoded image to a file object.

const imgName = incomingImage['FileName'];
const imgExt = imgName.split('.').pop();
let mimeType = 'image/png';
if (imgExt.toLowerCase() !== 'png') {
    mimeType = 'image/jpeg';
}
const imgB64 = incomingImage['_@ttribute'];
const bstr = atob(imgB64);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
  u8arr[n] = bstr.charCodeAt(n);
}
const file = new File([u8arr], imgName, {type: mimeType});

My incoming json object had two properties after conversion by xml2json-light: FileName and _@ttribute (which was b64 image data contained in the body of the incoming element.) I needed to generate the mime-type based on the incoming FileName extension. Once I had all the pieces extracted/referenced from the json object, it was a simple task (using cuixiping's supplied code reference) to generate the new File object which was completely compatible with my existing classes that expected a file object generated from the browser element.

Hope this helps connects the dots for others.

JHBSA
  • 51
  • 3
0

Heads up,

JAVASCRIPT

<script>
   function readMtlAtClient(){

       mtlFileContent = '';

       var mtlFile = document.getElementById('mtlFileInput').files[0];
       var readerMTL = new FileReader();

       // Closure to capture the file information.
       readerMTL.onload = (function(reader) {
           return function() {
               mtlFileContent = reader.result;
               mtlFileContent = mtlFileContent.replace('data:;base64,', '');
               mtlFileContent = window.atob(mtlFileContent);

           };
       })(readerMTL);

       readerMTL.readAsDataURL(mtlFile);
   }
</script>

HTML

    <input class="FullWidth" type="file" name="mtlFileInput" value="" id="mtlFileInput" 
onchange="readMtlAtClient()" accept=".mtl"/>

Then mtlFileContent has your text as a decoded string !

Dimitrios Ververidis
  • 1,118
  • 1
  • 9
  • 33
0

Complete Version for Typescript

async uploadImage(b64img: string) {
  var file = await this.urltoFile(b64img,'name.png',this.base64MimeType(b64img));
}

//return a promise that resolves with a File instance
urltoFile(url, filename, mimeType){
    return (fetch(url)
        .then(function(res){return res.arrayBuffer();})
        .then(function(buf){return new File([buf], filename,{type:mimeType});})
    );
}

//return mime Type of bs64
base64MimeType(encoded) {
    var result = null;
  
    if (typeof encoded !== 'string') {
      return result;
    }
  
    var mime = encoded.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/);
  
    if (mime && mime.length) {
      result = mime[1];
    }
  
    return result;
}

Thats Work for me Converting base64 Image to File

0

this worked for me credit

base64ToFile = (url: string) => {
let arr = url.split(',');
// console.log(arr)
let mime = arr[0].match(/:(.*?);/)![1];
let data = arr[1];

let dataStr = atob(data);
let n = dataStr.length;
let dataArr = new Uint8Array(n);

while (n--) {
  dataArr[n] = dataStr.charCodeAt(n);
}

let file = new File([dataArr], 'File.png', { type: mime });

return file;
};
ibrahimgb
  • 693
  • 5
  • 13