1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| function hex2rgb (hexStr) { const value = parseInt(hexStr.replace('#', ''), 16) const r = value >> 16 const g = value >> 8 & 0xff const b = value & 0xff return { r, g, b } }
let $canvas let $video let ctx let drawTimes = -1 let fullHeight = 0 const offscreenCvs = new OffscreenCanvas(0, 0) const offscreenCtx = offscreenCvs.getContext('2d')
window.$vm = new Vue({ el: '#app', data: function () { return { controls: true, video: { width: 200, height: 200, }, videoHeight: 0, ccForceShow: true, ccShow: false, ccShowTimer: -1, exportScale: 1, cc: { left: 0, top: 0, width: 0, height: 0, color: '#009688', }, fileName: '选择文件' } }, computed: { canvasStyle () { return { width: `${this.video.width * this.exportScale}px`, height: 'auto', } }, videoStyle () { return { width: `${this.video.width * this.exportScale}px`, height: `${this.video.height * this.exportScale}px`, } }, ccStyle () { return { left: `${this.cc.left * this.exportScale}px`, top: `${this.cc.top * this.exportScale}px`, width: `${this.cc.width * this.exportScale}px`, height: `${this.cc.height * this.exportScale}px`, backgroundColor: `${this.ccColor}`, } }, ccColor () { const rgb = hex2rgb(this.cc.color) return `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)` }, }, mounted () { $video = this.$refs.video $canvas = this.$refs.canvas ctx = $canvas.getContext('2d') }, methods: { onFileChange (e) { const $fileVideo = this.$refs.fileVideo const file = $fileVideo.files[0] this.fileName = file.name $video.src = URL.createObjectURL(file) }, onCcChange (e) { this.ccShow = true clearTimeout(this.ccShowTimer) this.ccShowTimer = setTimeout(() => { this.ccShow = false }, 1000)
}, onVideoMetaLoad () { const $video = this.$refs.video const videoWidth = Math.floor($video.videoWidth) const videoHeight = Math.floor($video.videoHeight) this.video = { width: videoWidth, height: videoHeight, } const ccHeight = 50 const ccLeft = 0 const ccWidth = Math.floor(videoWidth) const ccTop = videoHeight - ccHeight - 15 $canvas.width = videoWidth $canvas.height = videoHeight this.cc = { width: ccWidth, height: ccHeight, left: ccLeft, top: ccTop, color: this.cc.color, } drawTimes = 0 fullHeight = videoHeight this.exportScale = 1 }, drawVideo () { const video = this.video const cc = { left: Math.floor(this.cc.left), top: Math.floor(this.cc.top), width: Math.floor(this.cc.width), height: Math.floor(this.cc.height), } if (drawTimes === -1) { return alert('请先导入视频') } if (drawTimes === 0) { ctx.drawImage($video, 0, 0, video.width, video.height) drawTimes++ } else { const newHeight = fullHeight + cc.height offscreenCvs.width = video.width offscreenCvs.height = fullHeight offscreenCtx.drawImage($canvas, 0, 0, video.width, fullHeight) $canvas.height = newHeight ctx.drawImage(offscreenCvs, 0, 0, video.width, fullHeight) createImageBitmap($video, cc.left, cc.top, cc.width, cc.height) .then(res => { ctx.drawImage(res, cc.left, fullHeight, cc.width, cc.height) fullHeight = newHeight drawTimes++ }) } }, } })
|