HTML5画布处理中Web工作程序内存不足

Web worker out of memory in HTML5 canvas processing

本文关键字:Web 工作程序 内存不足 处理 布处理 HTML5      更新时间:2023-09-26

在主线程中:我通过getImageData方法获得源图像数组。它是一个uint8ClampedArray来记录我的图像数据。

以下是我在web worker中的代码:(这个代码会给我一个高分辨率的图像,但操作的结果太大了)

 self.addEventListener('message', function(e){
    var scale = e.data['scale'], cvWidth = e.data['width'], cvHeight = e.data['height'], sBufferData = e.data['sBuffer'].data;
    var sq = scale*scale,   //pixel of source within target
        sw = cvWidth, sh = cvHeight,
        sx = 0, sy = 0, sIdx = 0,
        tw = Math.floor(sw * scale), th = Math.floor(sh * scale),
        tx = 0, ty = 0, tIdx = 0,
        TX = 0, TY = 0, yIdx = 0,
        w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0,
        sR = 0, sG = 0, sB = 0,
        crossX = false, crossY = false,
        tBuffer = new Float32Array(3 * sw * sh);
    for( sy=0; sy<sh; sy++ ) {
        ty = sy * scale; TY = 0 | ty; yIdx = 3 * TY * tw; crossY = (TY != (0 | ty + scale));
        if(crossY) { wy = (TY + 1 - ty); nwy = (ty + scale - TY - 1); }
        for( sx=0; sx<sw; sx++, sIdx+=4 ) {
            tx = sx * scale; TX = 0 | tx; tIdx = yIdx + TX * 3; crossX = (TX != (0 | tx + scale));
            if(crossX) { wx = (TX + 1 - tx); nwx = (tx + scale - TX - 1); }
            sR = sBufferData[sIdx+0]; sG = sBufferData[sIdx+1]; sB = sBufferData[sIdx+2];
            if(!crossX && !crossY) {
                tBuffer[tIdx+0] += sR * sq; tBuffer[tIdx+1] += sG * sq; tBuffer[tIdx+2] += sB * sq;
            } else if(crossX && !crossY) {
                w = wx * scale;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwx * scale
                tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
            } else if(crossY && !crossX) {
                w = wy * scale;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwy * scale
                tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
            } else {
                w = wx * wy;
                tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
                nw = nwx * wy;  //for TX + 1; TY px
                tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
                nw = nwy * wx;
                tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
                nw = nwx * nwy;
                tBuffer[tIdx+3 * tw+3] += sR * nw; tBuffer[tIdx+3 * tw+4] += sG * nw; tBuffer[tIdx+3 * tw+5] += sB * nw;
            }
        }
    }
    var worker2Object = {'tBuffer': tBuffer}; //I guess tBuffer is too Large
        tBuffer = undefined; e = undefined;
    self.postMessage(worker2Object);   //Return to Main Thread
}, false);

当我使用IE或FireFox时,web工作线程中的内存将不足(Chrome很好)。

但是当图像大小小于1MB时,在3个浏览器上工作是很好的。

因此,我怀疑问题在于操作(tBuffer)的结果过大。有人能帮我解决这个问题吗?谢谢你的帮助。

我需要将big-O(n^2)算法移动到网络工作者,这样它就不会阻止我的主线程执行其他脚本。

现在,我需要在5个web worker线程中缩放5规范图像。下方的程序代码

for( var i in 5 spec image size array ) { //LOOP 5 time and new 5 web workers
   //get imageData of source image
   sourceBuffer = canvas.getContext("2d").getImageData(0, 0, w, h); 
   //new Worker_1 to process spec_1 image and so on
   Worker_1 = new Worker('myWebWorker.js');
   Worker_1.postMessage(sourceBuffer);
   Worker_1.onmessage = function(e){ get e.data }
}

好吧,这里有一个想法-当您使用Float32Array时,请记住每个颜色组件都从8位(1字节)大小转换为32位(4字节)大小。

因此,如果你的图像是,为了简单起见,比方说1000x1000,那么内存消耗将是:

Normal canvas:
1000 x 1000 x 4 = 4,000,000 bytes or 3.8 mb

在32位浮点数组的情况下,大小为:

Float32Array:
1000 x 1000 x 16 = 16,000,000 bytes or 15.3 mb

现在将其乘以5(假设每个都在图像或具有相同大小的图像上工作),使用float32,您的初始3.8mb画布(原始数据)将为76.5mb。

如果你的图像更多地位于2000 x 2000的通道中,那么你的画布是305 mb+15 mb,或者4000 x 4000然后1.2 gb(!)+61 mb,依此类推

此外:原始大小仅适用于您可以访问的缓冲区。浏览器可能有也可能没有该数据的后缓冲区,这意味着在后一种情况下,您将远远超过GB大小,这可以很容易地解释内存不足错误消息。

如果你需要高精度的颜色处理(我认为这是因为你使用的是浮动),一个替代方案可以是:

  • 请改用16位无符号缓冲区。这将把尺寸缩小到你现在的50%
  • 或者,如果可能的话,使用8位缓冲区,在将结果放回缓冲区之前,在浮点中脱机处理数据
  • 或者使用浮动缓冲器进行分段处理,但每次只处理图像的几行

提示:如果你和工人一起使用可转移的物品,你会获得巨大的性能提升。