简体   繁体   English

画布径向渐变与.png性能

[英]Canvas radial gradient vs .png performance

I'm trying to simulate brushes with the HTML canvas element. 我正在尝试使用HTML canvas元素模拟画笔。 To get brush hardness, I'm using a radial gradient, but I'm not entirely sure whether it's faster to create a new radial gradient for every point or saving the radial gradient as an image and use drawImage() instead. 为了获得笔刷的硬度,我使用了一个径向渐变,但是我不完全确定为每个点创建一个新的径向渐变还是将径向渐变保存为图像并使用drawImage()更快。

Current code: 当前代码:

var gradient = context.createRadialGradient(x, y, hardness * brushSize, x, y, brushSize);

gradient.addColorStop(0, color);
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');

context.fillStyle = gradient;
context.fillRect(x - halfBrushSize, y - halfBrushSize, brushSize, brushSize);

drawImage (apart from creating the image): drawImage (除了创建图像之外):

context.drawImage(img, x, y);

Gradients are expensive to generate contrary to images which are basically copies. 与基本为副本的图像相反,生成渐变的代价很高。 They both need to go through transformation matrix and anti-aliasing process though, but there is no calculation involved with images besides from that. 虽然它们都需要经过变换矩阵和抗锯齿处理,但是除此之外,没有涉及图像的计算。

UPDATE From the comments below people seem to get extremely variable test results depending on browser and hardware. 更新从下面的评论中,根据浏览器和硬件的不同,人们似乎会获得极其可变的测试结果。 The embedded test is not very accurate and was meant as a pointer, so for this reason I created a more accurate test here . 嵌入式测试不是很准确,只能作为一个指针,因此,出于这个原因,我在这里创建了一个更准确的测试 Feel free to post results below in comments. 随时在下面的评论中发布结果。
-- update end -- -更新结束-

The following is not the world's most accurate test, but the difference is so large that you get a pretty good pointer in any case to which is faster: 以下内容不是世界上最准确的测试,但是差异如此之大,无论如何您都会得到一个很好的指针,这是更快的:

 window.performance = window.performance || Date; setTimeout(go, 250); function go() { var ctx = c.getContext("2d"); // create radial gradient var gr = ctx.createRadialGradient(300, 300, 300, 300, 300, 0); gr.addColorStop(0, "#000"); gr.addColorStop(1, "#f00"); ctx.fillStyle = gr; // test gradient fill style var time1 = performance.now(); for (var i = 1000; i--;) ctx.fillRect(0, 0, c.width, c.height); var time2 = performance.now() - time1; o.innerHTML = "Gradient: " + time2.toFixed(4) + "<br>"; // test cached gradient (canvas = image source) ctx = c2.getContext("2d"); time1 = performance.now(); for (i = 1000; i--;) ctx.drawImage(c, 0, 0); time2 = performance.now() - time1; o.innerHTML += "drawImage: " + time2.toFixed(4); } 
 <output id=o>Running... please wait</output><br> <canvas id=c width=600 height=600></canvas><br> <canvas id=c2 width=600 height=600></canvas> 

When it comes to render a radial gradient, you can build the gradient on-the-fly, or use a png as you quoted, yet there's a third possibility : you can use a normalised gradient, that you build once, then use at will at any place/size by using the context transforms. 渲染径向渐变时,您可以即时构建渐变,也可以使用引用的png,但是还有第三种可能性:可以使用标准化的渐变,先构建一次,然后随意使用通过使用上下文转换,可以在任何位置/大小。

The code used to create the normalized gradient for a given hardness looks like : 用于为给定硬度创建归一化梯度的代码如下:

var mySingleGradient =  ctx.createRadialGradient(0.5, 0.5, 0.5*hardness, 0.5, 0.5, 0.5);
mySingleGradient.addColorStop(0, color);
mySingleGradient.addColorStop(1, '#000');

Just like when you are using png, you'll run into the issue of caching the gradients for any base color + hardness. 就像使用png一样,您会遇到为任何基色+硬度缓存渐变的问题。 But you won't have any png resolution issue, and most probably the size of the gradients will be way smaller than the png's. 但是您不会遇到任何png分辨率问题,并且最有可能的是,渐变的大小将比png的小得多。

You use such a normalised gradient with : 您可以将这样的归一化梯度与结合使用:

function drawThatGradientHere(ctx, x, y, gradient, brushSize) {
    ctx.save();
    ctx.translate(x,y);
    ctx.scale(brushSize,brushSize);
    ctx.fillStyle = gradient;
    ctx.fillRect(0,0,1,1);
    ctx.restore();
}

I won't go into benchmarking, since there are too many chances to compare apples and oranges without knowing more about the use. 我将不进行基准测试,因为有太多的机会可以比较苹果和橙子而又不了解其用途。 Because for instance, the drawImage might very well perform very differently if you are using its scaled version. 因为例如,drawImage在使用缩放版本时可能会表现出很大的不同。 Mind also that by using an image, you might run into resolution issues (too high : perf, too low : aliasing), that you won't have if you are using a gradient. 还请注意,通过使用图像,您可能会遇到分辨率问题(太高:perf,太低:aliasing),如果您使用渐变则不会。 So even if the gradient was proved slower, you might prefer it because of the way it consistently looks. 因此,即使事实证明渐变较慢,您也可能会喜欢它,因为它的外观始终如一。

A few questions : do you change your hardness often ? 几个问题:您经常改变硬度吗? do you change the brush size often ? 您经常更改画笔大小吗? do you change the start/end color of your gradient ? 您是否更改渐变的开始/结束颜色?

It's only by answering those question and having a random set of rect/hardness that has the same average distribution of your real use case that you'll be able to benchmark/compare anything. 只需回答这些问题,并获得一组随机的rect / hards,它们具有与实际用例相同的平均分布,就可以进行基准测试/比较。

Last word : If it's becoming hard to say which solution is faster, its time to pick the solution relying on... some other good reason... :-) 最后一句话:如果很难说出哪种解决方案更快,那就该依靠它来选择解决方案了……另一个很好的理由……:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM