2012-06-18 10 views
21

Attualmente sto lavorando a un'applicazione WebSocket che sta visualizzando immagini inviate da un server C++. Ho visto un paio di argomenti intorno lì, ma io non riesco a sbarazzarsi di questo errore in Firefox:Visualizza l'immagine dal BLOB usando javascript e websockets

Immagine corrotto o troncato: Dati: image/png; base64, [alcuni dati]

Ecco il codice Javascript che sto usando per mostrare il mio 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); 
} 

sto usando l'immagine di un puntino rosso che ho trovato su questo argomento: https://stackoverflow.com/a/4478878/1464608 E la classe Base64 è da qui: https://stackoverflow.com/a/246813/1464608

Ma il risultato base64 che ottengo non corrisponde e Firefox mi recupera un errore dell'immagine corrotta.

So che questo non è molte informazioni ma non ho la minima idea di dove guardare:/ Qualsiasi aiuto è più che benvenuto !!

+0

Forse puoi provare a decodificare l'immagine codificata altrove per essere sicuro che il tuo metodo di codifica/decodifica è corretta. –

+0

Prova a confrontare il risultato di 'Base64.encode (stringa)' a 'btoa (stringa)'. La maggior parte delle librerie base64 operano in modo un po 'diverso da 'btoa' per i byte di valore elevato; forse questo è il tuo problema? – apsillers

+0

Ho già provato btoa() e in effetti sta dando un risultato diverso che non funziona ancora. – guitio2002

risposta

20

Penso che la soluzione più pulita sarebbe quella di modificare l'encoder base64 per operare direttamente su un Uint8Array anziché su una stringa.

Importante: per questo scopo è necessario impostare il tipo binario del socket Web su "arraybuffer". Metodo

L'onMessage dovrebbe essere simile a questo:

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

    var image = document.getElementById('image'); 
    image.src = encode(bytes); 
}; 

L'encoder convertito deve quindi simile a questa (sulla base di https://stackoverflow.com/a/246813/1464608):

// public method for encoding an Uint8Array to base64 
function encode (input) { 
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 
    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; 
} 
+2

Grazie. È davvero una buona soluzione Per me devo aggiungere la codifica Base64. Il mio tipo di reso è il seguente: return "data: image/jpg; base64," + output; – abanmitra

13

Grazie, sta funzionando grande !!

così ho dato che vorrei condividere il mio codice javascript finale:

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

non capisco il motivo per cui la versione blob è così difficile, ma questo ha fatto il trucco!

+1

Il problema è la conversione di dati binari in una stringa (carattere), che fornisce risultati diversi a seconda della codifica dei caratteri utilizzata. Può funzionare per ISO-8859-1 perché tutti i punti di codice sono mappati ai corrispondenti punti di codice unicode. Per UTF-8, ci saranno probabilmente problemi perché due o più byte nell'input possono essere decodificati come un singolo carattere, e alcuni valori di byte potrebbero essere punti di codice UTF-8 illegali. –

+0

grazie per l'aiuto, molto apprezzato :) – guitio2002

12

Si può scrivere molto più semplice:

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

Non ha funzionato per me. Tuttavia, ha funzionato dopo aver rimosso le righe 'var bytes ...' e 'var blob ...' e poi cambiato 'reader.readAsDataURL (blob);' a 'reader.readAsDataURL (arrayBuffer);' - che è anche ancora più semplice. – Headcrab

+0

@Headcrab Quale browser usi? –

+0

Firefox 48.0.2 e Internet Explorer 11 su Windows 10. Nel browser Edge sullo stesso sistema operativo né la tua né la mia versione funzionano. – Headcrab

1

Un'altra alternativa

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; 

}; 
1

Grazie alle altre risposte, sono riuscito a ricevere un'immagine JPEG da websocket e visualizzarlo in una nuova finestra:

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