字玩FontPlayer开发笔记1 路径去除重叠功能的添加

字玩FontPlayer开发笔记1 路径去除重叠功能的添加

字玩FontPlayer是笔者开源的一款字体设计工具,使用Vue3 + ElementUI开发,源代码:
github: https://github.com/HiToysMaker/fontplayer
gitee: https://gitee.com/toysmaker/fontplayer

笔记

在中文字体设计中,笔者经常先设计笔画,然后再用几个笔画叠加在一起形成字形,最近发现这样直接导出,即使路径顺序都符合非零环绕规则,在部分软件中,还是会出现重叠部分镂空问题。参考了别的成熟软件,发现这个问题可以用合并路径的方式去除重叠。

paper.js提供了强大的对贝塞尔路径的布尔操作,笔者借助了paper.js帮我解决了这个问题。

具体去除重叠功能核心代码:

  // 读取字符轮廓信息(已经将形状都转换成字体轮廓)
  let contours: Array<Array<ILine | IQuadraticBezierCurve | ICubicBezierCurve>> = componentsToContours(orderedListWithItemsForCharacterFile(char), {
    unitsPerEm,
    descender,
    advanceWidth: unitsPerEm,
  }, { x: 0, y: 0 }, false, false, false)

  // 将轮廓转换成Path
  let paths = []
  for (let i = 0; i < contours.length; i++) {
    const contour = contours[i]
    let path = new paper.Path()
    path.moveTo(new paper.Point(contour[0].start.x, contour[0].start.y))
    for (let j = 0; j < contour.length; j++) {
      const _path = contour[j]
      if (_path.type === PathType.LINE) {
        path.lineTo(new paper.Point((_path as unknown as ILine).end.x, (_path as unknown as ILine).end.y))
      } else if (_path.type === PathType.CUBIC_BEZIER) {
        path.cubicCurveTo(
          new paper.Point(
            (_path as unknown as ICubicBezierCurve).control1.x,
            (_path as unknown as ICubicBezierCurve).control1.y,
          ),
          new paper.Point(
            (_path as unknown as ICubicBezierCurve).control2.x,
            (_path as unknown as ICubicBezierCurve).control2.y,
          ),
          new paper.Point(
            (_path as unknown as ICubicBezierCurve).end.x,
            (_path as unknown as ICubicBezierCurve).end.y,
          )
        )
      }
    }
    paths.push(path)
  }

  // 合并路径,去除重叠
  let unitedPath = null
  if (paths.length < 2) {
    unitedPath = paths[1]
  } else {
    unitedPath = paths[0].unite(paths[1])
    for (let i = 2; i < paths.length; i++) {
      unitedPath = unitedPath.unite(paths[i]) 
    }
  }

  // 根据合并路径生成轮廓数据
  let overlap_removed_contours = []
  for (let i = 0; i < unitedPath.children.length; i++) {
    const paths = unitedPath.children[i]
    if (!paths.curves.length) continue
    const contour = []
    for (let j = 0; j < paths.curves.length; j++) {
      const curve = paths.curves[j]
      const path = {
        type: PathType.CUBIC_BEZIER,
        start: { x: curve.points[0].x, y: curve.points[0].y },
        control1: { x: curve.points[1].x, y: curve.points[1].y },
        control2: { x: curve.points[2].x, y: curve.points[2].y },
        end: { x: curve.points[3].x, y: curve.points[3].y },
      }
      contour.push(path)
    }
    overlap_removed_contours.push(contour)
  }

  char.overlap_removed_contours = overlap_removed_contours

其中有一点令笔者不太满意,就是由于字玩自己的字形数据结构,和paper.js使用的数据结构差异较大,需要进行前后两次转换,耽误处理时间,这里以后看看要不要做优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值