使用 javascript 和 websockets 显示来自 blob 的图像
Posted
技术标签:
【中文标题】使用 javascript 和 websockets 显示来自 blob 的图像【英文标题】:Display image from blob using javascript and websockets 【发布时间】:2012-06-20 19:54:01 【问题描述】:我目前正在开发一个显示由 C++ 服务器发送的图像的 WebSocket 应用程序。 我在那里看到了几个主题,但我似乎无法摆脱 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://***.com/a/4478878/1464608 Base64 类来自这里:https://***.com/a/246813/1464608
但我得到的 base64 结果不匹配,并且 Firefox 检索到图像已损坏的错误。
我知道这不是很多信息,但我不知道去哪里看:/ 任何帮助都非常受欢迎!
【问题讨论】:
也许您可以尝试在其他地方解码您的编码图像,以确保您的编码/解码方法是正确的。 尝试比较Base64.encode(string)
和btoa(string)
的结果。大多数 base64 库的操作与 btoa
对于高值字节的操作略有不同;也许这是你的问题?
我已经尝试过 btoa() 并且确实给出了不同的结果,但仍然无法正常工作。
我刚刚找到了那个链接:***.com/a/10469264/1464608,说明 websockets 不能发送图像或二进制数据以外的任何东西。所以我在 C++ 中将我的二进制数据转换为 base64,而不是使用这个:adp-gmbh.ch/cpp/common/base64.html 这样我的图像在 Firefox 中正确显示。但是,图像大小要大 30%!使用 WebSockets 直接发送 PNG 图像真的不可能吗?顺便说一句,图像不是二进制数据吗? (对不起,如果这是一个愚蠢的问题:o))
【参考方案1】:
我认为最简洁的解决方案是将 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://***.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;【参考方案2】:谢谢,很好用!!
所以我想我会分享我的最终 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 代码点。【参考方案3】:你可以写得更简单:
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);
;
【讨论】:
对我不起作用。但是,在我删除var bytes...
和 var blob...
行,然后将 reader.readAsDataURL(blob);
更改为 reader.readAsDataURL(arrayBuffer);
之后,它确实起作用了——这更简单了。
@Headcrab 你用什么浏览器?
Firefox 48.0.2 和 Windows 10 上的 Internet Explorer 11。在同一操作系统上的 Edge 浏览器中,您的版本和我的版本都不起作用。
与 Chrome 相同。不知道是否重要,但我的测试服务器不提供 html 文件,我直接从同一台机器的硬盘驱动器打开它,例如。 G。比如file:///C:/blahblah/client.html,然后它与一个用python编写的测试服务器建立websocket连接,它以二进制模式读取一个PNG文件并按原样提供。【参考方案4】:
另一种选择
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;
;
【讨论】:
【参考方案5】:感谢其他答案,我设法通过 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【参考方案6】:使用 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">
(1) 它也可以在不指定 MIME 类型的情况下工作。
【讨论】:
以上是关于使用 javascript 和 websockets 显示来自 blob 的图像的主要内容,如果未能解决你的问题,请参考以下文章
结合 JavaScript、Websockets 和 Java
Azure 服务总线通知中心是不是与 websockets 和 javascript 一起使用?
使用 javascript 和 websockets 显示来自 blob 的图像
通过 websockets 使用 javascript 传输文件
使用 Glassfish + Nginx + Javascript 的 Websocket
使用 Openfire、Javascript (strophe.js) 和 html5 websockets 的聊天客户端?