坑这种东西, 踩起来是有瘾的~
最近遇到一个有意思的坑, 看起来简单的一个页面, 硬是让我加班到了晚上 11 点~ (前提: 19:00 开始遇坑)
废话不多说, 现在聊聊关于 canvas 写入文字, 图片的坑
需求:
在微信公众号上, 用户输入名字, 选择病假条模板, 生成图片, 用于保存和转发.
采用 .ttf 的第三方字体 (字体文件 4KB)
看似简单, 利用 html5 的画布功能 (canvas). 把图片和文字塞进去, 然后利用 toDataUrl 方法, 直接生成图片, 完美. demo 用了 10 分钟就做完了.
- var canvas = document.getElementById("canvas") // 获取 canvas 元素
- var imgObj = new Image() // new 一个图片对象
- imgObj.src = "images/logo.png" // 图片对象附上本地图片路径
- var ctx = canvas.getContext("2d") // 返回一个用于在画布上绘图的环境
- imgObj.onload = function() { // 本地图片加载完的回调
- ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
- canvas.toDataURL() // 把 canvas 的内容转成 base64 图片源文件
- }
但是谁能想到, 这里面涵盖了多少坑点~ 未来的自己, 你要好好看着, 再遇到就一定要绕行, 不要硬闯.
坑一
本地图片用 img 标签引入的时候, 清晰度非常不错, 但是引入到 canvas 中就特别模糊, 无法直视
坑一解决方案
- <!-- 坑 1.1 -->
- <canvas id="canvas" width="400%" height="400%" style="width: 100%; height: 100%;"></canvas>
- <!-- 上面这种方法能够让画面足够清晰, 但是在最后生成 base64 的时候, 图片尺寸是不正确的, 是一个正方形 -->
那该怎么办呢? 后来发现既然是这个百分比的问题, 那就只好附上实际的 px 值, 我是这么做的.
<canvas id="canvas" width="100%" height="100%" style="width: 100%; height: 100%;"></canvas>
然后在 js 部分给 canvas 定义宽高如下:
- // 这几句比较简单, 我就不做注释了
- var body_width = document.documentElement.clientWidth
- var body_height = document.documentElement.clientHeight
- var canvas = document.getElementById("canvas");
- canvas.width = body_width
- canvas.height = body_height
坑二
canvas 写入第三方字体文字, 依旧显示 微软雅黑
按照正常的字体加载方式写入
- @font-face {
- font-family: 'content';
- src: url('./font/contentSemibold.ttf');
- }
- .name {
- font-family: content;
- }
这样正常使用, 但是在进入页面的时候, 无法显示预期的字体
问题思路: 应该是字体样式加载的问题. 下面开始着手开始 找解决方案
坑二解决方案
网上给出了一些方案, 有配置兼容性的, 有获取字体加载完钩子回调的.. 等, 我一一做了尝试, 下面说说这些方法的结论.
第一种 利用 CSS 解决浏览器兼容性问题
- @font-face {
- font-family: 'SingleMaltaRegular';
- src: url('../fonts/singlemalta-webfont.eot');
- src: url('../fonts/singlemalta-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/singlemalta-webfont.woff') format('woff'),
- url('../fonts/singlemalta-webfont.ttf') format('truetype'),
- url('../fonts/singlemalta-webfont.svg#SingleMaltaRegular') format('svg');
- font-weight: normal;
- font-style: normal;
- }
- h2.singleMalta {
- font-family: 'SingleMaltaRegular'
- }
这个方法在相对低的浏览器版本中是可行的~ (没有做严格测试), 因为这次制作的 H5 手机页面, 亲测, 无须这些兼容写法.
第二种
这种方法是利用第三方字体加载的结束钩子.(方法忘记了, 下次补上)
总结
上面两种方法用起来真心不是很爽~
第三方字体加载是写在 css 文件中引入的, 有个坑的地方就是, 当你不调用这个字体时, 不加载字体库, 只有在调用的时候才加载. 当时我的这个字体库 4M, 服务器贷款 1M, 基本上时间都耗费在等待字体加载中. 基于这一点, 做出如下理解.
第一种方法: 在 canvas 的使用中无法顺利使用, 当 canvas 在首次插入文字的时候直接显示的是浏览器默认的字体样式, 只有在等到字体库加载完才能显示效果. 非常影响用户体验.
第二种方法: 利用字体加载钩子做处理. 这里需要多一个函数去做处理, 略显笨拙
推荐方法: 既然字体库的加载来自于文字内容的调用. 那么就可以按照这个思路去变相解决. 在 body 体中, 第一行添加任意一个标签 (div, p, span ...), 添加上任意文字, 样式字体设定为第三方的字体库. 最后把这个标签定位到可视区域以外的地方, 越远越好. 这样就能比较简单使用了. 希望能喜欢.
来源: http://www.qdfuns.com/article/15571/586770d28d722d9307c01686a44474ae.html