转载 尚未验证
作为资深的开发者,相信大家对 Canvas 都不陌生。这项能力在绘制图形方面发挥着极大的作用,高效支持图片编辑、数据可视化等应用场景。但是只局限于一般能力应用,那格局就小了图片
Canvas 的应用场景非常丰富!赶紧往下看看这些隐藏的 Canvas 小技巧,保证你新年用得上!还有手把手教程以及文末彩蛋哟。
绘制并生成图片
适用场景:图片分享海报
相关 API:RenderingContext/Canvas/wx.canvasToTempFilePath
Step 1: 创建实例获取对象
创建 Canvas 实例,获取 CanvasRenderingContext2D 对象(Canvas 绘图上下文)来绘制形状、文本、图像等。
<!-- canvas 2d --> <canvas type="2d" id="myCanvas"></canvas>
const query = wx.createSelectorQuery() let canvas = null query.select('#myCanvas') .fields({ node: true, size: true }) .exec((res) => { // 通过 wx.createSelectorQuery 获取到 canvas 实例 canvas = res[0].node // 通过 canvas.getContext('2d') 获取 CanvasRenderingContext2D 对象 const ctx = canvas.getContext('2d') })
Step 2: 设置宽高调整图片
获取 Canvas 绘图上下文后,将 Canvas 的宽高设置为节点宽高 * 设备像素比,绘制出来的图片更清晰
// 获取设备像素比 const dpr = wx.getSystemInfoSync().pixelRatio // 将 canvas 宽高设置为 canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr
Step 3: 绘制内容
使用 CanvasRenderingContext2D 绘制,根据业务需要在画布中绘制头像、文字、背景等
// 矩形 ctx.fillStyle = '#FFFFFF' ctx.fillRect(0, 0, canvas.width , canvas.height ) // 图片 var image = canvas.createImage() himage.src = 'https://example.com/example.jpg' headImage.onload = (res) => { ctx.drawImage(himage 0, 0, 32, 32; } // 文本 ctx.font = "18px SimHei"; ctx.textAlgin = "left" ctx.fillStyle = "#07c160"; ctx.fillText("这是我的名字", 0, 0);
Step 4: 生成并保存本地
使用 wx.canvasToTempFilePath 将画布生成图片,wx.saveImageToPhotosAlbum 将图片保存到本地
wx.canvasToTempFilePath({ canvas: canvas, // canvas 实例 success(res) { // canvas 生成图片成功 wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(res) { // 保存成功 } }) } })
Video 绘制 Canvas / webgl
适用场景:制作 Video 滤镜、挑选 Video 封面等
相关 API:RenderingContext/Canvas
Step 1: 获取实例
通过 wx.createSelectorQuery 获取 VideoContext 实例
let video = null wx.createSelectorQuery().select('#video').context(res => { // 通过 wx.createSelectorQuery 获取 VideoContext 实例 video = res.context; })
Step 2: 绘制内容
获取 VideoContext 实例后,将 VideoContext 传递给 Canvas 进行绘制。开发者根据业务需求选择绘制类型:
Canvas 2d 写法:canvas.drawImage(video, …)
webgl 写法:gl.texImage2D(…, video)
<!-- canvas 2d --> <canvas type="2d" id="myCanvas"></canvas> <!-- canvas webgl --> <canvas type="webgl" id="webglCanvas"></canvas>
wx.createSelectorQuery().selectAll('#myCanvas,#webglCanvas').node(res => { const ctx = res[0].node.getContext('2d') const gl = res[1].node.getContext('webgl') setInterval(() => { // canvas 2d // 将 video 纹理对象传入 drawImage 进行绘制 ctx1.drawImage(video, 0, 0, w * dpr, h * dpr); // 添加一个蒙层 ctx1.fillStyle = 'rgba(0, 0, 0, 0.3)' ctx1.fillRect(0, 0, w * dpr, h * dpr); // webgl const render = createRenderer(res[1].node, w, h) render(new Uint8Array(ctx1.getImageData(0, 0, w * dpr, h * dpr).data), w * dpr, h * dpr) }, 1000 / 24) }).exec() function createRenderer(canvas, width, height) { const gl = canvas.getContext("webgl") ... return (arrayBuffer, width, height) => { ... // 指定二维纹理图像 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBuffer) gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0) } }
视频解码并绘制到 webgl
适用场景:添加特效、贴图等视频编辑场景
相关 API:wx.createVideoDecoder/VideoDecoder/RenderingContext/Canvas.requestAnimationFrame/wx.createMediaAudioPlayer/MediaAudioPlayer
Step 1: 创建视频解码器进行解码
1. 调用 createVideoDecoder 对视频进行解码
2. 使用 videodecoder.start 启动解码,视频源文件不限制本地或远程路径
3. 通过 videodecoder.on(‘start’, res => {}) 监听解码,通过 videodecoder.getFrameData() 获取到解码数据
// 获取视频解码器 getVideoDecoder(source, abortAudio) { return new Promise((resolve, reject) => { // 创建视频解码器 videodecoder = wx.createVideoDecoder() // 开始解码 videodecoder.start({ abortAudio: abortAudio, source: source, // 视频源文件,支持本地路径&远程路径 mode: 0 // 按pts解码,保证音画同步 }) // 监听解码 开始 videodecoder.on('start', res => { console.log('videodecoder start', res) // 状态初始化 isStop = false resolve(videodecoder) }) // 监听解码 结束 videodecoder.on('ended', res => { // 状态设置为结束,停止画面录制器 isStop = true }) }) },
Step 2: 解码数据绘制到 webgl
1. 通过 gl.texImage2D(…, image) 将解码数据绘制到 webgl
2. 使用 webgl.requestAnimationFrame 继续绘制,效果更加流畅
<!-- canvas webgl --> <canvas type="webgl" id="webglCanvas"></canvas>
// 将解码数据绘制到 webgl 中 const query = wx.createSelectorQuery() query.select('#webglCanvas').node().exec((res) => { const webgl = res[0].node const requestAnimationFrame = webgl.requestAnimationFrame; // 初始化webgl let render = null if (!render) { render = createRenderer(webgl, 600, 400) } /** * 绘制视频帧到 canvas */ let i = 1 let loop = () => { // 解码结束,停止循环 if (isStop) { return } // 获取解码数据,绘制到 webgl 中 const imageData = videodecoder.getFrameData() if (imageData) { // render 的高宽需要设置为图片的宽高才可以绘制出来 render(new Uint8Array(imageData.data), imageData.width, imageData.height) } // 继续绘制 console.log('绘制帧数:', i++) requestAnimationFrame(loop) } // 启动录制循环 requestAnimationFrame(loop) })
Step 3: 添加音频播放器同步播放音频
完成 Step2 后,webgl 只有视频播放,缺少音频。因此使用 wx.createMediaAudioPlayer(),支持 addAudioSource 传入 videodecoder,保证视频帧渲染音画同步
/** * 创建媒体音频播放器 */ let mediaAudioPlayer = null let addAudio = () => { if (mediaAudioPlayer) return mediaAudioPlayer = wx.createMediaAudioPlayer() mediaAudioPlayer.start().then(() => { // 添加播放器音频来源 mediaAudioPlayer.addAudioSource(videodecoder).then(res => { console.log('add mediaAudioPlayer: ',) }) }) } // render 绘制视频同时添加音频 render(new Uint8Array(imageData.data), imageData.width, imageData.height) addAudio()
录制并导出 webgl 视频
适用场景:将动画、编辑过的视频导出视频文件保存
相关 API:wx.createMediaRecorder/MediaRecorder/wx.createMediaContainer/MediaContainer/MediaTrack
Step 1: 创建 webgl 画面录制器进行录制
通过 createMediaRecorder 创建页面录制器,并且绑定 webgl(建议离屏状态,效果更好)进行录制
/** * 获取画面录制器 */ getRecorder() { let canvas = this.getMainCanvasNode() let recorder = wx.createMediaRecorder(canvas, { fps: choosedVideoInfo.fps, // 实际视频的 fps videoBitsPerSecond: choosedVideoInfo.bitrate, // 实际视频的 bitrate gop: 12 }) // 监听录制事件 recorder.on("timeupdate", (res) => { console.log('recorder 录制中,当前时间:', res.currentTime) }) recorder.on("stop", (res) => { console.log('recorder停止') this.saveMedia(res.tempFilePath) }) // 开始录制 recorder.start() this.recorder = recorder return recorder }, // 初始化 画面录制器 并进行录制 await this.initRenderer() this.getDecoder().then((decoder) => { let recorder = this.getRecorder() var self = this function loop() { if (self.stopped) { return } let frameData = decoder.getFrameData() if (!frameData) { console.log('没取到帧') setTimeout(() => { loop() }, 1000/60) } else { self.renderFrame(frameData) recorder.requestFrame(() => { console.log('录制帧数:', i++) loop() }) } } loop() })
Step 2: 添加音频合成音视频
1. 通过 createMediaContainer 创建音视频处理容器来合成音视频
2. 通过 MediaContainer.extractDataSource 将视频源分离出视频轨道和音频轨道,将需要的轨道通过 MediaContainer.addTrack 添加到容器中
3. 通过 MediaContainer.export 导出即可获得合成后的视频文件
/** * 将视频和音频合到一起并保存到本地 * @param {*} videoTempFilePath */ saveMedia(videoTempFilePath) { const self = this let choosedFile = this.choosedFile const MediaContainer = wx.createMediaContainer() // webgl的取视频 MediaContainer.extractDataSource({ source: videoTempFilePath, success(res) { MediaContainer.addTrack(res.tracks[0]) // 源视频取音频 MediaContainer.extractDataSource({ source: choosedFile, success(res) { // 拿到音频轨道并加入到容器 res.tracks[0].kind == 'audio' && MediaContainer.addTrack(res.tracks[0]) res.tracks[1].kind == 'audio' && MediaContainer.addTrack(res.tracks[1]) // 合成视频并导出视频文件 MediaContainer.export({ success(res) { // 保存视频到本地 wx.saveVideoToPhotosAlbum({ filePath: res.tempFilePath, success() { wx.showToast({ title: '导出成功', icon: 'success', duration: 2000 }) self.destroy() } }) } }) } }) } }) },
本文由 猫斯基 转载发布。
转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。本网转载其他媒体之稿件,意在为公共提供免费服务。如稿件版权单位或个人不想再本网发布,可与本网联系,核实后将立即将其删除。 本文地址:https://www.maosiji.com/2925.html
转载地址:微信、