HTML5 Canvas没有显式设置单个像素的方法。

可以使用非常短的行设置像素,但反字符和行大写可能会干扰。

另一种方法可能是创建一个小的ImageData对象,并使用:

context.putImageData(data, x, y)

把它放在合适的位置。

有人能描述一种高效可靠的方法吗?


当前回答

嗯,你也可以只做一个1像素宽的线,长度为1像素,让它的方向沿着一个轴移动。

            ctx.beginPath();
            ctx.lineWidth = 1; // one pixel wide
            ctx.strokeStyle = rgba(...);
            ctx.moveTo(50,25); // positioned at 50,25
            ctx.lineTo(51,25); // one pixel long
            ctx.stroke();

其他回答

长方形呢?这比创建ImageData对象更有效。

由于不同的浏览器似乎更喜欢不同的方法,也许在加载过程中对所有这三种方法进行一个较小的测试,以找出使用哪个方法最好,然后在整个应用程序中使用该方法是有意义的。

我没有考虑过fillRect(),但答案促使我对putImage()进行基准测试。

在(旧的)MacBook Pro上使用Chrome 9.0.597.84在随机位置放置100,000个随机颜色的像素,使用putImage()只需不到100毫秒,但使用fillRect()需要近900毫秒。(基准代码在http://pastebin.com/4ijVKJcC)。

如果我在循环之外选择一种颜色,并在随机位置绘制该颜色,putImage()需要59ms而fillRect()需要102ms。

在rgb(…)语法中生成和解析CSS颜色规范的开销似乎是造成大部分差异的原因。

另一方面,将原始RGB值直接放入ImageData块中不需要字符串处理或解析。

有两个最好的竞争者:

创建一个1×1图像数据,设置颜色,putImageData在位置: var id = myContext.createImageData(1,1);//每页只做一次 Var d = id.data;//每页只做一次 D [0] = r; D [1] = g; D [2] = b; D [3] = a; myContext。putImageData(id, x, y); 使用fillRect()绘制一个像素(应该没有混叠问题): ctx。fillStyle = " rgba(“+ r +”、“+ g +”、“+ b + +(一个/ 255)+)”; ctx。fillRect(x, y, 1,1);

你可以在这里测试它们的速度:http://jsperf.com/setting-canvas-pixel/9或https://www.measurethat.net/Benchmarks/Show/1664/1

我建议针对您关心的浏览器进行测试,以获得最大速度。截至2017年7月,fillRect()在Firefox v54和Chrome v59 (Win7x64)上快了5-6倍。

其他更愚蠢的选择有:

using getImageData()/putImageData() on the entire canvas; this is about 100× slower than other options. creating a custom image using a data url and using drawImage() to show it: var img = new Image; img.src = "data:image/png;base64," + myPNGEncoder(r,g,b,a); // Writing the PNGEncoder is left as an exercise for the reader creating another img or canvas filled with all the pixels you want and use drawImage() to blit just the pixel you want across. This would probably be very fast, but has the limitation that you need to pre-calculate the pixels you need.

注意,我的测试没有尝试保存和恢复画布上下文fillStyle;这将降低fillRect()的性能。还要注意,我并没有从头开始,也没有为每个测试测试完全相同的像素集。

为了完成Phrogz非常彻底的回答,fillRect()和putImageData()之间有一个关键的区别。 第一个使用上下文通过添加一个矩形(不是像素)来绘制,使用fillStyle alpha值和上下文globalAlpha和转换矩阵,行大写等。 第二个替换整个像素集(可能是一个,但为什么?) 正如您在jsperf上看到的那样,结果是不同的。

没有人想一次只设置一个像素(也就是说在屏幕上绘制)。这就是为什么没有特定的API来做到这一点(这是正确的)。 在性能方面,如果目标是生成一张图片(例如光线跟踪软件),你总是想使用一个由getImageData()获得的数组,这是一个优化的Uint8Array。然后使用setTimeout/seTInterval每秒调用putImageData()一次或几次。