118

Reference: FileReader.readAsDataURL

Considering the following example:

function previewFile(file) {

  var reader  = new FileReader();

  reader.onloadend = function () {
    console.log(reader.result);
  }
  reader.readAsDataURL(file);
}

It states:

instanceOfFileReader.readAsDataURL(blob);

blob: The Blob or File from which to read.

  1. How can a local file URL like: 'file:///C:/path-to/root.png' be passed to the readAsDataURL()

  2. Is FileReader() available in a Firefox Addon?

erosman
  • 7,094
  • 7
  • 27
  • 46

9 Answers9

80

To convert a URL to a Blob for FileReader.readAsDataURL() do this:

var request = new XMLHttpRequest();
request.open('GET', MY_URL, true);
request.responseType = 'blob';
request.onload = function() {
    var reader = new FileReader();
    reader.readAsDataURL(request.response);
    reader.onload =  function(e){
        console.log('DataURL:', e.target.result);
    };
};
request.send();
Felix Turner
  • 1,345
  • 1
  • 9
  • 8
  • 1
    this could really benefit from some elaboration, never defined request.response in the snippet. can responseType or FileReader be used on url's already loaded without making a new XMLHttpRequest(); every time? – mibbit Jan 04 '18 at 04:49
  • This worked for me. Used the DataURL to load a Raster in paperjs from a image in s3 bucket. – Yasith Prabuddhaka Apr 04 '19 at 07:27
  • 1
    it seems to work well only on small files. if there is a large mp4 size around 800M, it takes a long time for the browser to respond and play. How could we leverage partial response here? – X.C. Aug 12 '19 at 08:26
67

Expanding on Felix Turner s response, here is how I would use this approach with the fetch API.

async function createFile(){
  let response = await fetch('http://127.0.0.1:8080/test.jpg');
  let data = await response.blob();
  let metadata = {
    type: 'image/jpeg'
  };
  let file = new File([data], "test.jpg", metadata);
  // ... do something with the file or return it
}
createFile();
Tibor Udvari
  • 2,932
  • 3
  • 23
  • 39
35

The suggested edit queue is full for @tibor-udvari's excellent fetch answer, so I'll post my suggested edits as a new answer.

This function gets the content type from the header if returned, otherwise falls back on a settable default type.

async function getFileFromUrl(url, name, defaultType = 'image/jpeg'){
  const response = await fetch(url);
  const data = await response.blob();
  return new File([data], name, {
    type: data.type || defaultType,
  });
}

// `await` can only be used in an async body, but showing it here for simplicity.
const file = await getFileFromUrl('https://example.com/image.jpg', 'example.jpg');
Endless
  • 34,080
  • 13
  • 108
  • 131
Krista
  • 616
  • 7
  • 5
17

Try this I learned this from @nmaier when I was mucking around with converting to ico: Well i dont really understand what array buffer is but it does what we need:

function previewFile(file) {

  var reader  = new FileReader();

  reader.onloadend = function () {
    console.log(reader.result); //this is an ArrayBuffer
  }
  reader.readAsArrayBuffer(file);
}

notice how i just changed your readAsDataURL to readAsArrayBuffer.

Here is the example @nmaier gave me: https://stackoverflow.com/a/24253997/1828637

it has a fiddle

if you want to take this and make a file out of it i would think you would use file-output-stream in the onloadend

