4

I'm trying to draw a black line on a white-filled canvas. For some reasons, only the inner pixels of that line (lineWidth = 3) are really black. The more I go to the edges of the line, the broghter in steps of the greyscale it gets. If I draw it with lineWith = 1, no pixels are really black.

I wrote a little demonstration of what happens: http://jsfiddle.net/xr5az/

Just for completeness, here is the code again:

<html>

<head>
<script type="text/javascript">
function page_loaded()
{
  var cv = document.getElementById("cv");
  var ctx = cv.getContext("2d");
  ctx.fillStyle = "#ffffff";
  ctx.strokeStyle = "#000000";
  ctx.lineWidth = 3;
  ctx.lineCap = "round";
  ctx.lineJoin = "bevel";
  ctx.fillRect(0, 0, cv.width, cv.height);
  ctx.moveTo(5, 5);
  ctx.lineTo(10, 10);
  ctx.stroke();
  var imgdata = ctx.getImageData(0, 0, cv.width, cv.height);
  for (var y = 0; y < cv.height; y ++)
  {
    for (var x = 0; x < cv.width; x ++)
    {
      var idx = 4 * (y * cv.width + x);
      var c = imgdata.data[idx]<<16 | imgdata.data[idx+1]<<8 | imgdata.data[idx+2];
      if (c != 0xffffff)
      {
        document.getElementById("debug").innerHTML += x+"x, "+y+"y: "+c.toString(16)+"<br/>";
      }
    }
  }
}
</script>
</head>

<body onload="page_loaded()">
<p>
<canvas id="cv" width="15" height="15"></canvas>
</p>
<p>
Found colors:
<div id="debug"></div>
</body>

</html>

Why isn't the line just black and how may I fix this issue?

Thanks a lot!

Robert
  • 43
  • 4
  • 1
    So one could argue that this is to do with the anti-alisaing of the line. If I change `lineWidth` to just 1 then the only colours found are black, so maybe this can help: http://stackoverflow.com/questions/195262/can-i-turn-off-antialiasing-on-an-html-canvas-element – Ahmed Nuaman Oct 20 '13 at 11:33
  • @AhmedNuaman - that's a rather old document. I found a more recent answer, here: http://stackoverflow.com/questions/4261090/html5-canvas-and-anti-aliasing. If you have a look at the canvas's context in the "Watches" list of the JS debugger (as got by getContext('2d') ), you'll see both an imageSmoothingEnabled and a webkitImageSmoothingEnabled flag. Setting false to the former applies it to the latter too. _However_ neither has an effect on the supplied fiddle. – enhzflep Oct 20 '13 at 11:44
  • @AhmedNuaman: If I set lineWith to 1 I get colors like 4x, 4y: fbfbfb; 5x, 4y: d0d0d0; 4x, 5y: c4c4c4; 5x, 5y: 151515; 6x, 5y: a7a7a7 for example in Firefox. – Robert Oct 20 '13 at 11:46
  • So clearly the issue is about how different browsers handle drawing lines in canvas. So how about instead of drawing a line you draw pixels instead to make the line? This way you control the colour of each pixel explicitly, but it is a more long winded process. – Ahmed Nuaman Oct 20 '13 at 11:59
  • @AhmedNuaman: yes, I will probably end up altering pixels directly... but just wanted to understand what the issue is here. – Robert Oct 20 '13 at 12:05
  • I now also tried in Safari on iPhone. There is the same issue, but the results are different! Safari colors different pixels than Firefox and also uses different grey values. So it really seems to be browser-related and not due to some missconfiguration of the context object. – Robert Oct 20 '13 at 12:12
  • Try to translate coordinates for 0.5 pixel. http://jsfiddle.net/xr5az/1/ – Rok Burgar Oct 20 '13 at 13:31
  • See these approaches, if they are of any use for you: https://github.com/harshalitalele/clean-line-to myLineTo method fills up every pixel of the line drawn with one color and that's how I used it. – Harshali Talele Apr 04 '19 at 09:05

1 Answers1

2
  1. draw vertically or horizontally and add 0.5 (jsfiddle.net/xr5az/2/) - you will get only black and white colours. (note that i hided line begin and end, it would be grey ...)

    ctx.moveTo(-2, 5.5); ctx.lineTo(17, 5.5); ctx.stroke();

  2. when you add angle, system adds extra grey colors pixels, without it, line would look bad.

  3. if you want to get line only from black color, draw many separate pixels (or squares if you want lineWidth > 1) between line start and end points.

p.s. sorry for broken fiddle link, system kicked my message even with code included like 10 times ...

ViliusL
  • 4,589
  • 26
  • 28
  • Okay, so it's really because of the gradient of the line... Well, adding black squares along the line is rather inefficient, so I decided to do the work completely at pixels level. But it's quite frustrating to see the different browsers behaving all differently. What a pity that it's not possible to force the creation of sharp-edged lines above raw pixels level. Thanks for your explanation! – Robert Oct 20 '13 at 14:41