Canvas 2D 基础
生成分享海报、给图片加文案、画签到卡片,这些场景都离不开 Canvas。新版小程序推荐用 Canvas 2D 接口,它在渲染性能和清晰度上都比旧版 canvas 组件好,写法也更接近浏览器标准。
页面里先放一个 canvas 节点,通过 type 属性声明 2d 类型,然后在脚本里用 SelectorQuery 拿到节点和画布上下文,就能开始画了。canvas-id 是旧接口的用法,新项目建议直接上 2d。
拿到上下文之后,绘制流程基本固定:先画背景,再贴图片,然后写字,最后整体导出。下面按这个顺序拆开讲。
- 画布Canvas 2D 创建与上下文。
- 绘制drawImage 与 fillText。
- 高清按像素比放大画布。
- 落地导出临时文件并保存相册。
绘制图片与文字
绘图上下文拿到手,先设画布尺寸和背景色,再用 drawImage 画图片、fillText 写文字。字号、颜色、对齐方式都要显式设置,避免真机上样式不一致。
const query = wx.createSelectorQuery();
query.select('#posterCanvas').fields({ node: true, size: true })
.exec(function (res) {
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
const dpr = wx.getWindowInfo().pixelRatio;
canvas.width = 375 * dpr;
canvas.height = 667 * dpr;
ctx.scale(dpr, dpr);
ctx.fillStyle = '#1b3a6b';
ctx.fillRect(0, 0, 375, 667);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 20px sans-serif';
ctx.fillText('吉极云码', 24, 60);
});
文字换行要自己处理:小程序没有现成的自动换行,写一个按字符宽度拆行的工具函数,遍历文案,累加测量宽度,超过画布宽度就换一行。
多行文字对齐也常见:左对齐、居中、两端对齐各写一个分支。海报里标题和正文的字号、行距分开配置,看起来才有层次。
网络图片先落地
Canvas 不能直接画网络地址的图片,必须先下载到本地临时文件再画。用 wx.getImageInfo 可以把网络图转成本地路径,同时拿到图片宽高,方便计算贴图的位置和尺寸。
wx.getImageInfo({
src: 'https://cdn.example.com/avatar.jpg',
success: function (res) {
const img = canvas.createImage();
img.src = res.path;
img.onload = function () {
ctx.drawImage(img, 24, 120, 120, 120);
};
}
});
头像、商品图这类图,最好先做一次服务端压缩,缩到海报需要的尺寸再下发,既省流量又省绘制时间。
图片域名要配进 downloadFile 合法域名,否则 getImageInfo 直接失败。本地图、临时文件路径可以直接画,不受域名限制。
另外,海报里要用的字体如果比较特殊,先确认设备上有没有。小程序 Canvas 只能用系统字体或已加载的字体,别在绘制时才临时下载字体,加载时序会打乱绘制流程。
高清输出不模糊
海报导出模糊,九成是画布尺寸没按像素比放大。逻辑尺寸 375 宽的画布,在 2 倍屏上导出前要把 canvas.width 设成 750,再 scale 一下上下文,画的内容才会以高清分辨率落盘。
| 屏幕像素比 | 画布逻辑宽 | 导出像素宽 |
|---|---|---|
| 1 | 375 | 375 |
| 2 | 375 | 750 |
| 3 | 375 | 1125 |
导出时用 wx.canvasToTempFilePath,可以指定输出图片的宽度高度和 fileType。导出 PNG 清晰但体积大,纯色多的海报用 JPEG 加质量参数更划算。
画布尺寸和导出尺寸保持一致,预览时用逻辑尺寸显示,导出时按物理像素出图,这样预览不占内存,成品又不糊。
高清海报的关键就一句:画布物理像素按像素比放大,导出前别缩放回去。
保存到相册
海报导出成临时文件之后,用 wx.saveImageToPhotosAlbum 存进相册。第一次调用会弹授权,用户拒绝之后再次调用会直接失败,所以要在设置页给一个手动开启入口。
保存成功要提示用户,失败要区分原因:拒绝授权引导去设置页,相册权限没开同样引导,文件太大失败就提示重试。用户点击保存按钮之前,最好先展示一张预览图,让用户确认内容再保存。
预览可以用临时文件路径直接渲染到 image 组件,确认后保存。整条链路:绘制、导出、预览、保存,四步各司其职,出错点都看得见。
海报内容如果是用户生成的,记得在绘制前把文案长度、敏感词都检查一遍。文案太长超出画布、或者包含违规内容,导出出来再返工就慢了。
常见 Canvas 坑
| 坑 | 现象 | 应对 |
|---|---|---|
| 导出空白 | 保存的图全透明 | 等图片 onload 完成再导出 |
| 真机字体不同 | 文字渲染不一致 | 用系统字体栈,别依赖本地字体 |
| 安卓画布偏移 | 内容被截或错位 | 设置 canvas 尺寸后重新 scale |
| 网络图画不上 | drawImage 无效果 | 先 getImageInfo 转本地路径 |
落地清单
- Canvas 2D 接口,按像素比放大画布。
- 网络图片先 getImageInfo 落地再画。
- 文字换行与对齐写成工具函数。
- 导出前确认图片全部加载完成。
- 保存相册带授权引导与失败兜底。
海报看着是画的,其实是排版工程:尺寸、字体、加载时序全对了,就不会糊。