web-dev-qa-db-fra.com

Afficher l'image de blob à l'aide de javascript et de websockets

Je travaille actuellement sur une application WebSocket qui affiche des images envoyées par un serveur C++. J'ai vu quelques sujets par là, mais je n'arrive pas à me débarrasser de cette erreur dans Firefox:

Image corrompue ou tronquée: données: image/png; base64, [certaines données]

Voici le code Javascript que j'utilise pour afficher mon blob:

socket.onmessage = function(msg) {
    var blob = msg.data;

    var reader = new FileReader();
    reader.onloadend = function() {
        var string = reader.result;
        var buffer = Base64.encode(string);
        var data = "data:image/png;base64,"+buffer;

        var image = document.getElementById('image');
        image.src = data;
    };
    reader.readAsBinaryString(blob);
}

J'utilise l'image d'un point rouge que j'ai trouvée sur ce sujet: https://stackoverflow.com/a/4478878/1464608 Et la classe Base64 est d'ici: https : //stackoverflow.com/a/246813/1464608

Mais le résultat en base64 que j'obtiens ne correspond pas et Firefox me récupère une erreur d'image corrompue.

Je sais que ce n'est pas beaucoup d'informations mais je n'ai aucune idée où chercher:/Toute aide est plus que bienvenue !!

26
guitio2002

Je pense que la solution la plus propre serait de changer l'encodeur base64 pour qu'il fonctionne directement sur un Uint8Array au lieu d'une chaîne.

Important: Pour cela, vous devez définir le type binaire du socket Web sur "arraybuffer".

La méthode onmessage devrait ressembler à ceci:

socket.onmessage = function(msg) {
    var arrayBuffer = msg.data;
    var bytes = new Uint8Array(arrayBuffer);

    var image = document.getElementById('image');
    image.src = 'data:image/png;base64,'+encode(bytes);
};

L'encodeur converti devrait alors ressembler à ceci (basé sur https://stackoverflow.com/a/246813/1464608 ):

// public method for encoding an Uint8Array to base64
function encode (input) {
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    while (i < input.length) {
        chr1 = input[i++];
        chr2 = i < input.length ? input[i++] : Number.NaN; // Not sure if the index 
        chr3 = i < input.length ? input[i++] : Number.NaN; // checks are needed here

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }
        output += keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                  keyStr.charAt(enc3) + keyStr.charAt(enc4);
    }
    return output;
}
26
Stefan Haustein

Merci, ça marche très bien !!

Donc je pense que je partagerais mon code javascript final:

var socket = new WebSocket('ws://'+Host+':'+port, protocol);
socket.binaryType = 'arraybuffer';

try {
    socket.onopen = function() {
        document.getElementById('status').style.backgroundColor = '#40ff40';
        document.getElementById('status').textContent = 'Connection opened';
    }

    socket.onmessage = function(msg) {
        var arrayBuffer = msg.data;
        var bytes = new Uint8Array(arrayBuffer);

        var image = document.getElementById('image');
        image.src = 'data:image/png;base64,'+encode(bytes);
    }

    socket.onclose = function(){
        document.getElementById('status').style.backgroundColor = '#ff4040';
        document.getElementById('status').textContent = 'Connection closed';
    }
} catch(exception) {
    alert('Error:'+exception);
}

ne comprends pas vraiment pourquoi la version blob est si délicate, mais cela a fait l'affaire!

13
guitio2002

Vous pouvez l'écrire beaucoup plus simplement:

socket.onmessage = function(msg) {
   var arrayBuffer = msg.data;
   var bytes = new Uint8Array(arrayBuffer);
   var blob        = new Blob([bytes.buffer]);

   var image = document.getElementById('image');

   var reader = new FileReader();
   reader.onload = function(e) {
       image.src = e.target.result;
   };
   reader.readAsDataURL(blob);
};
13
Nikita Koksharov

Une autre alternative

let urlObject;

socket.onmessage = function(msg) {
    const arrayBuffer = msg.data;
    const image = document.getElementById('image');

    if (urlObject) {
        URL.revokeObjectURL(urlObject) // only required if you do that multiple times
    }
    urlObject = URL.createObjectURL(new Blob([arrayBuffer]));

    image.src = urlObject;

};
2
Walle Cyril

Grâce aux autres réponses, j'ai réussi à recevoir une image jpeg par websocket et à l'afficher dans une nouvelle fenêtre:

socket.binaryType = "arraybuffer";                 
socket.onmessage = function (msg) 
               {    var bytes = new Uint8Array(msg.data);
                    var blob = new Blob([bytes.buffer]);
                    window.open(URL.createObjectURL(blob),'Name','resizable=1');
                };
2
J.Jacobs-VP