我允许用户通过拖放和其他方法将图像加载到页面中。当图像被删除时,我使用URL。createObjectURL转换为显示图像的对象URL。我没有撤销url,因为我重用了它。
因此,当需要创建一个FormData对象时我可以允许他们上传一个包含这些图像的表单,有什么方法可以将对象URL反向到Blob或File中,这样我就可以将它附加到FormData对象中?
我允许用户通过拖放和其他方法将图像加载到页面中。当图像被删除时,我使用URL。createObjectURL转换为显示图像的对象URL。我没有撤销url,因为我重用了它。
因此,当需要创建一个FormData对象时我可以允许他们上传一个包含这些图像的表单,有什么方法可以将对象URL反向到Blob或File中,这样我就可以将它附加到FormData对象中?
当前回答
如果你在画布中显示文件,你也可以将画布内容转换为blob对象。
canvas.toBlob(function(my_file){
//.toBlob is only implemented in > FF18 but there is a polyfill
//for other browsers https://github.com/blueimp/JavaScript-Canvas-to-Blob
var myBlob = (my_file);
})
其他回答
也许有人会发现这在使用React/Node/Axios时很有用。我在我的Cloudinary图像上传功能中使用了这个,在UI上使用了react-dropzone。
axios({
method: 'get',
url: file[0].preview, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
responseType: 'blob'
}).then(function(response){
var reader = new FileReader();
reader.readAsDataURL(response.data);
reader.onloadend = function() {
var base64data = reader.result;
self.props.onMainImageDrop(base64data)
}
})
再次获取blob URL的问题是,这将创建blob数据的完整副本,因此它将在内存中只有一次,而不是两次。对于大的Blobs,这可以很快地消耗你的内存。
这是相当不幸的,文件API不让我们访问当前链接的Blob,当然他们认为web作者应该在创建时自己存储Blob,这是正确的:
最好的方法是存储创建blob时使用的对象:// URL。
如果您担心这会阻止Blob被垃圾收集,那么您是对的,但是Blob:// URL首先也是如此,直到您撤销它。所以持有指向Blob的指针不会改变任何东西。
但是对于那些不负责创建blob:// URI的人(例如,因为它是库创建的),我们仍然可以通过覆盖默认URL来自己填补API漏洞。createObjectURL和URL。revokeObjectURL方法,这样它们就存储了对传递对象的引用。
确保在调用生成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 ) );
另一个优点是它甚至可以检索MediaSource对象,而在这种情况下,获取解决方案只会出错。
正如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的答案。
查看从XHR请求中获取BLOB数据,指出BlobBuilder在Chrome中不工作,所以你需要使用:
xhr.responseType = 'arraybuffer';
如果你在画布中显示文件,你也可以将画布内容转换为blob对象。
canvas.toBlob(function(my_file){
//.toBlob is only implemented in > FF18 but there is a polyfill
//for other browsers https://github.com/blueimp/JavaScript-Canvas-to-Blob
var myBlob = (my_file);
})