CSS线性渐变和Canvas线性渐变与不透明度设置不同 [英] CSS linear-gradient and Canvas linear-gradient aren't the same with opacity settings

查看:82
本文介绍了CSS线性渐变和Canvas线性渐变与不透明度设置不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要获得CSS在画布上定义的相同线性渐变外观.使用了一种有效的方法,直到不使用透明度设置为止.如果使用相同的线性渐变颜色设置定义了rgba颜色值,则结果看起来会有所不同,请参见以下链接:

I want to achieve the same linear gradient look defined by CSS on a canvas. Used a method that works great until no transparency setting is used. When there are rgba color values defined with the same linear gradient color settings the results doesn't look the same, please see the following link:

JSFiddle: 示例

var canvas = document.getElementById("myCanvas");
var ctx = document.getElementById("myCanvas").getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cssAng = Math.PI;
var dir = getDir(cssAng, w, h);
var gr = ctx.createLinearGradient(dir.x0,dir.y0,dir.x1,dir.y1);
gr.addColorStop(0, "rgb(255, 255, 255, 0)");
gr.addColorStop(0.87, "rgb(0, 0, 0, 1)");
ctx.fillStyle = gr;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);


function getDir(radian, width, height) {
        radian += Math.PI;
        const HALF_WIDTH = width * 0.5;
    const HALF_HEIGHT = height * 0.5;
    const lineLength = Math.abs(width * Math.sin(radian)) + Math.abs(height * Math.cos(radian));
    const HALF_LINE_LENGTH = lineLength / 2;

    const x0 = HALF_WIDTH + Math.sin(radian) * HALF_LINE_LENGTH;
    const y0 = HALF_HEIGHT - Math.cos(radian) * HALF_LINE_LENGTH;
    const x1 = width - x0;
    const y1 = height - y0;

return {x0, x1, y0, y1};
}

<!DOCTYPE html>
<html>
<body>
<div style='background-color:gray;display:inline-block;max-height:300px'>
  <div id="myDiv" style="display:inline-block;width:300px;height:300px;border:1px solid #d3d3d3;background:linear-gradient(180deg,rgba(255,255,255, 0) 0%, rgba(0,0,0,1) 87%"> </div>
</div>
<canvas id="myCanvas" width="300" height="300" style="background-color: gray;border:1px solid #d3d3d3;"> </canvas>
</body>
</html>

有人知道为什么会这样吗?是否有可以解决此问题的软件包?

Any idea why is this happening? Is there a package that can handle this issue?

推荐答案

CSS linear-gradient canvas线性渐变的规格实际上有所不同.它们看起来几乎完全相同,除了需要根据alpha值计算颜色的方式.对于CSS线性渐变,您需要:

There's actually a difference in the specs of the CSS linear-gradient and canvas linear gradient. They look almost exactly the same, except for the way the color needs to be calculated regarding the alpha value. For the CSS linear-gradient, you have this:

3.4.2.为渐变线着色在每个色标位置,渐变线是色标的颜色.在第一种颜色之前停止,渐变线是第一个颜色停止的颜色,并且在最后一个颜色停止之后,渐变线是最后一个颜色颜色停止.在两个色标之间,渐变线的颜色为插值在两个颜色的色标之间,插值发生在预乘的RGBA空间中.

请参阅: https://drafts.c​​sswg.org/css-images-3/#coloring-gradient-line

画布之一:

一旦创建了渐变(请参见下文),便会沿其放置停靠点它定义了颜色如何沿渐变分布.这每个停靠点处的渐变颜色是为此指定的颜色停止.在每个这样的停靠点之间,颜色和alpha分量必须在 RGBA空间上线性插值而无需预乘alpha值以查找在该偏移量处使用的颜色.之前第一站,颜色必须是第一站的颜色.

Once a gradient has been created (see below), stops are placed along it to define how the colors are distributed along the gradient. The color of the gradient at each stop is the color specified for that stop. Between each such stop, the colors and the alpha component must be linearly interpolated over the RGBA space without pre multiplying the alpha value to find the color to use at that offset. Before the first stop, the color must be the color of the first stop.

请参阅: https://html.spec.whatwg.org/multipage/canvas.html#interpolation

因此CSS版本通过将色标乘以其alpha值来计算色标.我更改了您的示例,使其更加明显.在以下示例中,CSS版本从 rgba(255,0,0,0) rgba(0,0,0,0)更改为 rgba(0,0,0,1).因此,使用预乘alpha计算得出的颜色在50%时为 rgba(0,0,0,0.5).

So the CSS version calculates the color stops by premultiplying their alpha values. I've changed your example to make it a bit more obvious. In the example below, the CSS version goes from rgba(255, 0, 0, 0) or rgba(0, 0, 0, 0) to rgba(0, 0, 0, 1). So at 50% the color calculated using premultiplied alpha is rgba(0, 0, 0, 0.5).

在画布版本中,插值是在没有预乘的情况下计算的.因此,您有50%的人是 rgba(127,5,0,0,0.5).对于渐变线的每个点都是如此.

In the canvas version, the interpolation is calculated without pre multiplying. So at 50% you have rgba(127,5, 0, 0, 0.5). This is true for every point of the gradient-line.

请参阅预乘的含义: https://drafts.c​​sswg.org/css-images-3/#premultiplied

和示例:

var canvas = document.getElementById("myCanvas");
var ctx = document.getElementById("myCanvas").getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cssAng = Math.PI;
var dir = getDir(cssAng, w, h);
var gr = ctx.createLinearGradient(dir.x0,dir.y0,dir.x1,dir.y1);
gr.addColorStop(0, "rgb(255, 0, 0, 0)");
gr.addColorStop(1, "rgb(0, 0, 0, 1)");
ctx.fillStyle = gr;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);


function getDir(radian, width, height) {
        radian += Math.PI;
        const HALF_WIDTH = width * 0.5;
    const HALF_HEIGHT = height * 0.5;
    const lineLength = Math.abs(width * Math.sin(radian)) + Math.abs(height * Math.cos(radian));
    const HALF_LINE_LENGTH = lineLength / 2;

    const x0 = HALF_WIDTH + Math.sin(radian) * HALF_LINE_LENGTH;
    const y0 = HALF_HEIGHT - Math.cos(radian) * HALF_LINE_LENGTH;
    const x1 = width - x0;
    const y1 = height - y0;

return {x0, x1, y0, y1};
}

<!DOCTYPE html>
<html>
<body>
<div style='display:inline-block;max-height:300px'>
  <div id="myDiv" style="display:inline-block;width:200px;height:300px;border:1px ;background:linear-gradient(180deg,rgba(255,0,0, 0) 0%, rgba(0,0,0,1) 100%"> </div>
   
</div>
<canvas id="myCanvas" width="200" height="300" > </canvas>
<div style="position: absolute;width:8px;height:8px;background:rgba(0,0,0,0.5); top: 144px; left: 0px; ">

</div>
<div style="position: absolute;width:10px;height:10px;background:rgba(127.5,0,0,0.5); top: 144px; left: 412px; ">

</div>
</body>
</html>

除了计算梯度线的每个点,我认为没有办法使2相等.

I don't think there's a way to make the 2 equivalent, except by calculating every point of the gradient line.

这篇关于CSS线性渐变和Canvas线性渐变与不透明度设置不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