Community
  • 1
  • 1
Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • Thanks Noitidart. At the moment, I am concentrating on converting it to DataURL I have tested other options but so far the above code (if I get it to work) seems like the cleanest :) – erosman Jul 31 '14 at 05:24
  • Can you make a gist at gist.github.com of your final code and share, i would like to see how its done :( – Noitidart Jul 31 '14 at 15:23
  • it is for [iGoogle](https://addons.mozilla.org/en-US/firefox/addon/igoogle/) and it will be in the next update. – erosman Jul 31 '14 at 17:29
  • @Noitidart what is really happening here flow-wise? We have not passed file to `new FileReader` then how is it reading? `readAsArraysBuffer` getting called before `reader.onload` ? – Govinda Sakhare Jun 17 '16 at 17:05
  • Hi @piechuckerr - Now I understand ArrayBuffers very well and DOMFile etc. what is happening above is we are passing a DOMFile and it is being turned into an ArrayBuffer. You can't pass anything else to this function I posted above. What are you trying to do? Load a local file? You can do that from addon scope, and from non-addon scope you will have to give the user a ` – Noitidart Jun 17 '16 at 17:52
  • For firefox use `reader.addEventListener("load", () => { ... })`. See [firefox mdn docs](https://developer.mozilla.org/en-US/docs/Web/API/FileReader#events) – Jurakin Jun 15 '22 at 17:46
14

This information is outdated as of now, but cannot be deleted.

  1. You can create File instances just by specifying a path when your code is chrome-privileged:

    new File("/path/to/file");
    

    File is a sub-class of Blob, so all File instances are also valid Blobs. Please note that this requires a platform path, and not a file URL.

  2. Yes, FileReader is available to addons.

File and FileReader are available in all windows. If you want to use them in a non-window scope (like bootstrap.js or a code module), you may use nsIDOMFile/nsIDOMFileReader.

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • 1
    Can you pass the urls returned by `canvas.toDataURL` and `canvas.toBlob` to `new File(here)`? – Blagoh Jul 30 '14 at 21:56
  • @Blagoh No. Why would would you wanna do that anyway? `.toBlob` already returns a blob... – nmaier Jul 30 '14 at 23:12
  • Oh I was just thinking for non-local url. But for that i can still just do `new File('http://blahblah.png')` right? – Blagoh Jul 30 '14 at 23:24
  • 2
    No, not really. For that you can do `XHR` to read (e.g. into an array buffer or directly as text) and then either use the resulting ArrayBuffer or text or just re-wrap if you need a blob for some reason ;) – nmaier Jul 30 '14 at 23:33
  • 12
    How would I do it from a local file URL (not path), like: file:///storage/emulated/0/Android/data/xxx/cache/1445607245908.jpg – raider33 Oct 23 '15 at 13:40
  • 36
    as per https://developer.mozilla.org/en-US/docs/Web/API/File/File, there ain't any `File()` ctor that simply takes path. –  Jul 07 '17 at 22:33
  • 5
    it is indeed not as simple as that, as File(path) doesn't exist, it's doesn't take only 'path' as argument. It should be something like that instead: [File(bits, path)](https://developer.mozilla.org/en-US/docs/Web/API/File/File) – arnaudambro Jun 18 '18 at 09:27
  • 4
    Using the fetch api: `new File([await (await fetch('/path/to/file')).blob()], '/path/to/file')` – Brian Takita Aug 17 '21 at 01:21
6

Here is my code using async awaits and promises

const getBlobFromUrl = (myImageUrl) => {
    return new Promise((resolve, reject) => {
        let request = new XMLHttpRequest();
        request.open('GET', myImageUrl, true);
        request.responseType = 'blob';
        request.onload = () => {
            resolve(request.response);
        };
        request.onerror = reject;
        request.send();
    })
}

const getDataFromBlob = (myBlob) => {
    return new Promise((resolve, reject) => {
        let reader = new FileReader();
        reader.onload = () => {
            resolve(reader.result);
        };
        reader.onerror = reject;
        reader.readAsDataURL(myBlob);
    })
}

const convertUrlToImageData = async (myImageUrl) => {
    try {
        let myBlob = await getBlobFromUrl(myImageUrl);
        console.log(myBlob)
        let myImageData = await getDataFromBlob(myBlob);
        console.log(myImageData)
        return myImageData;
    } catch (err) {
        console.log(err);
        return null;
    }
}

export default convertUrlToImageData;
jbailey
  • 309
  • 4
  • 6
  • This answer actually returns the original image down to the individual bytes instead of a different image that *looks* the same. If you're trying to implement functionality where you really want the original unaltered image, this is the best answer. Thanks :) – Steven Hunt Feb 17 '22 at 02:05
5

I know this is an expansion off of @tibor-udvari's answer, but for a nicer copy and paste.

async function createFile(url, type){
  if (typeof window === 'undefined') return // make sure we are in the browser
  const response = await fetch(url)
  const data = await response.blob()
  const metadata = {
    type: type || 'video/quicktime'
  }
  return new File([data], url, metadata)
}
Alex Cory
  • 10,635
  • 10
  • 52
  • 62
0

I ended up wanting something similar to this but without having to pass the type for the file or the filename, so I made my own example based on @Felix Turner's example. I used the content-disposition header for the filename first in case the file is coming back from an API endpoint, but use the last part of the URL path if that header doesn't exist.

function getFilenameFromContentDisposition(res) {
  let filename = null;

  const disposition = res.headers.get("content-disposition");

  if (disposition?.includes("attachment")) {
    const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
    const matches = filenameRegex.exec(disposition);
    if (matches?.[1]) {
      filename = matches[1].replace(/['"]/g, "");
      // Sometimes the filename comes in a URI encoded format so decode it
      filename = decodeURIComponent(filename);
      // Sometimes the filename starts with UTF-8, remove that
      filename = filename.replace(/^UTF-8/i, "").trim();
    }
  }

  return filename;
}

async function getFileFromLink(url) {
  const fileRes = await fetch(url);
  const blob = await fileRes.blob();

  let fileName = getFilenameFromContentDisposition(fileRes);
  if (!fileName) {
    fileName = url.split("/").pop();
  }

  const file = new File([blob], fileName, {
    type: blob.type,
  });

  return file;
}

If you wanted to make this better, I'd use the content-disposition package on npm for the parsing as the formatting of it can get strange. I'd also probably use the mime package for ensuring that the filename from the URL has a proper file extension based on the returned content-type

Chris Sandvik
  • 1,787
  • 9
  • 19
-1

Here's a simplest way to get blob or file object with vanila.js and promise

const fileURL_to_blob = (file_url) => {
  return new Promise((resolve, reject) => {
    let request = new XMLHttpRequest();
    request.open('GET', file_url, true);
    request.responseType = 'blob';
    request.onload = function() {
        var reader = new FileReader();
        reader.readAsDataURL(request.response);
        reader.onload =  function(e){
            //console.log('DataURL:', e.target.result);
            resolve(e.target.result);
        };
    };
    request.onerror=function(e){
      reject(e);
    }
    request.send();
  });
}