how to create soft stroke edge using HTML5 canvas

2019-06-20 11:05发布

I'm creating a drawing application using HTML5 canvas.

https://github.com/homanchou/sketchyPad

I can use rgba to control opacity in my line strokes, but how do I achieve a soft feathered brush edge vs a hard circular edge?

4条回答
淡お忘
2楼-- · 2019-06-20 11:42

I'm fairly sure that depends on the browser you're using. Last I checked (a while ago - might have changed) Firefox and Chrome do not antialias edges, whereas IE9 does.

查看更多
闹够了就滚
3楼-- · 2019-06-20 11:49

Three possible solutions:

  1. You could write your lines into an off-screen canvas, apply a blur filter, and then draw the result into the visible canvas.

  2. If you only use straight line segments, you could use a linear gradient for each line segment. The direction of the gradient must be in an 90" angle compared to the direction of the line segment.

  3. Draw the same lines multiple times at the same place. First with the full width and a low alpha. Then decrease the width and increase the alpha.

Example for using a linear gradient for each line segment:

http://jsfiddle.net/chdh/MmYAt/

function drawSoftLine(x1, y1, x2, y2, lineWidth, r, g, b, a) {
   var lx = x2 - x1;
   var ly = y2 - y1;
   var lineLength = Math.sqrt(lx*lx + ly*ly);
   var wy = lx / lineLength * lineWidth;
   var wx = ly / lineLength * lineWidth;
   var gradient = ctx.createLinearGradient(x1-wx/2, y1+wy/2, x1+wx/2, y1-wy/2);
      // The gradient must be defined accross the line, 90° turned compared
      // to the line direction.
   gradient.addColorStop(0,    "rgba("+r+","+g+","+b+",0)");
   gradient.addColorStop(0.43, "rgba("+r+","+g+","+b+","+a+")");
   gradient.addColorStop(0.57, "rgba("+r+","+g+","+b+","+a+")");
   gradient.addColorStop(1,    "rgba("+r+","+g+","+b+",0)");
   ctx.save();
   ctx.beginPath();
   ctx.lineWidth = lineWidth;
   ctx.strokeStyle = gradient;
   ctx.moveTo(x1, y1);
   ctx.lineTo(x2, y2);
   ctx.stroke();
   ctx.restore(); }

Example for drawing a line multiple times, by decreasing width and increasing alpha:

http://jsfiddle.net/chdh/RmtxL/

function drawSoftLine(x1, y1, x2, y2, lineWidth, r, g, b, a) {
   ctx.save();
   var widths = [1   , 0.8 , 0.6 , 0.4 , 0.2  ];
   var alphas = [0.2 , 0.4 , 0.6 , 0.8 , 1    ];
   var previousAlpha = 0;
   for (var pass = 0; pass < widths.length; pass++) {
      ctx.beginPath();
      ctx.lineWidth = lineWidth * widths[pass];
      var alpha = a * alphas[pass];
      // Formula: (1 - alpha) = (1 - deltaAlpha) * (1 - previousAlpha)
      var deltaAlpha = 1 - (1 - alpha) / (1 - previousAlpha)
      ctx.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + deltaAlpha + ")";
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.stroke();
      previousAlpha = alpha; }
   ctx.restore(); }
查看更多
劫难
4楼-- · 2019-06-20 11:51

You can use css filter to blur the canvas. It is possible with SVG rasterization trick. Here's how you do it:

  1. Make two canvases, one on top of another. One of them let's call «Target» and another «Buffer». Buffer is one you draw on and Target is the resulting canvas.

  2. Apply css-filter: blur(px) to Buffer canvas so user can instantly see the blurred preview.

  3. This is the interesting part. On each stroke (i. e. on mouseup), rasterize the Buffer canvas, put the image into <svg><foreignObject></foreignObject></svg>, apply the same CSS filter to it, rasterize SVG, and put the rasterized SVG on Target canvas. Here's gist with code example.

查看更多
地球回转人心会变
5楼-- · 2019-06-20 11:57

Once you have committed your lines to a canvas, you can soften (blur) using the CanvasPixelArray class. It's just a matter of adding your color to neighboring pixels. Here is a good info on pixel manipulation .

查看更多
登录 后发表回答