190

ユーザーがドラッグ&ドロップやその他の方法でページに画像をロードできるようにしています。画像がドロップURL.createObjectURLされると、オブジェクト URL に変換して画像を表示するために使用しています。私はそれを再利用するので、私はURLを取り消すつもりはありません。

したがって、オブジェクトを作成して、それらの画像の1つを含むフォームをアップロードできるようにするときが来たら、FormDataそのオブジェクトURLを元に戻したり、追加しBlobたりできる方法はありますか?物体?FileFormData

4

9 に答える 9

82

上記のコメントで gengkev が暗示しているように、これを行う最善の/唯一の方法は、非同期 xhr2 呼び出しを使用することです。

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//your.blob.url.here', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status == 200) {
    var myBlob = this.response;
    // myBlob is now the blob that the object URL pointed to.
  }
};
xhr.send();

更新 (2018): ES5 を安全に使用できる状況について、Joe は以下のより単純な ES5 ベースの回答を提供しています。

于 2012-08-10T12:25:51.690 に答える
6

Blob URL を再度取得する際の問題は、Blob のデータの完全なコピーが作成されるため、メモリ内に 1 回だけ保持するのではなく、2 回保持することになります。大きなブロブを使用すると、メモリ使用量が急速に増加する可能性があります。

File API では、現在リンクされている Blob にアクセスできないのはかなり残念です。確かに、Web 作成者は作成時にその Blob を自分で保存する必要があると考えていましたが、これは事実です。

ここでの最善の方法は、blob:// URL を作成したときに使用したオブジェクトを保存することです。

これにより Blob がガベージ コレクションされなくなるのではないかと心配しているのであれば、その通りですが、最初から blob:// URL を取り消すまでそうします。したがって、その Blob へのポインターを保持しても、何も変わりません。

しかし、blob:// URI の作成に責任を負わない人 (たとえば、ライブラリが作成したため) については、デフォルトのURL.createObjectURLおよびURL.revokeObjectURLメソッドをオーバーライドすることで、その API の穴を自分で埋めることができます。渡されたオブジェクトへの参照を保存します。

blob:// URI を生成するコードが呼び出される前に、必ずこの関数を呼び出してください。

// Adds an URL.getFromObjectURL( <blob:// URI> ) method
// returns the original object (<Blob> or <MediaSource>) the URI points to or null
(() => {
  // overrides URL methods to be able to retrieve the original blobs later on
  const old_create = URL.createObjectURL;
  const old_revoke = URL.revokeObjectURL;
  Object.defineProperty(URL, 'createObjectURL', {
    get: () => storeAndCreate
  });
  Object.defineProperty(URL, 'revokeObjectURL', {
    get: () => forgetAndRevoke
  });
  Object.defineProperty(URL, 'getFromObjectURL', {
    get: () => getBlob
  });
  const dict = {};

  function storeAndCreate(blob) {
    const url = old_create(blob); // let it throw if it has to
    dict[url] = blob;
    return url
  }

  function forgetAndRevoke(url) {
    old_revoke(url);
    try {
      if(new URL(url).protocol === 'blob:') {
        delete dict[url];
      }
    } catch(e){}
  }

  function getBlob(url) {
    return dict[url] || null;
  }
})();

//  Usage:
const blob = new Blob( ["foo"] );
const url = URL.createObjectURL( blob );
console.log( url );
const retrieved = URL.getFromObjectURL( url );
console.log( "retrieved Blob is Same Object?", retrieved === blob );
fetch( url ).then( (resp) => resp.blob() )
  .then( (fetched) => console.log( "fetched Blob is Same Object?", fetched === blob ) );

もう 1 つの利点は、MediaSourceオブジェクトを取得することもできることですが、その場合、フェッチ ソリューションはエラーになります。

于 2021-04-08T06:29:37.137 に答える
5

BlobBuilder は Chrome では機能しないため、以下を使用する必要があることを指摘しているXHR 要求からの BLOB データの取得を参照してください。

xhr.responseType = 'arraybuffer';
于 2014-12-12T21:58:01.357 に答える
3

残念ながら、@BrianFreudの答えは私のニーズに合っていません。私には少し異なるニーズがありました。@BrianFreudの質問に対する答えではないことはわかっていますが、多くの人が同じニーズでここに来たので、ここに残します。「URL からファイルまたは BLOB を取得する方法は?」のようなものが必要でしたが、クロスドメインではないため、現在の正解は私のニーズには合いません。

Amazon S3/Azure Storage からの画像を使用する Web サイトがあり、一意の識別子で名前が付けられたオブジェクトを保存しています。

サンプル: http://****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf

この画像の一部は、システム インターフェイスからダウンロードする必要があります。このトラフィックが HTTP サーバーを通過しないようにするために、このオブジェクトへのアクセスに (ドメイン フィルタリングを除いて) セキュリティを必要としないため、ユーザーのブラウザーで直接要求を行い、ローカル処理を使用してファイルに実際の名前を付け、拡大。

それを達成するために、Henry Algus の次の素晴らしい記事を使用しました: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. 最初のステップ: jquery にバイナリ サポートを追加する

/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0 
* @author Henry Algus <henryalgus@gmail.com>
*
*/

// use this transport for "binary" data type
$.ajaxTransport("+binary", function (options, originalOptions, jqXHR) {
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
        return {
            // create new XMLHttpRequest
            send: function (headers, callback) {
                // setup all variables
                var xhr = new XMLHttpRequest(),
        url = options.url,
        type = options.type,
        async = options.async || true,
        // blob or arraybuffer. Default is blob
        dataType = options.responseType || "blob",
        data = options.data || null,
        username = options.username || null,
        password = options.password || null;

                xhr.addEventListener('load', function () {
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

                // setup custom headers
                for (var i in headers) {
                    xhr.setRequestHeader(i, headers[i]);
                }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function () {
                jqXHR.abort();
            }
        };
    }
});

2. 2 番目のステップ: このトランスポート タイプを使用してリクエストを作成します。

function downloadArt(url)
{
    $.ajax(url, {
        dataType: "binary",
        processData: false
    }).done(function (data) {
        // just my logic to name/create files
        var filename = url.substr(url.lastIndexOf('/') + 1) + '.png';
        var blob = new Blob([data], { type: 'image/png' });

        saveAs(blob, filename);
    });
}

これで、作成した Blob を自由に使用できます。私の場合は、ディスクに保存したいと考えています。

3. オプション: FileSaver を使用してユーザーのコンピューターにファイルを保存します。

FileSaver.js を使用して、ダウンロードしたファイルをディスクに保存しました。これを行う必要がある場合は、次の JavaScript ライブラリを使用してください。

https://github.com/eligrey/FileSaver.js/

これが、より具体的なニーズを持つ他の人に役立つことを期待しています。

于 2016-11-22T11:52:47.483 に答える