为什么突然会去做这件事,主要是最近接了一个需求?就是3D文字的开发,由于我们是2d和3d都是需要的,所以解决思路就是通过font-to-svg, 然后去npm 和github 上大概搜索了两天吧, 搜索到了搜索到了npm最流行的库叫text-tosvg, 它支持将多种文字转换成svg。然后又去翻看了 他这个库的源码, 原来他其实是纸老虎哇, 就是他也是依赖的第三库,当时也没有发现他有多厉害啊,然后我又去搜索了一个谷歌的一个也是 转svg,但是他好像不支持中文。网页截图给大家看下:
地址在这里:danmarshall.github.io/google-font…
然后又去翻看他的源码: marker.js依赖的其实是opentype.js
opentype.js
这个库是真的牛皮,他支持解析font, 然后呢同样可以获得path 路径,有了path 路径我们是不是可以生成svg,然后呢,也就是我们任意输出的文字可以得到svg, 那现在问题就变成了将svg和我们的底图及进行合并,OK那这样我们就将两张图片合成一张图片。这时候我又去npm search 页面比较成熟的库。然后皇天不负有心人, 被我找到了。sharp我为什么选择他主要是官方对他的定义就是 高性能
然后呢我又去仔细研究了一下这个库,发现这个库真的牛皮,我可能只解锁了他的部分功能。我先給大家看下效果图吧。
这里的字体我选用的是阿里巴巴普惠体,毕竟他免费哇。 你可以使用任何字体的ttf 文件。 opentype.js 都是可以解析的下面我们看下代码:
const opentype = require('opentype.js')
const sharp = require('sharp')
let id = 1
async function getFont(size = 20) {
const font = await opentype.loadSync('../font/Alibaba-PuHuiTi-Bold.ttf')
const path = font.getPath('端午节快乐', 0, 30, size)
const svg = '<svg>' + path.toSVG(2) + '</svg>'
sharp(`${__dirname}/test.png`)
.resize(1303, 734)
.composite([
{
input: Buffer.from(svg),
},
])
.png()
.toFile(`${__dirname}/test${++id}.png`)
.catch((err) => {
console.log(err)
})
}
getFont(40)
复制代码
我还是解读一下这段代码。
第一行的话主要是加载我本地的ttf 文件, 注意一定要在node.js 环境下去执行,不要去浏览器去跑不然会报模块加载错误。 然后我们得到解析到的font 通过getpath() 这个方法就可以获得当前文字的path。 也是支持异步的 opentype.load (url)
Font.getPath(text, x, y, fontSize, options)
- 第一个参数主要是我们输入的文字
- x 代表的是什么呢 文字一开始的水平位置
- y 这个代表的是文字的基线位置, 这个还是非常有用的,如果设置不对他会导致生成的文字只有半截
- fontsize 代表的是文字大小
- options 就是一个可选项
sharp一个参数是原图像, resize就是控制生成图片大小的。
composite 就是合成图片, 这里要注意的svg 一定要用Buffer.from 去转义一下
png 就是图片转成png 的格式, tofile就是转成对应的文件。
说到这里很多人想问难道只支持黑色? 当然不可能, 我们可以对输入的path做处理是增加描边,填充色,描边大小哇。 都是可以的
path.fill = color
path.strokeWidth = strokeWidth
path.stroke = stroke
复制代码
看到这里很多人以为结束了,那你是远远低估了sharp这个库的威力,我先给大家看张图。
没错就是这种效果,这就AE文字扫光效果,我还特地问了专业人士, 就是令人十分惊讶和震撼哇。
其实呢我就加了一个参数
.composite([
{
input: Buffer.from(svg),
blend: 'dest-in',
},
])
复制代码
到这里本篇文章技术分享结束, 说句老实话还是非常有趣的。写完有的小伙伴就问我,这用css实现的文字遮罩有什么区别?
- 首先第一个不同的就是我提供的是生成一张图片
- 就是本篇文章主要是展示的多种字体转svg技术方案的分享,以后如果遇到了这个需求,大家可以参考
- 还有就是文字毕竟是2d的,如果想要在三维上渲染出来,其实也是要解析输入文字(three.js其实是不支持渲染中文的)的位置信息,也就是Svg中的path中的路线, 我将它一步步转成3d能够显示的线段,然后呢形成闭合的Mesh,最后生成gemotery, 这中间涉及到了2d点转3d技术。如果大家感兴趣的话,我可以专门写一篇文章来分享下three中如何实现3d文字。