Display image from blob using javascript and websockets

后端 未结 6 1346
春和景丽
春和景丽 2020-11-29 22:05

I\'m currently working on a WebSocket application that is displaying images send by a C++ server. I\'ve seen a couple of topics around there but I can\'t seem to get rid of

相关标签:
6条回答
  • 2020-11-29 22:27

    Thanks, it's working great!!

    So I figure I'd share my final javascript code:

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

    don't really understand why the blob version is so tricky but this did the trick!

    0 讨论(0)
  • 2020-11-29 22:28

    Thanks to the other answers, I managed to receive a jpeg image by websocket and display it in a new window :

    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');
                    };
    
    0 讨论(0)
  • 2020-11-29 22:31

    I think the cleanest solution would be to change the base64 encoder to operate directly on a Uint8Array instead of a string.

    Important: You'll need to set the binaryType of the web socket to "arraybuffer" for this.

    The onmessage method should look like this:

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

    The converted encoder should then look like this (based on https://stackoverflow.com/a/246813/1464608):

    // public method for encoding an Uint8Array to base64
    function encode (input) {
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        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;
    }
    
    0 讨论(0)
  • 2020-11-29 22:31

    This is very simple using a Blob:

    // Small red dot image
    const content = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]);
    
    document.getElementById('my-img').src = URL.createObjectURL(
      new Blob([content.buffer], { type: 'image/png' } /* (1) */)
    );
    Should display a small red dot: <img id="my-img">

    Works also with a simple array instead of Uint8Array:

    // Small red dot image
    const content = [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 5, 0, 0, 0, 5, 8, 6, 0, 0, 0, 141, 111, 38, 229, 0, 0, 0, 28, 73, 68, 65, 84, 8, 215, 99, 248, 255, 255, 63, 195, 127, 6, 32, 5, 195, 32, 18, 132, 208, 49, 241, 130, 88, 205, 4, 0, 14, 245, 53, 203, 209, 142, 14, 31, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
    
    document.getElementById('my-img').src = URL.createObjectURL(
      new Blob(content /* (1) */)
    );
    

    (1) It works without specifying the Blob MIME type.

    0 讨论(0)
  • 2020-11-29 22:32

    Another alternative

    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;
    
    };
    
    0 讨论(0)
  • 2020-11-29 22:38

    You may write it much simpler:

    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 讨论(0)
提交回复
热议问题