Преобразуйте URI данных в файл, а затем добавьте в FormData
Я пытался повторно реализовать загрузчик изображений HTML5, как один на Mozilla хаки сайт, но это работает с браузерами WebKit. Часть задачи состоит в том, чтобы извлечь файл изображения из canvas "объект" и добавить его в FormData для загрузки.
проблема в том, что пока canvas имеет toDataURL функция для возврата представления файла изображения объект FormData принимает только объекты File или Blob из API.
решение Mozilla использовало следующую функцию Firefox-only на canvas:
var file = canvas.mozGetAsFile("foo.png");
...который не доступен в браузерах WebKit. Лучшее решение, которое я мог бы придумать, - это найти способ преобразовать URI данных в объект File, который, как я думал, может быть частью файлового API, но я не могу найти что-то для этого.
возможно ли это? Если нет, то какие альтернативы?
спасибо.
14 ответов:
после игры вокруг с несколькими вещами, мне удалось выяснить это самостоятельно.
прежде всего, это преобразует dataURI в Blob:
function dataURItoBlob(dataURI) { // convert base64/URLEncoded data component to raw binary data held in a string var byteString; if (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1]); else byteString = unescape(dataURI.split(',')[1]); // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to a typed array var ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], {type:mimeString}); }оттуда, добавление данных в форму таким образом, что он будет загружен в виде файла легко:
var dataURL = canvas.toDataURL('image/jpeg', 0.5); var blob = dataURItoBlob(dataURL); var fd = new FormData(document.forms[0]); fd.append("canvasImage", blob);
BlobBuilder и ArrayBuffer теперь устарели, вот код верхнего комментария, обновленный с помощью конструктора Blob:
function dataURItoBlob(dataURI) { var binary = atob(dataURI.split(',')[1]); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], {type: 'image/jpeg'}); }
этот работает в iOS и Safari.
вам нужно использовать решение ArrayBuffer Stoive, но вы не можете использовать BlobBuilder, как указывает vava720, так что вот мэшап обоих.
function dataURItoBlob(dataURI) { var byteString = atob(dataURI.split(',')[1]); var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: 'image/jpeg' }); }
Firefox имеет холст.toBlob() и Canvas.методы mozGetAsFile ().
но другие браузеры этого не делают.
мы можем получить dataurl из canvas, а затем преобразовать dataurl в объект blob.
вот моя функция dataURLtoBlob (). Она очень короткая.
function dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }используйте эту функцию с FormData для обработки вашего холста или dataurl.
например:
var dataurl = canvas.toDataURL('image/jpeg',0.8); var blob = dataURLtoBlob(dataurl); var fd = new FormData(); fd.append("myFile", blob, "thumb.jpg");кроме того, вы можете создать HTMLCanvasElement.прототип.способ toBlob для не браузер движке Gecko.
if(!HTMLCanvasElement.prototype.toBlob){ HTMLCanvasElement.prototype.toBlob = function(callback, type, encoderOptions){ var dataurl = this.toDataURL(type, encoderOptions); var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } var blob = new Blob([u8arr], {type: type}); callback.call(this, blob); }; }теперь холсте.toBlob () работает для всех современных браузеров, а не только firefox. например:
canvas.toBlob( function(blob){ var fd = new FormData(); fd.append("myFile", blob, "thumb.jpg"); //continue do something... }, 'image/jpeg', 0.8 );
благодаря @Stoive и @vava720 я объединил их таким образом, избегая использовать устаревшие BlobBuilder и ArrayBuffer
function dataURItoBlob(dataURI) { 'use strict' var byteString, mimestring if(dataURI.split(',')[0].indexOf('base64') !== -1 ) { byteString = atob(dataURI.split(',')[1]) } else { byteString = decodeURI(dataURI.split(',')[1]) } mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0] var content = new Array(); for (var i = 0; i < byteString.length; i++) { content[i] = byteString.charCodeAt(i) } return new Blob([new Uint8Array(content)], {type: mimestring}); }
мой предпочтительный способ холст.toBlob()
но в любом случае вот еще один способ конвертировать base64 в blob с помощью fetch ^^,
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" fetch(url) .then(res => res.blob()) .then(blob => { var fd = new FormData() fd.append('image', blob, 'filename') console.log(blob) // Upload // fetch('upload', {method: 'POST', body: fd}) })
развивающийся стандарт выглядит как холст.toBlob() не холст.getAsFile () как Mozilla рискнул догадаться.
Я не вижу ни одного браузера, который бы его поддерживал: (
Спасибо за эту замечательную тему!
кроме того, любой, кто пытается принять ответ, должен быть осторожен с BlobBuilder, поскольку я нахожу поддержку ограниченной (и пространством имен):
var bb; try { bb = new BlobBuilder(); } catch(e) { try { bb = new WebKitBlobBuilder(); } catch(e) { bb = new MozBlobBuilder(); } }вы использовали полифилл другой библиотеки для BlobBuilder?
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);может использоваться без try catch.
спасибо check_ca. Большая работа.
оригинальный ответ на Stoive легко поправимо путем изменения последней строки, чтобы вместить большого двоичного объекта:
function dataURItoBlob (dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs var byteString; if (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1]); else byteString = unescape(dataURI.split(',')[1]); // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to an ArrayBuffer var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } // write the ArrayBuffer to a blob, and you're done return new Blob([ab],{type: mimeString}); }
вот ES6 версия Stoive это:
export class ImageDataConverter { constructor(dataURI) { this.dataURI = dataURI; } getByteString() { let byteString; if (this.dataURI.split(',')[0].indexOf('base64') >= 0) { byteString = atob(this.dataURI.split(',')[1]); } else { byteString = decodeURI(this.dataURI.split(',')[1]); } return byteString; } getMimeString() { return this.dataURI.split(',')[0].split(':')[1].split(';')[0]; } convertToTypedArray() { let byteString = this.getByteString(); let ia = new Uint8Array(byteString.length); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return ia; } dataURItoBlob() { let mimeString = this.getMimeString(); let intArray = this.convertToTypedArray(); return new Blob([intArray], {type: mimeString}); } }использование:
const dataURL = canvas.toDataURL('image/jpeg', 0.5); const blob = new ImageDataConverter(dataURL).dataURItoBlob(); let fd = new FormData(document.forms[0]); fd.append("canvasImage", blob);
сделать это просто :D
function dataURItoBlob(dataURI,mime) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs var byteString = window.atob(dataURI); // separate out the mime component // write the bytes of the string to an ArrayBuffer //var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } // write the ArrayBuffer to a blob, and you're done var blob = new Blob([ia], { type: mime }); return blob; }
спасибо! @steovi для этого решения.
Я добавил поддержку версии ES6 и изменился с unescape на dataURI(unescape устарел).
converterDataURItoBlob(dataURI) { let byteString; let mimeString; let ia; if (dataURI.split(',')[0].indexOf('base64') >= 0) { byteString = atob(dataURI.split(',')[1]); } else { byteString = encodeURI(dataURI.split(',')[1]); } // separate out the mime component mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to a typed array ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], {type:mimeString}); }
У меня была точно такая же проблема, как у Равиндера паяла, и я нашел ответ. Попробуйте это:
var dataURL = canvas.toDataURL("image/jpeg"); var name = "image.jpg"; var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});
Comments