2012-06-18 28 views
21

Actualmente estoy trabajando en una aplicación WebSocket que muestra imágenes enviadas por un servidor C++. he visto un par de temas por ahí, pero me parece que no puede deshacerse de este error en Firefox:Mostrar imagen desde blob usando javascript y websockets

de imagen dañado o truncado: Datos: image/png; base64, algunos datos []

Aquí está el código Javascript que estoy usando para mostrar mi burbuja:

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

estoy usando la imagen de un punto rojo que he encontrado en este tema: https://stackoverflow.com/a/4478878/1464608 Y la clase base 64 es de aquí: https://stackoverflow.com/a/246813/1464608

Pero el resultado de base64 que recibo no coincide y Firefox me muestra un error al corromper la imagen.

Sé que esto no es mucha información, pero no tengo ni idea de dónde buscar:/ ¡Cualquier ayuda es más que bienvenida!

+0

Tal vez puedas intentar decodificar tu imagen codificada en otro lugar para asegurarte de que tu método de codificación/descodificación es correcto. –

+0

Intente comparar el resultado de 'Base64.encode (cadena)' a 'btoa (cadena)'. La mayoría de las bibliotecas base64 operan de forma un poco diferente que 'btoa' para bytes de alto valor; tal vez ese es tu problema? – apsillers

+0

Ya he probado btoa() y de hecho está dando un resultado diferente que todavía no está funcionando. – guitio2002

Respuesta

20

Creo que la solución más limpia sería cambiar el codificador base64 para operar directamente en un Uint8Array en lugar de una cadena.

Importante: Para esto, deberá establecer el tipo binario del socket web en "arraybuffer". Método

El onmessage debería tener este aspecto:

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

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

El codificador convertida debe tener el siguiente aspecto (basado en 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

Gracias. Es realmente una buena solución. Para mí tengo que agregar Base64 Encoding. Mi tipo de devolución se ve así: return "data: image/jpg; base64," + output; – abanmitra

13

gracias, es un gran trabajo !!

por lo que figura que me gustaría compartir mi código Javascript definitiva:

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

no entienden realmente por qué la versión burbuja es tan difícil, pero esto no hizo el truco!

+1

El problema es convertir datos binarios en una cadena (de caracteres), que ofrece resultados diferentes según la codificación de caracteres utilizada. Puede funcionar para ISO-8859-1 porque todos los puntos de código se asignan a los puntos de código Unicode correspondientes. Para UTF-8, probablemente haya problemas porque dos o más bytes en la entrada pueden decodificarse como un solo carácter, y algunos valores de bytes pueden ser puntos de código UTF-8 ilegales. –

+0

gracias por la ayuda, muy apreciada :) – guitio2002

12

puede escribir mucho más simple:

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

No funcionó para mí. Sin embargo, funcionó después de eliminar las líneas 'var bytes ...' y 'var blob ...' y luego cambié 'reader.readAsDataURL (blob);' a 'reader.readAsDataURL (arrayBuffer);' - que es par más simple aún. – Headcrab

+0

@Headcrab ¿Qué navegador usas? –

+0

Firefox 48.0.2 e Internet Explorer 11 en Windows 10. En el navegador Edge en el mismo sistema operativo, ni el tuyo ni mi versión funcionan. – Headcrab

1

Otra 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

Gracias a las otras respuestas, me las arreglé para recibir una imagen jpeg por WebSocket y lo mostrará en una nueva ventana:

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