2012-06-18 8 views
21

Aktualnie pracuję nad aplikacją WebSocket, która wyświetla obrazy wysyłane przez serwer C++. Widziałem kilka tematów, wokół tam, ale ja nie potrafię pozbyć się tego błędu w Firefoksie:Wyświetl obraz z obiektu blob za pomocą javascript i stron internetowych

Obraz uszkodzony lub ściętego: data: image/png; base64 [niektóre dane]

Oto kod JavaScript używam do wyświetlania mojego 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); 
} 

Używam obraz czerwoną kropką, które znalazłem na ten temat: https://stackoverflow.com/a/4478878/1464608 a klasa jest z Base64 tutaj: https://stackoverflow.com/a/246813/1464608

Ale wynik base64, który otrzymuję, nie jest zgodny, a Firefox pobiera błąd w obrazie, który jest uszkodzony.

Wiem, że to niewiele informacji, ale nie mam pojęcia, gdzie szukać:/ Każda pomoc jest więcej niż mile widziany !!

+0

Może możesz spróbować odszyfrować kodowany obraz w innym miejscu, aby mieć pewność, że twoja metoda kodowania/dekodowania jest poprawne. –

+0

Spróbuj porównać wynik 'Base64.encode (napis)' do 'btoa (ciąg)'. Większość bibliotek base64 działa nieco inaczej niż "btoa" dla bajtów o dużej wartości; może to twój problem? – apsillers

+0

Już próbowałem btoa() i rzeczywiście daje inny wynik, który wciąż nie działa. – guitio2002

Odpowiedz

20

Myślę, że najczystszym rozwiązaniem byłoby zmiana enkodera base64, aby działał bezpośrednio na tablicy Uint8Array zamiast na łańcuchu.

Ważne: W tym celu musisz ustawić wartość binaryType gniazda internetowego na "arraybuffer". Metoda

onmessage powinna wyglądać następująco:

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

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

Przetworzony koder powinien wyglądać następująco (na podstawie 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

Dziękuję. To naprawdę dobre rozwiązanie. Dla mnie muszę dodać kodowanie Base64. Mój typ zwrotu wygląda następująco: return "data: image/jpg; base64," + output; – abanmitra

13

Dzięki, wszystko działa super !!

więc postać chciałbym podzielić się moją ostateczną kodu javascript:

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

naprawdę nie rozumiem, dlaczego wersja blob jest tak trudne, ale to załatwiło sprawę!

+1

Problem polega na konwertowaniu danych binarnych na ciąg (znak), który zapewnia różne wyniki w zależności od użytego kodowania znaków. Może działać dla ISO-8859-1, ponieważ wszystkie punkty kodowe są mapowane do odpowiednich punktów kodowych Unicode. W przypadku UTF-8 prawdopodobnie wystąpią problemy, ponieważ dwa lub więcej bajtów na wejściu może zostać zdekodowanych jako pojedynczy znak, a niektóre wartości bajtowe mogą być niedozwolonymi punktami kodowymi UTF-8. –

+0

dzięki za pomoc, bardzo doceniane :) – guitio2002

12

Możesz napisać to znacznie prostsze:

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

Nie działa dla mnie. Jednak zadziałało to po usunięciu linii 'var bytes ...' i 'var blob ...', a następnie zmieniono 'reader.readAsDataURL (blob); na' read.readAsDataURL (arrayBuffer); '- który jest równy jeszcze prostsze. – Headcrab

+0

@Headcrab Jakiej przeglądarki używasz? –

+0

Firefox 48.0.2 i Internet Explorer 11 na Windows 10. W przeglądarce krawędzi w tym samym systemie operacyjnym nie działa Twoja ani moja wersja. – Headcrab

1

Inną alternatywą

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

Dzięki innych odpowiedzi, udało mi się otrzymać obrazu JPEG przez websocket i wyświetlić go w nowym oknie:

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'); 
       }; 
Powiązane problemy