Как создать мягкий край обводки, используя HTML5 canvas - PullRequest
6 голосов
/ 26 января 2012

Я создаю приложение для рисования, используя HTML5 canvas.

https://github.com/homanchou/sketchyPad

Я могу использовать rgba для контроля непрозрачности в штрихах линии, но как мне добиться мягкого закрашенного края кисти по сравнению с жестким круглым краем?

Ответы [ 4 ]

7 голосов
/ 31 января 2012

Три возможных решения:

  1. Вы можете написать свои линии на холсте за пределами экрана, применить фильтр размытия и затем нарисовать результат на видимом холсте.

  2. Если вы используете только прямые отрезки, вы можете использовать линейный градиент для каждого отрезка.Направление градиента должно быть под углом 90 "по сравнению с направлением отрезка.

  3. Нарисуйте одни и те же линии несколько раз в одном и том же месте. Сначала с полной шириной инизкий альфа. Затем уменьшите ширину и увеличьте альфа.

Пример использования линейного градиента для каждого отрезка:

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(); }

Пример для многократного рисования линии путем уменьшения ширины и увеличения альфа:

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(); }
0 голосов
/ 09 марта 2016

Вы можете использовать фильтр CSS, чтобы размыть холст.Это возможно при приеме растеризации SVG .Вот как вы это делаете:

  1. Создайте два холста, один поверх другого.Одного из них назовем «Target», а другого «Buffer».Буфер - это тот, на котором вы рисуете, а Target является результирующим холстом.

  2. Примените css-filter: blur(px) к холсту буфера, чтобы пользователь мог сразу увидеть размытый предварительный просмотр.

    Это интересная часть.При каждом штрихе (т. Е. При наведении мыши) растеризуйте холст буфера, поместите изображение в <svg><foreignObject></foreignObject></svg>, примените к нему один и тот же CSS-фильтр, растеризуйте SVG и поместите растеризованный SVG на целевой холст.Вот гист с примером кода .

0 голосов
/ 26 января 2012

После того, как вы зафиксировали свои линии на холсте, вы можете смягчить (размыть) класс CanvasPixelArray. Это просто вопрос добавления вашего цвета к соседним пикселям. Вот хорошая информация о манипулировании пикселями .

0 голосов
/ 26 января 2012

Я вполне уверен, что это зависит от браузера, который вы используете.В последний раз я проверял (некоторое время назад - возможно, изменился) Firefox и Chrome не сглаживают края, в то время как IE9 делает.

...