<template>
<div>
<div class="fengmian" @click="showCoverDialog">
<i class="ivu-icon ivu-icon-ios-camera" style="font-size: 20px;" />
</div>
<el-dialog
append-to-body
modal-append-to-body
:visible.sync="coverDialog"
width="800px"
top="0"
:close-on-click-modal="false"
>
<el-tabs v-model="activeName" class="cut-cover-tab">
<el-tab-pane label="截取封面" name="first" class="cut-cover">
<video
id="video"
crossOrigin="anonymous" /* 必须加这个 为了解决跨域 */
:src="this.$store.state.user.asset + video"
controls
style="width:320px;height:530px;"
></video>
<div>
<img id="image" style=" margin: 23px 10px 0 10px;"/>
</div>
<div>
<el-button type="primary" size="small" @click="cutPicture">点我截图</el-button>
</div>
<canvas id="myCanvas" width="320" height="530"></canvas>
</el-tab-pane>
<el-tab-pane label="本地上传" name="second">
<upload-only
class="upload-only"
@on-change="changeImage"
:imgList="image"
></upload-only>
</el-tab-pane>
</el-tabs>
<div slot="footer">
<el-button type="primary" @click="makeSure" :disabled="disabled">
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import uploadOnly from '_c/upload-only'
import { getQiniuToken } from '@/api/commen'
import axios from 'axios'
export default {
data () {
return {
coverDialog: false,
activeName: 'first',
direction: '',
image: '',
upToken: '',
dataURL: '',
disabled: false
}
},
props: {
video: {
type: String,
default: ''
},
title: {
type: String,
default: ''
}
},
components: {
uploadOnly
},
mounted () {
// 这里我把编辑好的图片上传到了第三方平台 所以需要token
getQiniuToken()
.then(res => {
this.upToken = res.data.token
})
.catch(() => {
this.$message.error('失败')
})
// 根据图片尺寸信息来判断图片应该横屏显示还是竖屏显示
axios({
method: 'get',
url: `${this.$store.state.user.asset}${this.video}?avinfo`
}).then(res => {
const width = res.data.streams[0].width
const height = res.data.streams[0].height
if (width > height) {
this.direction = 'landscape'
} else {
this.direction = 'portrait'
}
})
},
watch: {
video: {
handler (v) {
if (!v) return
axios({
method: 'get',
url: `${this.$store.state.user.asset}${v}?avinfo`
}).then(res => {
const width = res.data.streams[0].width
const height = res.data.streams[0].height
if (width > height) {
this.direction = 'landscape'
} else {
this.direction = 'portrait'
}
})
}
}
},
methods: {
showCoverDialog () {
this.$nextTick(() => {
if (!this.video) {
this.$message.error('请先上传视频')
return
}
if (!this.title) {
this.$message.error('请填写标题')
return
}
const length = this.title.length
if (
length < 8 ||
length > 30
) {
this.$message.error('标题字数总长度应在8~30字之间')
return
}
this.coverDialog = true
this.dataURL = ''
})
},
changeImage (val) {
this.image = val
},
// 截取当前帧的图片
cutPicture () {
var v = document.getElementById('video')
const canvas = document.getElementById('myCanvas')
var ctx = canvas.getContext('2d')
canvas.width = 320
canvas.height = 530
if (this.direction === 'landscape') {
CanvasRenderingContext2D.prototype.wrapText = function ( // 长文本
text,
x,
y,
maxWidth,
lineHeight
) {
if (
typeof text !== 'string' ||
typeof x !== 'number' ||
typeof y !== 'number'
) {
return
}
var context = this
var canvas = context.canvas
if (typeof maxWidth === 'undefined') {
maxWidth = (canvas && canvas.width) || 300
}
if (typeof lineHeight === 'undefined') {
lineHeight =
(canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) ||
parseInt(window.getComputedStyle(document.body).lineHeight)
}
// 字符分隔为数组
var arrText = text.split('')
var line = ''
for (var n = 0; n < arrText.length; n++) {
var testLine = line + arrText[n]
var metrics = context.measureText(testLine)
var testWidth = metrics.width
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y)
line = arrText[n]
y += lineHeight
} else {
line = testLine
}
}
context.fillText(line, x, y)
}
ctx.fillStyle = '#000000'
ctx.fillRect(0, 0, 320, 530)
ctx.fillStyle = '#FEE20F'
ctx.font = 'bold 24px 微软雅黑'
ctx.textAlign = 'center'
ctx.wrapText(this.title, 320 / 2, 110, 240, 24)
ctx.drawImage(v, 0, 175, 320, 190)
this.dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
} else {
ctx.fillStyle = '#ffffff'
ctx.drawImage(v, 0, 0, 320, 530)
this.dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
}
},
makeSure () {
if (this.activeName === 'first') {
this.disabled = true
var canvas = document.getElementById('myCanvas')
var img64 = canvas.toDataURL('image/png', 0.1)
if (!this.dataURL) {
this.$message.error('请截取图片')
return
}
this.uploadQiniu(img64)
} else {
if (!this.image) {
this.$message.error('请上传图片')
return
}
this.$emit('changeCover', this.image)
this.coverDialog = false
}
},
uploadQiniu (pic) {
const img = pic.split(',')
const picNew = img[1]
var url = '七牛地址' // 非华东空间需要根据注意事项 1 修改上传域名
var xhr = new XMLHttpRequest()
const _self = this
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
const Text = JSON.parse(xhr.responseText)
_self.$emit('changeCover', _self.$store.state.user.assetUrl + Text.hash)
_self.disabled = false
_self.coverDialog = false
}
}
xhr.open('POST', url, true)
xhr.setRequestHeader('Content-Type', 'application/octet-stream')
xhr.setRequestHeader('Authorization', 'UpToken ' + this.upToken)
xhr.send(picNew)
}
}
}
</script>
<style lang='less' scoped>
.fengmian {
width: 100px;
height: 80px;
line-height: 80px;
border: 1px dashed #dcdee2;
text-align: center;
cursor: pointer;
&:hover {
border-color: #409EFF;
}
}
.cut-cover {
display: flex;
justify-content: space-between;
align-items: center;
}
.cut-cover-tab {
.upload-only {
width: 80px;
height: 90px;
margin-left: 45%;
}
}
</style>
通过canvas实现视频截图并且生成图片上传到网络
于 2022-10-25 17:02:30 首次发布