使用 javascript 和 websockets 显示 blob 中的图像

IT技术 javascript html websocket blob filereader
2021-03-18 19:52:16

我目前正在开发一个 WebSocket 应用程序,该应用程序显示由 C++ 服务器发送的图像。我在那里看到了几个主题,但我似乎无法摆脱 Firefox 中的这个错误:

图像损坏或截断:data:image/png;base64,[some data]

这是我用来显示我的 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 检索到我的图像已损坏的错误。

我知道这不是很多信息,但我不知道在哪里看:/任何帮助都非常受欢迎!!

6个回答

我认为最干净的解决方案是将 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 = 'data:image/png;base64,'+encode(bytes);
};

转换后的编码器应如下所示(基于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;
}
谢谢你。这确实是一个很好的解决方案。对我来说,我必须添加 Base64 编码。我的返回类型如下: return "data:image/jpg;base64,"+output;
2021-04-21 19:52:16

你可以写得更简单:

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);
};
@Headcrab 你用的是哪个浏览器?
2021-04-20 19:52:16
没有为我工作。但是,在我删除var bytes...删除var blob...行然后更改reader.readAsDataURL(blob);之后它确实有效reader.readAsDataURL(arrayBuffer);- 这甚至更简单。
2021-05-16 19:52:16
与 Chrome 相同。不知道它是否重要,但是我的测试服务器不提供html文件,我直接从同一台机器的硬盘驱动器打开它,例如file:///C:/blahblah/client.html,然后它与用python编写的测试服务器建立websocket连接,该服务器以二进制模式读取PNG文件并按原样提供服务。
2021-05-17 19:52:16
Windows 10 上的 Firefox 48.0.2 和 Internet Explorer 11。在同一操作系统上的 Edge 浏览器中,您和我的版本都无法使用。
2021-05-19 19:52:16

谢谢,效果很好!!

所以我想我会分享我的最终 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 版本如此棘手,但这确实成功了!

问题是将二进制数据转换为(字符)字符串,它会根据所使用的字符编码提供不同的结果。它可能适用于 ISO-8859-1,因为所有代码点都映射到相应的 Unicode 代码点。对于 UTF-8,可能会出现问题,因为输入中的两个或更多字节可能会被解码为单个字符,并且某些字节值可能是非法的 UTF-8 代码点。
2021-04-24 19:52:16

感谢其他答案,我设法通过 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');
                };
如果您正在构建单页应用程序,请不要忘记释放 URL 以避免浪费内存: revokeObjectURL
2021-04-24 19:52:16

另一种选择

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;

};