相交的半透明笔画文本



我对绘画上下文有一个问题。样式包含alpha的stokeText。线宽值太大,会产生一些笔画相交的效果,导致颜色偏深。我怎样才能避免这种情况呢?

ctx.strokeStyle ="rgba(0,0,0,0.3)";                
ctx.lineWidth = 15;
ctx.lineJoin="round";                
ctx.strokeText(text, x, y);

形象

这在规范中有点不一致,因为通常重叠的子路径只被绘制一次。

然而,strokeText()确实为每个字形创建了一个形状,因此该方法确实会将每个字形单独绘制,从而创建可见的重叠。

要克服这个问题,你需要一点创造性:

  • 首先绘制完全不透明的文本,
  • 然后重新绘制产生的像素与所需的alpha水平(许多方法这样做)。
  • 把它画在你的场景上(或者画后面的背景)。

这里有一些方法(还有许多其他方法):

可能是最简单的,但它消耗更多的内存:使用第二个断开连接的画布:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
// create a new canvas just for the text
const canvas2 = canvas.cloneNode();
const ctx2 = canvas2.getContext("2d");
ctx2.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx2.measureText(text).width - 20;
const y = canvas.height - 20;
// draw it fully opaque
ctx2.lineWidth = 15;
ctx2.lineJoin="round";                
ctx2.strokeText(text, x, y);
// draw the background on the visible canvas
ctx.fillStyle = "#ffe97f";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// now draw our text canvas onto the visible one
// with the desired opacity
ctx.globalAlpha = 0.3;
ctx.drawImage(canvas2, 0, 0);
<canvas width="465" height="234"></canvas>

更内存友好,但这需要你在不同的方向重写你的绘图逻辑,使用合成:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx.measureText(text).width - 20;
const y = canvas.height - 20;
// first draw the text fully opaque
ctx.lineWidth = 15;
ctx.lineJoin="round";                
ctx.strokeText(text, x, y);
// now apply the opacity
ctx.fillStyle ="rgba(0,0,0,0.3)";
ctx.globalCompositeOperation = "source-in";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// and the background
ctx.fillStyle = "#ffe97f";
ctx.globalCompositeOperation = "destination-over";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// if you want to keep drawing "normaly"
ctx.globalCompositeOperation = "source-over";
<canvas width="465" height="234"></canvas>

两者的混合,使用不同的合成规则:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.font = "60px sans-serif";
const text = "MY TEXT";
const x = canvas.width - ctx.measureText(text).width - 20;
const y = canvas.height - 20;
// first draw the text fully opaque
ctx.lineWidth = 15;
ctx.lineJoin="round";                
ctx.strokeText(text, x, y);
// now redraw over itself with the desired opacity
ctx.globalAlpha = 0.3;
ctx.globalCompositeOperation = "copy";
ctx.drawImage(canvas, 0, 0);
ctx.globalAlpha = 1;
// and the background
ctx.fillStyle = "#ffe97f";
ctx.globalCompositeOperation = "destination-over";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// if you want to keep drawing "normaly"
ctx.globalCompositeOperation = "source-over";
<canvas width="465" height="234"></canvas>

最新更新