本文原创:huanghaijin
项目背景
用户通过上传合适尺寸的图片,选着渲染动画的效果和音乐,可以预览类似幻灯片的效果,最后点击确认生成视频,可以放到头条或者抖音播放。
生成视频可能的方案
-
纯前端的视频编码转换(例如WebM Encoder Whammy)
-
图片地址只能是相对地址
-
音乐不能收录
-
生成的视频需要下载再上传
-
-
将每帧图片传给后端实现,由后端调用FFmpeg进行视频转码
-
截图多的时候,base64字符串形式的图片太大,在前端不好传给后端
-
在前端截图还依赖用户电脑性能;
-
最后定的方案流程
-
canvas动画和截图在服务器端运行,后端根据标识获取截图
-
利用FFmpeg将图片合并成视频,并将视频存储在server端,并返回相应下载url
-
前端通过请求得到视频文件
前端canvas如何截图
每帧图片生成
图片生成可以通过canvas原生接口toDataURL实现,最终返回base64形式的图像数据
function generatePng() {
var canvas = document.createElement('canvas');
let icavas = '#canvas' //渲染动画的canvas id
if (wrapWidth == 2) {
icavas = '#verticalCanvas'
}
var canvasNode = document.querySelector(icavas)
canvas.width = canvasNode.width;
canvas.height = canvasNode.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(canvasNode, 0, 0);
var imgData = canvas.toDataURL("image/png");
return imgData;
}
复制代码
canvas动画截图的方法
用setInterval定时执行图片生成的方法,当然也可以用requestAnimationFrame
setInterval(function() {
imgsTemp.push(generatePng())
}, 1000/60)
复制代码
后端如何获取每帧图片
方案一:无头浏览器运行前端canvas动画js,然后js截图
- 最初设想:
截图用console.log打印出来,canvas截图是base64格式的,一个15秒的动画,截图有100多张,直接导致服务器运行崩溃(被否了);
- 试运行方案:
截图存储在js变量中,动画播放完成,在页面中加一个标识,然后后端去取这个变量,代码如下:
const pages = {
imageZoomOut: import ('./image_zoom_inout.js'), //缩放
imageArt: import ('./image_art.js'), //擦除
imageGrid: import ('./image_grid.js'), //网格
imageRotate: import ('./image_rotate.js'), //开合
imageFlash: import ('./image_flash.js'), //图文快闪
imageVerticalArt: import ('./image_vertical_art.js'), //竖版擦除
imageVerticalGrid: import ('./image_vertical_grid.js'), //竖版网格
imageVerticalRotate: import ('./image_vertical_rotate.js'), //竖版开合
imageVerticalFlash: import ('./image_vertical_flash.js'), //竖版图文快闪
imageVerticalZoomOut: import ('./image_vertical_zoom_inout.js&#