html 5 canvas LineTo() 线条颜色问题

Posted

技术标签:

【中文标题】html 5 canvas LineTo() 线条颜色问题【英文标题】:html 5 canvas LineTo() line color issues 【发布时间】:2018-09-18 21:29:46 【问题描述】:

我在 HMTL 5 2D 画布上绘制五条水平线:

var canvas_ctx = my_canvas.getContext("2d");
    canvas_ctx.lineWidth = 0.5;
    canvas_ctx.strokeStyle = "black";

    
        let line_x = 0;
        let line_length = canvas_ctx.width;
        let offset = 5;
        let numLines = 5;
        let numYincrement = 10;
        for (let i=0;i<numLines * numYincrement;i+=numYincrement) 
            //canvas_ctx.beginPath();
            canvas_ctx.moveTo(line_x,i + offset);
            canvas_ctx.lineTo(line_length,i + offset);
            canvas_ctx.stroke();
            //canvas_ctx.closePath();
        
    

理想情况下,这应该会产生 5 条黑线。相反,线条的颜色似乎随着每条新线而褪色(好像它是一个渐变!),所以第 5 行是灰色的。如果我取消注释 canvas_ctx.beginPath();canvas_ctx.closePath();,所有的行都会变成灰色。为什么会这样??

【问题讨论】:

【参考方案1】:

笔划确实从坐标的两侧重叠。

var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// draw big
ctx.scale(30, 30);
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(5, 10);
ctx.stroke();

drawPixelGrid();


function drawPixelGrid() 
  // simply renders where the pixel bounds are
  ctx.beginPath();
  // remove the zoom
  ctx.setTransform(1,0,0,1,0,0);
  ctx.strokeStyle = 'gray';
  ctx.lineWidth = 2; // avoid the problem we are demonstrating by using a perfect lineWidth ;-)

  for(let y=0; y<=300; y+=30) 
    ctx.moveTo(0, y);
    ctx.lineTo(300, y);
    for(let x=0; x<=300; x+=30) 
      ctx.moveTo(x, 0);
      ctx.lineTo(x, 300);
    
  
  ctx.stroke();
&lt;canvas id="c" height=300&gt;&lt;/canvas&gt;

但显然,一个像素不能同时设置为两种颜色。所以浏览器应用antialiasing,它会将你的像素颜色淡化为另一种颜色,这是混合背景色和前景色的结果。 因此,对于白色或透明背景上的黑色笔触,这会导致渲染实际的灰色像素。这里我继续以红色为例:

var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// first draw as on a 10*10 canvas
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(5, 10);
ctx.stroke();

// zoom it
ctx.imageSmoothingEnabled = 0;
ctx.globalCompositeOperation = 'copy';
ctx.drawImage(c, 0,0,9000,9000);

drawPixelGrid();

// this is not red...

function drawPixelGrid() 
  ctx.globalCompositeOperation = 'source-over';
  ctx.beginPath();
  ctx.setTransform(1,0,0,1,0,0);
  ctx.strokeStyle = 'gray';
  ctx.lineWidth = 2;

  for(let y=0; y<=300; y+=30) 
    ctx.moveTo(0, y);
    ctx.lineTo(300, y);
    for(let x=0; x<=300; x+=30) 
      ctx.moveTo(x, 0);
      ctx.lineTo(x, 300);
    
  
  ctx.stroke();
&lt;canvas id="c" height=300&gt;&lt;/canvas&gt;

避免这种情况的一种方法通常是在坐标上应用偏移量,以便线条在像素边界上正确延伸。例如,对于 1px 的线宽,您将应用 0.5 的偏移量:

var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// first draw as on a 10*10 canvas
ctx.beginPath();
ctx.moveTo(5.5, 0); // offset +0.5px
ctx.lineTo(5.5, 10);
ctx.stroke();

// zoom it
ctx.imageSmoothingEnabled = 0;
ctx.globalCompositeOperation = 'copy';
ctx.drawImage(c, 0,0,9000,9000);

drawPixelGrid();
// now we've got a real red

function drawPixelGrid() 
  ctx.globalCompositeOperation = 'source-over';
  ctx.beginPath();
  ctx.setTransform(1,0,0,1,0,0);
  ctx.strokeStyle = 'gray';
  ctx.lineWidth = 2;

  for(let y=0; y<=300; y+=30) 
    ctx.moveTo(0, y);
    ctx.lineTo(300, y);
    for(let x=0; x<=300; x+=30) 
      ctx.moveTo(x, 0);
      ctx.lineTo(x, 300);
    
  
  ctx.stroke();
&lt;canvas id="c" height=300&gt;&lt;/canvas&gt;

但在您的情况下,您绘制的线宽为 0.5px,因此任何偏移都无法消除这种抗锯齿。

因此,如果您想要完美的颜色,请选择正确的线宽。

【讨论】:

感谢您的详尽回答,Kaiido!

以上是关于html 5 canvas LineTo() 线条颜色问题的主要内容,如果未能解决你的问题,请参考以下文章

canvas基础入门绘制线条三角形七巧板

h5 Canvas线段的绘制

canvas学习:线条,图像变换和状态保存

canvas 基本线条绘制

12 canvas 画布 - 基础

总结:canvas与svg的区别