0

考虑这段代码:

var deSaturated = deSaturate(greyscaleCtx.getImageData(0, 0, canvasWidth, canvasHeight));

imageData 来自 getImageData 画布函数。

function deSaturate (imageData) {
                var theData = imageData.data;

                var dataLength = theData.length;
                var i = dataLength-1;
                var lightLevel;
                // Iterate through each pixel, desaturating it
                while ( i >= 0) {
                    // To find the desaturated value, average the brightness of the red, green, and blue values

                    theData[i] = theData[i+1] = theData[i+2] = (theData[i] + theData[i + 1] + theData[i + 2]) / 3;

                    // Fully opaque
                    theData[i+3] = 255;
                    // returning an average intensity of all pixels.  Used for calibrating sensitivity based on room light level.
                    lightLevel += theData[i]; //combining the light level in the samefunction
                    i -= 4;

                }

                imageData.data = theData; //bring back theData into imageData.data - do I really need this?


                var r = [lightLevel/dataLength,imageData]
                return r;
            }

在编写和优化此代码期间,我发现我并不真正了解 js 如何处理例如“theData”变量。正在使用它只是引用 imageData.data 的一种简短方法,在这种情况下,我最终不需要以下代码:

imageData.data = theData

但是我是否要为性能下降(大量的 DOM I/O)付出代价?

或者正在theData = imageData.data实际复制原始数组(表示为 Uint8ClampedArray),然后我必须将修改后的数据重新分配给imageData.data.

我想这是基本的 javascript,但我在 MDN 和其他开发人员资源中发现了相互矛盾的代码示例,我真的很想正确理解这一点。

谢谢您的帮助!

4

2 回答 2

1

在 javascript 中,分配 anarray或 anobject只是分配对该数组或对象的引用 - 它不会复制数据。仅当您实际创建一个新数组并复制数据或调用一些旨在为您执行此操作的函数时,才会生成副本。

因此,如果imageData.data是一个array,那么将其分配给theData只是为引用相同数据创建了一个快捷方式。它不会制作数据的新副本。因此,在修改 指向的数据后theData,您不必将其分配回,imageData.data因为只有一个数据副本,并且两者theData和都imageData.data指向了数据的同一个副本。

所以,直接回答你的问题,这条线是不必要的:

imageData.data = theData;
于 2012-10-27T16:08:17.300 回答
1

刚刚进行了快速测试:

    var idata = ctx.getImageData(0,0,300,300);
    var data = idata.data;
    for(var i=0;i<data.length;i++){
        data[i]=0;
    }

    ctx.putImageData(idata,0,0);

正如预期的那样,这正确地消除了屏幕的一部分。但是没有 putImageData 什么都不会发生。因此,更改数据对象,无论是否存储在不同的变量中,都将反映在该 imageData 对象中。但是,在调用 putImageData 之前,这不会影响画布。

所以,是的,您可以删除最终分配,它会按需要工作。

但是我会警告说,它不是一个有效的假设它是一个 Uint8ClampedArray。是的,这就是 Chrome 的处理方式(我上次检查过),这确实是官方规范使用的。然而,一些浏览器没有 Uint8ClampedArray 的概念,但仍然通过现已弃用的 CanvasPixelArray 支持画布。

所以你保证得到的只是一些类似数组的接口。当我试图通过创建一个新的 Uint8ClampedArray 来缓存图像数据的有趣特征时,我不得不以艰难的方式学习这一点,但在某些浏览器中失败了。

请参阅:https ://developer.mozilla.org/en-US/docs/DOM/CanvasPixelArray

于 2012-10-27T16:29:28.603 回答