2012-06-18 23 views
21

我目前正在處理顯示由C++服務器發送的圖像的WebSocket應用程序。 我見過一對夫婦的主題圍繞有,但我似乎無法在Firefox擺脫這種錯誤的:使用javascript和websockets從blob顯示圖像

圖片損壞或截斷:數據:圖像/ PNG; BASE64,[一些數據]

這裏是我用來顯示我的BLOB的Javascript代碼:

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

我用一個紅點,我在這個話題中的形象:https://stackoverflow.com/a/4478878/1464608 而Base64編碼類是從這裏:https://stackoverflow.com/a/246813/1464608

但是我得到的base64結果不匹配,Firefox檢索到了一個圖像被損壞的錯誤。

我知道這不是很多的信息,但我沒有線索去哪裏尋找:/ 任何幫助都是值得歡迎的!

+0

也許你可以嘗試在別處解碼你的編碼圖像,以確保你的編碼/解碼方法是正確的。 –

+0

嘗試將'Base64.encode(string)'的結果與'btoa(string)'進行比較。大多數base64庫的操作有點不同,即對於高值字節使用'btoa';也許這是你的問題? – apsillers

+0

我已經嘗試btoa(),它確實給不同的結果,仍然不工作壽。 – guitio2002

回答

20

我認爲最簡潔的解決方案是將base64編碼器更改爲直接在Uint8Array而不是字符串上運行。

重要提示:爲此,您需要將Web套接字的binaryType設置爲「arraybuffer」。

onMessage方法應該是這樣的:那麼

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

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

轉換後的編碼器應該是這樣的(基於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

謝謝。這真是一個很好的解決方案。對我來說,我必須添加Base64編碼。我的返回類型如下所示:return「data:image/jpg; base64,」+ output; – abanmitra

13

謝謝,它的工作的偉大!

所以我想我會分享我的最後的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); 
} 

真的不明白,爲什麼BLOB的版本是如此棘手,但是這並獲得成功!

+1

問題是將二進制數據轉換爲(字符)字符串,根據使用的字符編碼提供不同的結果。它可能適用於ISO-8859-1,因爲所有代碼點都映射到相應的unicode代碼點。對於UTF-8,可能會有問題,因爲輸入中的兩個或多個字節可能會被解碼爲單個字符,並且某些字節值可能是非法的UTF-8編碼點。 –

+0

感謝您的幫助,非常感謝:) – guitio2002

12

你可以寫簡單得多:

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

沒有爲我工作。然而,在我刪除了'var bytes ...'和'var blob ...'行,然後改變了'reader.readAsDataURL(blob);'到'reader.readAsDataURL(arrayBuffer);' - 這是行得通的更簡單了。 – Headcrab

+0

@Headcrab你使用哪種瀏覽器? –

+0

Firefox 48.0.2和Windows 10上的Internet Explorer 11.在同一OS上的Edge瀏覽器中,您的版本和我的版本都無法正常工作。 – Headcrab

1

另一種選擇

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

由於其他的答案,我設法通過WebSocket的接收JPEG圖像並在新窗口中顯示:

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