最近在自己的小程序实现视频转gif的功能,开发过程中发现网上的很多方案在小程序中实现效果不好或不能实现,比如:
使用前端canvas方案实现的(gif.js,gifshot.js等),在h5上效果没问题,但是在小程序中获取数据的时候极慢;
后来就转而使用uniCloud的云函数方式实现,即使用node.js实现。node.js使用node-canvas后端生成gif,这个是可以的,但是uniCloud使用的服务器node版本自己无法升级,导致想要发布,就只能放弃这个方案。
自己研究了很久,最终使用前端canvas按间隔时间截取一组图片,然后上传到uniCloud,再通过node的gif-encoder
,get-pixels
等第三方包在云服务端将图片合成gif文件,上传到服务器,就可以在小程序将文件下载到本地了。
实现该功能分两步,第一步是将视频按时间间隔截取图片;第二部:将视频按顺序拼接成gif图,并保存导出。本文章先介绍如何在前段将视频画面截图。
云函数node.js 将多图合成gif的代码和思路参考:
视频转gif(二):后端,云函数nodejs实现多图转gif
获取video元素,作为参数传给ctx.drawImage(video,)
,setInterval
每间隔一段时间截图画面。
// 获取canvas
const getCanvasNode = (id, instance) => {
const query = uni.createSelectorQuery().in(instance);
const queryCvs = query.select(`#${id}`).node();
return new Promise((resolve, reject) => {
queryCvs.exec(res => {
resolve(res);
});
});
}
// 获取video节点
const getVideoContext = (id, instance) => {
const query = uni.createSelectorQuery().in(instance);
const queryVideo = query.select(`#${id}`).context();
return new Promise((resolve, reject) => {
queryVideo.exec(res => {
resolve(res);
});
});
}
async drawNative() {
const { width, height, duration } = this.videoInfo; // 实现获取到的视频的信息
// 获取video元素和canvas元素(这里是uniapp 实现,网页版可用getElementById获取)
const videoRes = await getVideoContext('video-play', this);
const video = videoRes[0].context;
const canvasRes = await getCanvasNode('cas-item', this);
const canvas = canvasRes[0].node;
// 改变canvas的尺寸,适配横屏视频和 竖屏视频
canvas.width = this.cvsWidth.replace('rpx', '')
canvas.height = this.cvsHeight.replace('rpx', '')
const ctx = canvas.getContext('2d');
// 截取视频的张数
this.intTime = duration * 20; // 每个多少毫秒截取 2s-> 40 3s -> 60 5s -> 100
let computedLen = Math.ceil((duration * 1000) / this.intTime); // 计算可截取的数量
const imgNameDate = Date.now(); // 用与命名截取的图片
try {
this.timer = setInterval(async () => {
// 微信开发工具里canvas不会动,但是真机可以
if (computedLen < 1) {
clearInterval(this.timer);
// 截取完成,将图片上传到存储
this.uploadToOssTmp();
return;
}
// 使用canvas context drawImage将视频画面绘制到画布
ctx.drawImage(video, 0, 0, width, height, 0, 0, canvas.width, canvas.height);
// 从canvas获取图片像素数据
const imgData = canvas.toDataURL('image/png', this.qualityVal);
// genImg将imgData转换为图片base64并保存
computedLen >= 1 && this.genImg(imgData, imgNameDate, computedLen);
computedLen--;
}, this.intTime);
} catch (err) {
}
},
// 图片像素数据转base6并保存
async genImg(imgData, name, count, loading) {
const fm = wx.getFileSystemManager();
let filePath = `${this.baseTmpDirName}/${name}_${count}.png`;
this.imgBase64.push(imgData.split(',')[1]);
},
到此,视频转GIF的第一步就完成了,接下来就是要实现多张图片转为GIF的功能。
也欢迎,扫码体验一下,如有使用问题可以联系我(目前小程序云服务器未续费,导致无法正常使用20231218)