22

This Question is related to and inspired by How to updoad in old browsers (ex Safari 5.1.4)

Given an <input type="file"> element having a files property containing File objects which inherit from Blob, is it possible to create a ArrayBuffer and convert the ArrayBuffer to a data URI from a Blob or File object without using FileReader?

Approaches have tried so far have been

  • create a mock WebSocket with .binaryType set to "arraybuffer", create a MessageEvent with event.data set to File object; result is File object at onmessage handler

  • set prototype of File to ArrayBuffer, Uint8Array; result is Uncaught TypeError: Method ArrayBuffer.prototype.byteLength called on incompatible receiver #<ArrayBuffer>(), Uncaught TypeError: Method get TypedArray.prototype.byteLength called on incompatible receiver [object Object]()

  • set File at FormData object, attempt to post request body to <iframe>, admittedly not well-conceived; result Bad Request at plnkr

Expected result: Convert Blob and File objects to TypedArray then to data URL, or directly to data URL

<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <form method="get" entype="multipart/form-data" target="binaryFrame">
    <input id="#avatar" type="file" name="file" />
    <input type="submit" />
  </form>
  <iframe name="binaryFrame"></iframe>
  <script>
    var input = document.querySelector("input[type=file]");
    input.addEventListener("change", handleFiles, true);
    // see http://jsfiddle.net/adamboduch/JVfkt/
    var sock = new WebSocket("ws://mock");
    sock.binaryType = "arraybuffer";
    sock.onerror = function(e) {
        console.log("sock error", e); // ignore, here
      }

    sock.onmessage = function(e) {
      console.log("socket message", e.data, e.data instanceof ArrayBuffer);
    };

    function handleFiles(evnet) {
      var file = event.target.files[0];
      sock.dispatchEvent(new MessageEvent("message", {
        data: file
      }));
      var data = new FormData();
      data.append("file", file);
      document.forms[0].action = data;
    }
  </script>
</body>

</html>

See also Display image from blob using javascript and websockets , How can you encode a string to Base64 in JavaScript? ; interestingly ironic as am now asking similar Question https://stackoverflow.com/questions/34302231/is-there-any-way-to-convert-the-file-to-an-arraybuffer-without-filereader-api ; Blob .slice() method , FileReader .readAsDataURL() method

Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • I don't have safari 5 at hand (btw this browser is deprecated for years users should change it to an up-to-date one ASAP), nor a browser that does support `Blob` objects (or `File`) but doesn't support the `FileReader`. Does it really exists? aren't you looking the wrong way? (one workaround would be to upload the File somewhere and then refetch it with XHR but try to answer these first questions first) – Kaiido Jul 05 '16 at 06:14
  • 1
    @Kaiido _"nor a browser that does support Blob objects (or File) but doesn't support the FileReader. Does it really exists?"_ Do not have access to safari here, either. According to MDN browser compatibility, `` is supported at version 1.0 of safari, `Blob` at 5.1, `FileReader` at 6.0; `responseType` `"blob"` and `"arraybuffer"` at `XMLHttpRequest` state `"Yes"`. Curious how raw data is actually stored, accessed within `Blob` object? – guest271314 Jul 05 '16 at 06:57
  • Probably an early implementation... Too bad it doesn't support URL.createObjectURL either, otherwise you could have tried something as simple as `var url = URL.createObjectURL(blob); var xhr = new XMLHttpRequest(); xhr.onload = function(){ rawData = this.response; } xhr.open('get', url) xhr.send();`. Ps talking about early implementations, you can see that IE9 didn't support TypedArray, but still had one kind through canvas' `imageData` object. – Kaiido Jul 05 '16 at 07:09
  • @Kaiido Yes, curious how the process was discussed being implemented, or implemented; that is, accessing raw data stored in `Blob`, or `input.files` object at 1.0-5.1? If `Blob` is an object, the raw data is stored within object, yes? Another way to ask Question would be how to follow algorithm for `FileReader` to create a `FileReader` implementation from scratch using steps in algorithm - without using `FileReader` – guest271314 Jul 05 '16 at 07:24
  • Yes and no : yes the browser have it somewhere, but no, the Blob object doesn't expose its data... – Kaiido Jul 05 '16 at 07:38
  • @Kaiido Is requirement not possible? – guest271314 Jul 05 '16 at 07:41
  • Yes, as I said in first comment, if `` is supported, this means that you can send it to a server (e.g using a `
    `), once done, you can fetch the raw data back using xhr. But it will take longer than the small snippet in previous comment ;-)
    – Kaiido Jul 05 '16 at 07:44
  • @Kaiido Yes, possible using post to `php`, though is it possible by other processes without using `XMLHttpRequest`? See also, https://bugs.chromium.org/p/chromium/issues/detail?id=375297 , https://cs.chromium.org/chromium/src/storage/browser/blob/blob_reader.h – guest271314 Jul 05 '16 at 07:52
  • @Kaiido Is requirement not possible at safari 5.1.4 environment using `javascript` alone without using `FileReader` ? _"The only way to read content from a Blob is to use a FileReader."_ https://developer.mozilla.org/en-US/docs/Web/API/Blob#Example_for_creating_a_URL_to_a_typed_array_using_a_blob – guest271314 Jul 11 '16 at 01:59
  • 1
    Read this post please [what-to-use-instead-of-filereader-for-safari](http://stackoverflow.com/questions/7734150/what-to-use-instead-of-filereader-for-safari) – Alex Nikulin Jul 12 '16 at 05:03

1 Answers1

2

I just put it here:

var input = document.querySelector("input[type=file]");
input.addEventListener("change", handleFiles, true);

// for url
window.URL = window.URL || window.webkitURL;

function handleFiles(evnet) {
  var file = event.target.files[0];
  document.querySelector('iframe')
    .setAttribute('src', window.URL.createObjectURL(file));
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <form method="get" entype="multipart/form-data" target="binaryFrame">
    <input id="#avatar" type="file" name="file" />
    <input type="submit" />
  </form>
  <iframe name="binaryFrame"></iframe>
</body>
</html> 
Daniil Loban
  • 4,165
  • 1
  • 14
  • 20