it-swarm.com.de

Konvertieren Sie den Daten-URI in eine Datei und hängen Sie ihn an FormData an

Ich habe versucht, einen HTML5-Image-Uploader wie den auf der Mozilla Hacks - Site erneut zu implementieren, aber das funktioniert mit WebKit-Browsern. Ein Teil der Aufgabe besteht darin, eine Bilddatei aus dem Objekt canvas zu extrahieren und zum Hochladen an ein FormData - Objekt anzuhängen.

Das Problem ist, dass canvas über die Funktion toDataURL verfügt, um eine Darstellung der Bilddatei zurückzugeben, das FormData-Objekt jedoch nur Datei- oder Blob-Objekte von der Datei-API akzeptiert.

Die Mozilla-Lösung verwendete die folgende Nur-Firefox-Funktion für canvas:

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

... was in WebKit-Browsern nicht verfügbar ist. Die beste Lösung, die ich mir vorstellen kann, besteht darin, einen Weg zu finden, um einen Daten-URI in ein Datei-Objekt zu konvertieren, von dem ich dachte, dass es Teil der Datei-API ist, aber ich kann für mein ganzes Leben nichts finden, um das zu tun.

Ist es möglich? Wenn nicht, welche Alternativen?

Vielen Dank.

253
Stoive

Nachdem ich mit ein paar Dingen herumgespielt hatte, gelang es mir, dies selbst herauszufinden.

Zunächst wird eine dataURI in einen Blob konvertiert:

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

Das Anhängen der Daten an ein Formular ist so einfach, dass es als Datei hochgeladen wird:

var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
430
Stoive

BlobBuilder und ArrayBuffer sind jetzt veraltet. Hier ist der Code des Top-Kommentars, der mit dem Blob-Konstruktor aktualisiert wurde:

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

Dieses funktioniert in iOS und Safari.

Sie müssen die ArrayBuffer-Lösung von Stoive verwenden, BlobBuilder kann jedoch nicht verwendet werden, wie es bei vava720 der Fall ist.

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' });
}
51
William T.

Firefox verfügt über canvas.toBlob () und canvas.mozGetAsFile () - Methoden. 

Andere Browser jedoch nicht. 

Wir können dataurl vom Canvas bekommen und dann dataurl in ein blob-Objekt konvertieren.

Hier ist meine dataURLtoBlob()-Funktion. Es ist sehr kurz.

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

Verwenden Sie diese Funktion in Verbindung mit FormData, um Ihre Zeichenfläche oder Datenquelle zu bearbeiten.

Zum Beispiel:

var dataurl = canvas.toDataURL('image/jpeg',0.8);
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");

Sie können auch eine HTMLCanvasElement.prototype.toBlob-Methode für einen Browser ohne Gecko-Engine erstellen.

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

Jetzt funktioniert canvas.toBlob() für alle modernen Browser, nicht nur für Firefox . Zum Beispiel:

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

Mein bevorzugter Weg ist canvas.toBlob ()

Aber irgendwie ist hier noch ein anderer Weg, um base64 in einen Blob zu konvertieren

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

19
Endless

Dank @Stoive und @ vava720 habe ich die beiden auf diese Weise kombiniert, um den veralteten BlobBuilder und den ArrayBuffer zu vermeiden

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

Der sich entwickelnde Standard scheint canvas.toBlob () und nicht canvas.getAsFile () zu sein, wie Mozilla vermutete.

Ich sehe noch keinen Browser, der es unterstützt :(

Danke für diesen tollen Thread!

Jeder, der die akzeptierte Antwort versucht, sollte mit BlobBuilder vorsichtig sein, da ich Unterstützung finde, die begrenzt ist (und Namensraum):

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

Haben Sie die Polyfill einer anderen Bibliothek für BlobBuilder verwendet?

12
Chris Bosco
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);

kann ohne den try catch verwendet werden. 

Vielen Dank an check_ca. Gute Arbeit. 

5
Nafis Ahmad

Die ursprüngliche Antwort von Stoive kann leicht korrigiert werden, indem die letzte Zeile geändert wird, um Blob aufzunehmen:

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

Hier ist eine ES6-Version von Stoive's Antwort :

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

Verwendungszweck: 

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

mach es einfach: 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;
}
1
Sendy

Vielen Dank! @steovi für diese Lösung.

Ich habe die Unterstützung für die ES6-Version hinzugefügt und von unescape zu dataURI geändert (unescape ist veraltet).

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