HTML5 Canvas没有显式设置单个像素的方法。
可以使用非常短的行设置像素,但反字符和行大写可能会干扰。
另一种方法可能是创建一个小的ImageData对象,并使用:
context.putImageData(data, x, y)
把它放在合适的位置。
有人能描述一种高效可靠的方法吗?
HTML5 Canvas没有显式设置单个像素的方法。
可以使用非常短的行设置像素,但反字符和行大写可能会干扰。
另一种方法可能是创建一个小的ImageData对象,并使用:
context.putImageData(data, x, y)
把它放在合适的位置。
有人能描述一种高效可靠的方法吗?
当前回答
一种没有提到的方法是使用getImageData,然后使用putImageData。 这种方法很适合当你想要画很多的时候,快速。 http://next.plnkr.co/edit/mfNyalsAR2MWkccr
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
var id = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var pixels = id.data;
var x = Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
var off = (y * id.width + x) * 4;
pixels[off] = r;
pixels[off + 1] = g;
pixels[off + 2] = b;
pixels[off + 3] = 255;
ctx.putImageData(id, 0, 0);
其他回答
有两个最好的竞争者:
创建一个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()的性能。还要注意,我并没有从头开始,也没有为每个测试测试完全相同的像素集。
像sdleihssirhc说的那样画一个矩形!
ctx.fillRect (10, 10, 1, 1);
^——应该在x:10, y:10处画一个1x1的矩形
如果你担心速度,那么你也可以考虑WebGL。
快捷方便
下面的类实现了本文中描述的快速方法,并包含了所有您需要的:readPixel, putPixel,获取宽度/高度。类在调用refresh()方法后更新画布。算例求解二维波动方程的简单情形
class Screen{ constructor(canvasSelector) { this.canvas = document.querySelector(canvasSelector); this.width = this.canvas.width; this.height = this.canvas.height; this.ctx = this.canvas.getContext('2d'); this.imageData = this.ctx.getImageData(0, 0, this.width, this.height); this.buf = new ArrayBuffer(this.imageData.data.length); this.buf8 = new Uint8ClampedArray(this.buf); this.data = new Uint32Array(this.buf); } // r,g,b,a - red, gren, blue, alpha components in range 0-255 putPixel(x,y,r,g,b,a=255) { this.data[y * this.width + x] = (a<<24) | (b<<16) | (g<<8) | r; } readPixel(x,y) { let p= this.data[y * this.width + x] return [p&0xff, p>>8&0xff, p>>16&0xff, p>>>24]; } refresh() { this.imageData.data.set(this.buf8); this.ctx.putImageData(this.imageData, 0, 0); } } // -------- // TEST // -------- let s= new Screen('#canvas'); // initialise function draw() { for (var y = 1; y < s.height-1; ++y) { for (var x = 1; x < s.width-1; ++x) { let a = [[1,0],[-1,0],[0,1],[0,-1]].reduce((a,[xp,yp])=> a+= s.readPixel(x+xp,y+yp)[0] // read pixel ,0); let v= a/1.99446-tmp[x][y]; tmp[x][y]=v<0 ? 0:v; } } for (var y = 1; y < s.height-1; ++y) { for (var x = 1; x < s.width-1; ++x) { let v=tmp[x][y]; tmp[x][y]= s.readPixel(x,y)[0]; // read pixel s.putPixel(x,y, v,0,0); // put pixel } } s.refresh(); window.requestAnimationFrame(draw) } // temporary 2d buffer ()for solving wave equation) let tmp = [...Array(s.width)].map(x => Array(s.height).fill(0)); function move(e) { s.putPixel(e.x-10, e.y-10, 255,255,255);} draw(); <canvas id="canvas" height="150" width="512" onmousemove="move(event)"></canvas> <div>Move mouse on black square</div>
function setPixel(imageData, x, y, r, g, b, a) {
var index = 4 * (x + y * imageData.width);
imageData.data[index+0] = r;
imageData.data[index+1] = g;
imageData.data[index+2] = b;
imageData.data[index+3] = a;
}