gpt4 book ai didi

html - 在 HTML5 Canvas 上模仿 photoshop/painter 平滑绘制?

转载 作者:可可西里 更新时间:2023-11-01 13:35:28 26 4
gpt4 key购买 nike

很多人都知道,HTML5 Canvas lineTo() 会在每个角处给您一条锯齿状的线。在这一点上,更可取的解决方案是实现 quadraticCurveTo(),这是生成平滑绘图的一种非常好的方法。但是,我希望在 Canvas HTML5 上创建流畅而准确的绘图。二次曲线方法在平滑绘图方面效果很好,但它不会遍历所有样本点。换句话说,当我尝试使用二次曲线绘制快速曲线时,有时曲线似乎被应用程序“修正”了。一些线段没有按照我的绘图路径弯曲,而是从其原始路径弯曲以遵循二次曲线。

我的应用程序旨在用于在 HTML5 canvas 上进行专业绘图,因此绘图的流畅性和精确性非常重要。我不确定通过尝试将 HTML5 Canvas 与 photoshop 或任何其他画家应用程序(SAI、painterX 等)放在同一水平上,我是否在要求不可能

谢谢

最佳答案

你想要的是一个Cardinal spline当基数样条曲线穿过您绘制的实际点时。

注意:要获得专业的结果,您还需要对较短的阈值执行移动平均,而对较大的阈值使用基数样条,并使用拐点值在尖角处打断线条,这样您就不会平滑整条线条。我不会在这里讨论移动平均线或拐点(也不是锥度),因为它们超出了范围,但会展示一种使用基数样条的方法。

还有一个旁注 - 应用程序似乎修改线条的效果是不可避免的,因为平滑发生在后期。存在可以在您绘制时平滑的算法,但它们不会保留拐点值,并且在您绘制时线条似乎“摆动”。我想这是一个偏好问题。

这是一个演示以下内容的 fiddle :
ONLINE DEMO

首先是一些先决条件(我正在使用我的 easyCanvas 库在演示中设置环境,因为它节省了我很多工作,但这不是此解决方案工作的必要条件):

  • 我建议您将新笔画绘制到位于主 Canvas 之上的单独 Canvas 上。
  • 笔划完成后(鼠标悬停)将其通过平滑器并将其存储在笔划堆栈中。
  • 然后将平滑的线画到主线上。

当你的数组中的点按 X/Y 排序时(即 [x1, y1, x2, y2, ... xn, yn]),那么你可以使用这个函数来平滑它:

张力 值(ts,默认值 0.5)使曲线平滑。数字越大,曲线越圆。您可以在正常区间 [0, 1] 之外进行 curl 。

(nos,或段数)是每个点之间的分辨率。在大多数情况下,您可能不需要高于 9-10。但在速度较慢的计算机上或绘制速度较快的地方,需要更高的值。

函数(优化):

/// cardinal spline by Ken Fyrstenberg, CC-attribute
function smoothCurve(pts, ts, nos) {

// use input value if provided, or use a default value
ts = (typeof ts === 'undefined') ? 0.5 : ts;
nos = (typeof nos === 'undefined') ? 16 : nos;

var _pts = [], res = [], // clone array
x, y, // our x,y coords
t1x, t2x, t1y, t2y, // tension vectors
c1, c2, c3, c4, // cardinal points
st, st2, st3, st23, st32, // steps
t, i, r = 0,
len = pts.length,
pt1, pt2, pt3, pt4;

_pts.push(pts[0]); //copy 1. point and insert at beginning
_pts.push(pts[1]);

_pts = _pts.concat(pts);

_pts.push(pts[len - 2]); //copy last point and append
_pts.push(pts[len - 1]);

for (i = 2; i < len; i+=2) {

pt1 = _pts[i];
pt2 = _pts[i+1];
pt3 = _pts[i+2];
pt4 = _pts[i+3];

t1x = (pt3 - _pts[i-2]) * ts;
t2x = (_pts[i+4] - pt1) * ts;

t1y = (pt4 - _pts[i-1]) * ts;
t2y = (_pts[i+5] - pt2) * ts;

for (t = 0; t <= nos; t++) {

// pre-calc steps
st = t / nos;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;

// calc cardinals
c1 = st23 - st32 + 1;
c2 = st32 - st23;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;

res.push(c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x);
res.push(c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y);

} //for t
} //for i

return res;
}

然后在存储点后从 mouseup 事件简单地调用它:

stroke = smoothCurve(stroke, 0.5, 16);
strokes.push(stroke);

膝盖值的简短评论:

在此上下文中,拐点值是直线中各点(作为线段的一部分)之间的角度大于某个阈值(通常在 45 - 60 度之间)的位置。当发生拐点时,线条会被分成一条新线,以便仅使用由点之间的角度小于阈值的点组成的线(由于不使用拐点,您会在演示中看到小 curl )。

关于移动平均线的简短评论:

Moving average通常用于统计目的,但对于绘图应用程序也非常有用。当你有一个由许多点组成的集群,它们之间的距离很短时,样条曲线就不能很好地工作。所以这里可以使用MA来平滑点。

还有一些可以使用的减分算法,例如 Ramer/Douglas/Peucker一个,但它更多地用于存储目的以减少数据量。

关于html - 在 HTML5 Canvas 上模仿 photoshop/painter 平滑绘制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17877276/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com