主题
视频字符化特效
说明
使用 HTML5 Canvas 将视频每一帧的像素转换为字符,实现独特的视觉效果。
效果演示
实现原理
- 视频源:使用
<video>标签加载并播放视频(隐藏原始视频)。 - 画布绘制:使用
<canvas>获取视频的每一帧图像。 - 像素分析:
- 获取画布上的像素数据 (
getImageData)。 - 遍历像素点,计算灰度值或平均颜色。
- 获取画布上的像素数据 (
- 字符渲染:
- 清空画布。
- 根据像素位置和颜色,使用
fillText绘制字符(如 '8')。 - 使用
requestAnimationFrame循环执行,实现动画效果。
查看代码
vue
<template>
<div class="container" ref="boxRef">
<video
:muted="false"
autoplay
preload="true"
loop
x5-video-player-fullscreen="true"
x5-playsinline="true"
playsinline
webkit-playsinline="true"
crossorigin="anonymous"
ref="videoRef"
>
<source :src="videoSrc" />
</video>
<canvas ref="canvasRef"></canvas>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
videoSrc: {
type: String,
default: '',
},
})
const canvasWidth = 324
const canvasHeight = 570
let ctxRef = null
let frameId = 0
const boxRef = ref()
const videoRef = ref()
const canvasRef = ref()
const init = () => {
if (boxRef.value && videoRef.value && canvasRef.value) {
canvasRef.value.width = canvasWidth
canvasRef.value.height = canvasHeight
ctxRef = canvasRef.value.getContext('2d', {
willReadFrequently: true,
})
videoRef.value.crossOrigin = 'anonymous'
}
}
const play = () => {
if (videoRef.value && ctxRef) {
ctxRef.drawImage(videoRef.value, 0, 0, canvasWidth, canvasHeight)
const imageData = ctxRef.getImageData(0, 0, canvasWidth, canvasHeight)
ctxRef.clearRect(0, 0, canvasWidth, canvasHeight)
const { data, width, height } = imageData
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const startIndex = (y * width + x) * 4
if (x % 6 === 0 && y % 6 === 0) {
const avgColor = (data[startIndex] + data[startIndex + 1] + data[startIndex + 2]) / 3
ctxRef.fillStyle = `rgb(${avgColor}, ${avgColor}, ${avgColor})`
ctxRef.font = '10px Arial'
ctxRef.fillText('8', x, y)
}
}
}
frameId = window.requestAnimationFrame(play)
}
}
onMounted(() => {
init()
play()
})
onUnmounted(() => {
frameId && cancelAnimationFrame(frameId)
})
</script>
<style scoped lang="scss">
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
video {
position: absolute;
width: 324px;
height: 570px;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
visibility: hidden;
}
.tip {
margin-top: 20px;
color: #666;
}
}
</style>