webentwicklung-frage-antwort-db.com.de

Verwenden von Rohbilddaten aus einer Ajax-Anforderung für Daten-URI

Ich versuche, eine Kombination aus Ajax und Daten-URIs zu verwenden, um ein JPEG-Bild zu laden und seine EXIF-Daten mit einer einzigen HTTP-Anforderung zu extrahieren. Ich ändere dazu eine Bibliothek ( https://github.com/kennydude/photosphere ), um dies zu tun. Derzeit verwendet diese Bibliothek zwei HTTP-Anforderungen, um die Quelle des Images festzulegen und die EXIF-Daten abzurufen.

Das EXIF ​​funktioniert nicht, kein Problem. Ich habe jedoch Schwierigkeiten, die Rohdaten aus der Ajax-Anforderung als Quelle für das Bild zu verwenden.

Quellcode für einen kleinen Test der Technik:

<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>

function init()
{
    // own ajax library - using it to request a test jpg image
    new Ajax().sendRequest
    (
        "/images/photos/badger.jpg",
         { method : "GET",
            callback: function(xmlHTTP)
            {

                var encoded = btoa (unescape(encodeURIComponent(xmlHTTP.responseText)));
                var dataURL="data:image/jpeg;base64,"+encoded;

                document.getElementById("image").src = dataURL;
            }
        }
    );
}

</script>
<script type="text/javascript" src="http://www.free-map.org.uk/0.6/js/lib/Ajax.js"></script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>

Ich bekomme, wie es aussieht, vernünftige JPEG-Daten zurückgesendet, und die Länge (in Bytes) der Rohdaten und der base64-codierten - dann-nicht-codierten - Rohdaten ist gleich. Der Versuch, das Image src einzustellen, schlägt jedoch sowohl bei Firefox (25) als auch bei Chrome (31) (aktuelle Versionen) fehl. Chrome zeigt das Symbol "Defektes Bild" an, was darauf hindeutet, dass src ein ungültiges Format hat. 

Ich habe diese Mozilla-Seite für Informationen zur base64-Codierung/Decodierung verwendet:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding

Irgendeine Idee, was könnte falsch sein? Wenn ich mich umschaue, kann ich den base64-codierten Image-Server erstellen, aber kann dies auf der Clientseite so erfolgen? Zum einen erhöht die Base64-Codierungs-Serverseite offensichtlich die Datengröße, und der Zweck dieser Übung besteht darin, die vom Server übertragene Datenmenge sowie die Anzahl der Anforderungen zu reduzieren.

Danke, Nick

36
nickw

Dank dafür. Ich habe ein wenig mehr damit beschäftigt und es stellt sich heraus, dass es zumindest für die aktuellen Versionen von Firefox und Chrome eine Lösung gibt (EDIT: IE10 funktioniert auch). Sie können XMLHttpRequest2 und ein typisiertes Array (Uint8Array) verwenden. Der folgende Code funktioniert:

<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>

function init()
{
    var xmlHTTP = new XMLHttpRequest();
    xmlHTTP.open('GET','/images/photos/badger.jpg',true);

    // Must include this line - specifies the response type we want
    xmlHTTP.responseType = 'arraybuffer';

    xmlHTTP.onload = function(e)
    {

        var arr = new Uint8Array(this.response);


        // Convert the int array to a binary string
        // We have to use apply() as we are converting an *array*
        // and String.fromCharCode() takes one or more single values, not
        // an array.
        var raw = String.fromCharCode.apply(null,arr);

        // This works!!!
        var b64=btoa(raw);
        var dataURL="data:image/jpeg;base64,"+b64;
        document.getElementById("image").src = dataURL;
    };

    xmlHTTP.send();
}

</script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>

Grundsätzlich fragen Sie nach einer binären Antwort und erstellen dann eine vorzeichenlose 8-Bit-Int-Ansicht der Daten, bevor Sie sie wieder in einen (binär-freundlichen) String String.fromCharCode () konvertieren. Die Anwendung ist erforderlich, da String.fromCharCode () kein Array-Argument akzeptiert. Sie verwenden dann btoa (), erstellen Ihre Daten-URL und es funktioniert dann.

Die folgenden Ressourcen waren hierfür hilfreich:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays

und

http://www.html5rocks.com/de/tutorials/file/xhr2/

Nick

32
nickw

Die Antwort von Nick funktioniert sehr gut. Als ich dies mit einer ziemlich großen Datei machte, bekam ich einen Stapelüberlauf 

var raw = String.fromCharCode.apply(null,arr);

Die Erzeugung der rohen Saite in Stückchen hat für mich gut funktioniert.

var raw = '';
var i,j,subArray,chunk = 5000;
for (i=0,j=arr.length; i<j; i+=chunk) {
   subArray = arr.subarray(i,i+chunk);
   raw += String.fromCharCode.apply(null, subArray);
}
16
RoccoB

Ich hatte Probleme mit der oben beschriebenen ArrayBuffer -> String -> Base64-Methode, stieß jedoch auf eine andere Methode mit Blob , die hervorragend funktionierte. Es ist nicht eine Möglichkeit, Rohdaten in Base 64 zu konvertieren (wie im Titel), aber ist eine Möglichkeit, Rohbilddaten anzuzeigen (wie in der eigentlichen Frage):

var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
    var blb = new Blob([xhr.response], {type: 'image/png'});
    var url = (window.URL || window.webkitURL).createObjectURL(blb);
    image.src = url;
}

xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();

Alle Anerkennung geht an Jan Miksovsky, Autor von dieser Geige . Ich bin einfach darüber gestolpert und dachte, es würde eine nützliche Ergänzung zu dieser Diskussion sein.

15
Xavier Holt

Sie müssen auf dem Server eine base64-Kodierung durchführen, da der responseText als String behandelt wird und die Antwortdaten, die der Server sendet, binär sind. 

0
Shreyas

Moderne ES6-basierte Lösung zum Herunterladen von Bildern: (ohne Angabe des Bildtyps)

async function downloadImageFromUrl(url) {    // returns dataURL
  const xmlHTTP = new XMLHttpRequest();
  xmlHTTP.open('GET', url, true);
  xmlHTTP.responseType = 'blob';
  const imageBlob = await new Promise((resolve, reject) => {
    xmlHTTP.onload = e => xmlHTTP.status >= 200 && xmlHTTP.status < 300 && xmlHTTP.response.type.startsWith('image/') ? resolve(xmlHTTP.response) : reject(Error(`wrong status or type: ${xmlHTTP.status}/${xmlHTTP.response.type}`));
    xmlHTTP.onerror = reject;
    xmlHTTP.send();
  });
  return blobToDataUrl(imageBlob);
}

function blobToDataUrl(blob) { return new Promise(resolve => {
  const reader = new FileReader();    // https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
  reader.onload = e => resolve(e.target.result);
  reader.readAsDataURL(blob);
})}

Verwendungszweck:

downloadImageFromUrl('https://a.b/img.png').then(console.log, console.error)
0
icl7126

Ich habe seit zwei Tagen an diesem Problem gearbeitet, da ich eine Lösung brauchte, um das Outlook-Profilbild des Benutzers aus den Rohdaten von Microsoft Graft zu rendern. Ich habe alle oben genannten Lösungen implementiert, ohne Erfolg. Dann fand ich diesen git: Holen Sie sich Base64-Rohdaten des Bildes von responseBody mit jquery ajax

In meinem Fall habe ich gerade "data:image/png;base64," durch "data:image/jpg;base64," ersetzt.

Es wirkt wie ein Zauber.

0
KingofDendroar