Convert URL to File or Blob for FileReader.readAsDataURL

389.2k Views Asked by At

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?

10

There are 10 best solutions below

8
On BEST ANSWER

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.

0
On

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)
}
0
On

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');
0
On

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

6
On

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

7
On

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();
4
On

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();
1
On

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;
0
On

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

For my React projects, I use following function I created. It basically gets imageUrl as input and returns the file. The idea behind is to use fetch API and get the image as blob and convert to File. For the file name, I just use the original image name using substring function.

Important thing is not to forget try/catch in your functions.

export async function imageUrlToFile(imageUrl) {
    try {
        const response = await fetch(imageUrl);
        if (!response.ok) {
            throw new Error(`Failed to fetch image (status ${response.status})`);
        }
        const blob = await response.blob();
        const filename = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
        const file = new File([blob], filename, { type: blob.type });
        return file;
    } catch (error) {
        console.error('Error:', error);
        throw error;
    }
}