2012-06-18 9 views
21

Tôi hiện đang làm việc trên một ứng dụng WebSocket hiển thị hình ảnh được gửi bởi một máy chủ C++. Tôi đã nhìn thấy một vài chủ đề xung quanh đó nhưng tôi dường như không thể thoát khỏi lỗi này trong Firefox:Hiển thị hình ảnh từ blob bằng cách sử dụng javascript và websockets

ảnh bị hỏng hoặc cắt ngắn: Dữ liệu: image/png; base64, [một số dữ liệu]

Dưới đây là các mã Javascript tôi đang sử dụng để hiển thị blob của tôi:

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

tôi đang sử dụng hình ảnh của một dấu chấm màu đỏ mà tôi tìm thấy về chủ đề này: https://stackoverflow.com/a/4478878/1464608 Và lớp Base64 là từ ở đây: https://stackoverflow.com/a/246813/1464608

Nhưng kết quả base64 mà tôi nhận được không khớp và Firefox truy xuất cho tôi lỗi của hình ảnh bị hỏng.

Tôi biết điều này không phải là nhiều thông tin nhưng tôi không có một đầu mối để tìm:/ Bất kỳ trợ giúp nào được hoan nghênh hơn !!

+0

Có thể bạn có thể thử giải mã hình ảnh được mã hóa của mình ở nơi khác để đảm bảo rằng phương pháp mã hóa/giải mã của bạn đúng. –

+0

Thử so sánh kết quả của 'Base64.encode (chuỗi)' với 'btoa (chuỗi)'. Hầu hết các thư viện base64 hoạt động hơi khác một chút so với 'btoa' cho các byte có giá trị cao; có lẽ đó là vấn đề của bạn? – apsillers

+0

Tôi đã thử btoa() và nó thực sự đưa ra một kết quả khác nhau mà vẫn không làm việc tho. – guitio2002

Trả lời

20

Tôi nghĩ giải pháp sạch nhất là thay đổi bộ mã hóa base64 để hoạt động trực tiếp trên Uint8Array thay vì chuỗi.

Quan trọng: Bạn sẽ cần phải đặt binaryType của ổ cắm web thành "arraybuffer" cho việc này. phương pháp

Các onmessage sẽ trông như thế này:

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

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

Các bộ mã hóa chuyển đổi sau đó sẽ giống như thế này (dựa trên 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

Cảm ơn bạn. Nó thực sự là một giải pháp tốt. Đối với tôi, tôi phải thêm mã hóa Base64. Kiểu trả về của tôi trông giống như: return "data: image/jpg; base64," + output; – abanmitra

13

Cảm ơn, nó hoạt động tuyệt vời !!

Vì vậy, tôi hình dung tôi muốn chia sẻ mã javascript cuối cùng của tôi:

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

không thực sự hiểu tại sao phiên bản blob là rất khó khăn nhưng điều này đã làm các trick!

+1

Sự cố đang chuyển đổi dữ liệu nhị phân thành chuỗi (ký tự), cung cấp các kết quả khác nhau tùy thuộc vào mã hóa ký tự được sử dụng. Nó có thể làm việc cho ISO-8859-1 bởi vì tất cả các điểm mã ánh xạ tới các điểm mã unicode tương ứng. Đối với UTF-8, có thể sẽ có vấn đề vì hai hoặc nhiều byte trong đầu vào có thể được giải mã dưới dạng một ký tự đơn và một số giá trị byte có thể là các điểm mã UTF-8 bất hợp pháp. –

+0

cảm ơn sự giúp đỡ, đánh giá cao :) – guitio2002

12

Bạn có thể viết nó đơn giản hơn nhiều:

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

Đã không làm việc cho tôi. Tuy nhiên, nó đã làm việc sau khi tôi loại bỏ 'var bytes ...' và 'var blob ...' dòng và sau đó thay đổi 'reader.readAsDataURL (blob);' thành 'reader.readAsDataURL (arrayBuffer);' - thậm chí là đơn giản hơn. – Headcrab

+0

@Headcrab Bạn sử dụng trình duyệt nào? –

+0

Firefox 48.0.2 và Internet Explorer 11 trên Windows 10. Trong trình duyệt Edge trên cùng một hệ điều hành, cả bạn lẫn phiên bản của tôi đều không hoạt động. – Headcrab

1

Một thay thế

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

Nhờ có câu trả lời khác, tôi quản lý để nhận được một hình ảnh jpeg bởi WebSocket và hiển thị nó trong một cửa sổ mới:

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