Преобразовать URI данных в файл, а затем добавить в FormData

Я пытаюсь переустановить загрузчик изображений HTML5, например, на сайте Mozilla Hacks, но это работает с браузерами WebKit, Часть задачи состоит в извлечении файла изображения из объекта canvas и добавлении его в объект FormData для загрузки.

Проблема заключается в том, что while canvas имеет функцию toDataURL для возврата представления файла изображения, объект FormData принимает объекты File или Blob только из API файлов.

Решение Mozilla использовало следующую функцию только для Firefox на canvas:

var file = canvas.mozGetAsFile("foo.png");

..., который недоступен в браузерах WebKit. Лучшее решение, которое я мог бы подумать, - найти способ конвертировать URI данных в объект File, который, как я думал, может быть частью File API, но я не могу на всю жизнь найти что-то для этого.

Возможно ли это? Если нет, то какие-либо альтернативы?

Спасибо.

Ответ 1

Поиграв с несколькими вещами, мне удалось понять это сам.

Прежде всего, это преобразует 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);

Ответ 2

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'});
}

Ответ 3

Это работает в iOS и Safari.

Вам нужно использовать решение Stoive ArrayBuffer, но вы не можете использовать BlobBuilder, как указывает vava720, поэтому здесь mashup для обоих.

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' });
}

Ответ 4

В Firefox есть методы canvas.toBlob() и canvas.mozGetAsFile().

Но другие браузеры этого не делают.

Мы можем получить dataurl с холста, а затем преобразовать 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.prototype.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);
    };
}

Теперь canvas.toBlob() работает для всех современных браузеров не только firefox. например:

canvas.toBlob(
    function(blob){
        var fd = new FormData();
        fd.append("myFile", blob, "thumb.jpg");
        //continue do something...
    },
    'image/jpeg',
    0.8
);

Ответ 5

Благодаря @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});
}

Ответ 6

Развивающийся стандарт выглядит как canvas.toBlob(), а не canvas.getAsFile(), поскольку Mozilla рискует угадать.

Я не вижу ни одного браузера, поддерживающего его: (

Спасибо за эту замечательную тему!

Кроме того, любой, кто пытается принять ответ, должен быть осторожен с BlobBuilder, поскольку я нахожу поддержку ограниченной (и имен):

    var bb;
    try {
        bb = new BlobBuilder();
    } catch(e) {
        try {
            bb = new WebKitBlobBuilder();
        } catch(e) {
            bb = new MozBlobBuilder();
        }
    }

Вы использовали другую библиотеку polyfill для BlobBuilder?

Ответ 7

Мой предпочтительный способ canvas.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})
})

Ответ 8

var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);

можно использовать без улова try.

Благодарим check_ca. Отличная работа.

Ответ 9

Исходный ответ Stoive легко фиксируется путем изменения последней строки для размещения Blob:

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});
}

Ответ 10

Вот версия ES6 Отвечайте ответ:

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);

Ответ 11

сделать это простым: 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;
}

Ответ 12

toDataURL дает вам строку, и вы можете поместить эту строку в скрытый ввод.

Ответ 13

У меня была такая же проблема, как у Равиндера Пайлала, и я нашел ответ. Попробуйте следующее:

var dataURL = canvas.toDataURL("image/jpeg");

var name = "image.jpg";
var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});