通过canvas实现视频截图并且生成图片上传到网络

<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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值