什么';用JavaScript从RGB像素阵列向屏幕绘制图像的最快方法是什么?

什么';用JavaScript从RGB像素阵列向屏幕绘制图像的最快方法是什么?,javascript,performance,firefox,canvas,Javascript,Performance,Firefox,Canvas,我正在开发一个图形前端,它通过向客户端发送压缩图像来呈现服务器端并将屏幕更新推送到浏览器(想想VNC)。我已经决定对PNG进行编码的开销太高,所以目前我正在通过websocket(启用压缩)发送8位RGB像素值的原始块。这实际上非常快,我看到了巨大的压缩增益(例如75K->2.7k) 然而,在客户端上,我必须获取原始像素,然后将它们绘制到画布上。这是我目前最佳的代码性能: // receive message from server self.ws.onmessage = function (e

我正在开发一个图形前端,它通过向客户端发送压缩图像来呈现服务器端并将屏幕更新推送到浏览器(想想VNC)。我已经决定对PNG进行编码的开销太高,所以目前我正在通过websocket(启用压缩)发送8位RGB像素值的原始块。这实际上非常快,我看到了巨大的压缩增益(例如75K->2.7k)

然而,在客户端上,我必须获取原始像素,然后将它们绘制到画布上。这是我目前最佳的代码性能:

// receive message from server
self.ws.onmessage = function (evt) {
    // get image offset
    var dv = new DataView(evt.data);
    var dx = dv.getInt16(0);
    var dy = dv.getInt16(2);
    var ww = dv.getInt16(4);
    var hh = dv.getInt16(6);
    var offset = 8;

    // get context to canvas and create image
    var ctx = self.canvas.getContext("2d");
    var img = ctx.createImageData(ww, hh);

    // unpack image data
    var start = performance.now();
    var dst = 0, src = offset;
    for (var ii=0; ii < ww*hh; ii++) {
        img.data[dst++] = dv.getUint8(src++);
        img.data[dst++] = dv.getUint8(src++);
        img.data[dst++] = dv.getUint8(src++);
        img.data[dst++] = 255;
    }

    // draw image
    ctx.putImageData(img, dx, dy, 0, 0, ww, hh);
    var end = performance.now();

    console.log("draw took " + (end-start) + " milliseconds");
//从服务器接收消息
self.ws.onmessage=函数(evt){
//获取图像偏移量
var dv=新数据视图(evt.data);
var dx=dv.getInt16(0);
var dy=dv.getInt16(2);
var ww=dv.getInt16(4);
var hh=dv.getInt16(6);
var偏移=8;
//获取画布的上下文并创建图像
var ctx=self.canvas.getContext(“2d”);
var img=ctx.createImageData(ww,hh);
//解包图像数据
var start=performance.now();
var dst=0,src=offset;
对于(var ii=0;ii
上面提到的75K图像(1000x500像素)以这种方式渲染需要约53毫秒,这是一段很长的时间。执行此绘制操作的最快方式是什么?我可以输出RGBA像素,而不是其他方式,这样可以使生活更轻松


编辑:这似乎更像是Firefox的问题,Chrome平均在2.5毫秒内运行相同的解码循环。

切换到完整的RGBA输出(由于压缩不会增加太多开销),并且使用此代码直接包装websocket缓冲区的速度要快得多:

// receive message from server
self.ws.onmessage = function (evt) {
    // get image offset
    var dv = new DataView(evt.data);
    var dx = dv.getInt16(0);
    var dy = dv.getInt16(2);
    var ww = dv.getInt16(4);
    var hh = dv.getInt16(6);

    // get context to canvas and create image
    var ctx = self.canvas.getContext("2d");

    // draw image data
    var start = performance.now();
    ctx.putImageData(
        new ImageData(new Uint8ClampedArray(evt.data, 8), ww, hh),
        dx, dy,
        0,  0,
        ww, hh
    );
    var end = performance.now();

    console.log("draw took " + (end-start) + " milliseconds");
}

现在,在Firefox和Chrome中渲染大图像需要1毫秒,而在Chrome中渲染则需要350毫秒。这就足够了。

websocket服务器与您的web服务器在同一台机器上吗?如果是,也许您可以让websocket拥有一个“临时”网站文件中的文件夹?通过这种方式,websocket服务器将图像保存到临时文件夹中,并将链接发送到客户端,您的web应用程序可以直接获取图像,而无需对其进行解释。图像是当前的,但不是给定的。图像的具体用途是什么?是由websocket生成的,还是从服务器发送的r websocket客户端?它是由服务器发送的,它是渲染窗口的一部分。不要再使用DataView设置像素数据。而是创建一个Uint8Array视图,或者更好,如果您能够为元数据创建一个固定偏移量,则创建一个UInt32数组用于读取,另一个用于从imagedata.data.buffer设置,这样您就有了一个每像素单读写操作。