视频转gif需求全流程分析✨
1. 背景
基本需求是这样的,在一个固定宽高的视频播放器中截取一块区域,选择视频的开始和结束位置,设置帧率、速度、预览等信息转成GIF。
2.分析
首先我们先确定是前端转gif还是后端转,然后具体问题具体分析,我们采用的是后端转gif,需要传给后端视频源、截取的开始,结束时间、缩放后的x,y值、截取框的宽高、帧率、速度等信息。
分析难点!
- 传参最复杂的就是计算比例,视频源可能是1080也可能720等等视频原始尺寸,放到视频播放器中会按照长或宽等比缩放。宽高比不同的话,如果是竖屏视频会有左右黑边,横屏会有上下黑边。所以要算出蒙版层mask的缩放比例,才能拿到真实的x,y值
- 视频截取框需要能拖拽,截选区域为透明色,四周为黑灰色,可截选区域为去除左右黑边或者上下黑边后的真实播放区域
设计效果比如这是左右黑边,还有横屏的上线黑边
3.实现
难点一,通过分析宽高比,播放器宽度/视频宽度 = 缩放比,用这个缩放比乘原视频高度,如果小于播放器高度则是上下留有黑边,反之则是左右有黑边,等比的话就是刚好与播放器比例一致。算出的缩放比例ratio,再把这个比例用于蒙版层mask。
3.1难点一 核心代码
<my-video-player>...播放器代码省略</my-video-player>
<div class="mask">
...拖拽代码
</div>
// 860 490是播放器宽高
let l = document.getElementsByClassName('mask')[0] // 蒙版层,放在视频播放器上
let ratio = 860 / this.originalWidth // originalWidth 原视频宽度 originalHeight 原视频高度
l.style.transformOrigin = '0 0'
if (ratio * this.originalHeight < 490) { // 上下黑边
this.radio = 860 / this.originalWidth
} else if (ratio * this.originalHeight > 490) { // 上下左右
this.radio = 490 / this.originalHeight
} else { // 等比
this.radio = 490 / this.originalHeight
}
l.style.transform = `scale(${this.radio})` // 缩放比
3.1难点二 核心代码
这里用了vue-draggable-resizable包来实现可拖拽框,在难点一中我们拿到了radio,接下来计算拖拽框的可移动区域,以及初始值
let initXY = this.calculateCanvasImageParam(this.originalWidth, this.originalHeight)
calculateCanvasImageParam(videoWidth, videoHeight) {
let height = 490
let width = 860
if (videoWidth === 0 || videoHeight === 0) {
return {
x: 0,
y: 0,
width: width,
height: height
}
}
// 计算比例
if (videoHeight / videoWidth > (height / width)) {
const realW = height * videoWidth / videoHeight
return {
x: (width - realW) / 2,
y: 0,
width: realW,
height: height
}
} else {
const realH = width * videoHeight / videoWidth
return {
x: 0,
y: (height - realH) / 2,
width: width,
height: realH
}
}
}
这样initXY这个对象里的,x、y就是传入vue-draggable-resizable组件的初始x、y值
<div class="mask">
<vue-draggable-resizable
:w="width"
:h="height"
:x="x"
:y="y"
@dragging="onDrag"
@resizing="onResize"
:parent="true"
class="innerCheck"
:scale='radio'>
</vue-draggable-resizable>
</div>
接下来就是截图效果的实现,这里我们用了css属性mix-blend-mode,他是用来控制元素的混合模式,可以混合叠加产生不一样的效果,我们先来看看兼容性 还不错,没多少用户还在用IE吧,贴代码:
.mask {
position: absolute;
opacity: .9;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
mix-blend-mode: hard-light;
pointer-events: auto;
.innerCheck {
border: 3px solid #FC4F08;
//top: 50px;
//left: 50px;
background-color: gray;
.dingwei {
...
}
.dingwei2 {
...
}
.dingwei3 {
...
}
.dingwei4 {
...
}
}
}
之前项目离职不在上家公司环境打不开了,实现的效果类似这样:
四周黑灰色,中间透明可拖拽
鄙人文笔有限,写的代码也许还不够优雅,见谅啦