如何通过websockets高效处理大量HTML5画布像素数据

use*_*569 9 javascript compression canvas websocket socket.io

可能重复:
通过websocket接收图像

运用

imageData = context.getImageData(0, 0, width, height);
JSON.stringify(imageData.data);
Run Code Online (Sandbox Code Playgroud)

我抓取像素数据,将其转换为字符串,然后通过websockets通过电线发送.但是,此字符串可能非常大,具体取决于画布对象的大小.我尝试使用这里找到的压缩技术:Gzip的JavaScript实现但socket.io抛出错误Websocket message contains invalid character(s).是否有一种有效的方法来压缩这些数据,以便它可以通过websockets发送?

kan*_*aka 6

根据您想要的效率轴(带宽与CPU效率),我会推荐几种方法.

选项1:您可以使用canvas toDataURL方法.这将返回画布图像数据的base64编码图像.它将使用您指定的图像格式(或默认的PNG)进行压缩,并将预编码为base64以通过WebSocket发送.

canvas = document.getElementById("mycanvas");
b64png = canvas.toDataURL();

ws.send(b64png);
Run Code Online (Sandbox Code Playgroud)

选项2:如果您可以容忍有损压缩,那么您可以从toDataURL方法请求图像为base64编码的JPEG:

canvas = document.getElementById("mycanvas");
b64jpeg = canvas.toDataURL("image/jpeg");

ws.send(b64jpeg);
Run Code Online (Sandbox Code Playgroud)

选项3:如果您使用的浏览器支持二进制WebSocket数据(Chrome,Firefox,IE 10),那么您可以直接通过WebSocket发送canvas arraybuffer

canvas = document.getElementById("mycanvas");
ctx = canvas.getContext('2d');
imgdata = ctx.getImageData(0,0, width, height).data; // This is a Uint8ClampedArray
ws.send(imgdata.buffer); // Send the ArrayBuffer from the Uint8ClampedArray
Run Code Online (Sandbox Code Playgroud)

选项3在带宽方面可能效率最低,但在客户端和服务器端处理能力方面效率最高,因为图像数据是原始发送的,只需要很少的前/后处理.

带宽效率最高的选项可能是#2,但在将图像数据转换为JPEG格式时会丢失一些图像质量.您甚至可以进一步将base64解码为arraybuffer或blob并通过二进制WebSocket发送,这样就不会获得33%base64带宽开销,但这会增加更多的CPU开销.

如果您想要高效的带宽而不会丢失任何图像质量,那么选项#2是您最好的选择.

一些注意事项/警告:

toDataURL为base64数据加前缀如下:

"data:image/png;base64,iVBORw0KGgoAAAA..."
Run Code Online (Sandbox Code Playgroud)

关于数据URL格式的一个好处是,您可以将整个内容粘贴到浏览器地址栏中,浏览器将呈现图像.

有关toDataURL的更多信息,请参阅MDN Canvas页面.


Sim*_*ris 3

我不同意关闭的尝试,因为您要求更有效的方式。我们至少能做的就是帮助您想出更有效的方法。

这实际上取决于你在做什么。你能让客户做更多的工作吗?

您真的必须发送所有画布像素数据吗?您可以只发送已更改的像素吗?(或者这几乎是全部?)

仅来回发送更改会将其推入计算问题,而不是大量数据传输问题。


根据您的应用程序,您可以跟踪已更改的区域吗?如果画布上有 2-3 个小矩形发生了变化,那么发送的矩形应该比整个画布小得多。


与任何效率问题一样,首先值得问的是您是否在做正确的事情。您真的需要通过网络传输大量像素数据吗?通常,使用画布,通过发送已更改场景的命令来在服务器上重新创建场景比发送位图本身更容易。Websockets 应该非常适合这一点。对于许多绘图应用程序和游戏来说,这可能是一个很好的解决方案,但这实际上取决于您想要在这里完成的任务。