内容简介:博客地址先看一下效果,原视频是这样的。我们要实现的效果是这样子的。之所以找这个视频是因为...这个视频和背景的对比度比较高做出来比较有辨识度,没有其他的意思 ( *・ω・)✄╰ひ╯某天一个基友在群里问我,在抖音看到一种视频,问我是不是能实现。我说可以的~ 于是当天晚上花了一个多小时折腾了一个粗糙版本...
博客地址 jsonz1993.github.io/2018/07/vid…
先看一下效果,原视频是这样的。我们要实现的效果是这样子的。之所以找这个视频是因为...这个视频和背景的对比度比较高做出来比较有辨识度,没有其他的意思 ( *・ω・)✄╰ひ╯
起因
某天一个基友在群里问我,在抖音看到一种视频,问我是不是能实现。我说可以的~ 于是当天晚上花了一个多小时折腾了一个粗糙版本...
先把视频丢到部门技术群问有没有关键字,给了一个keyword 图片转字符串 于是照着这个思路去gayhub找资源拼乐高!
整体思路
input[type="file"] URL.createObjectURL ctx.drawImage ctx.getImageData ctx.fillText video.currentTime
既然大概的思路已经理清,接下来就是具体的编码,把想法写出来的过程
具体编码实现
获取视频文件
首先我们先确定下html需要哪些元素
- 一个 input[type="file"] 用来给用户上传的
- 一个 video 用来承载上传的video
- 一个 canvas 用来展示最终的结果
大概是长这样:
<input type="file" id="inputFile" accept=".mp4" /> <canvas id="canvasShow"></canvas> <video id="video"></video> 复制代码
接下来js文件,我们要先对 input 绑定个监听事件,拿到文件url之后设置给video
这里要注意两点,一个是 url
用完不用的话,用 URL.revokeObjectURL
释放资源; 一个是我们这里用了 await
在domVide.onCanplay之前不做任何操作,防止视频没有加载完就操作,有黑屏风险。
如果对 es6、es7、es8不熟悉的小伙伴要去补一下了~ 现在基本不会这些基本语法都看不懂demo= = 附上阮一峰老师的ES6教程,又想起面试被问ES7有什么新特性 简直是*了狗
domInput.addEventListener('change', async({target: {files }})=> { const file = files[0]; const url = URL.createObjectURL(file); domVideo.src = urlrl; await new Promise(res=> domVideo.addEventListener('canplay', res)); // next ====> handleVideoInit() }); 复制代码
将视频渲染到canvas
拿到视频之后,我们要把当前这一个时刻的图像渲染到canvas里面 先用 ctx.drawImage(video, 0, 0, width, height)
把video dom当前屏渲染进canvas
再用 ctx.getImageData(0, 0, width, height)
获取图片的色值来做处理
可以通过调整 img2Text
来选择渲染出来的图片是想要怎样的(由哪些字符组成等等)
比如把 textList改为 ['Aa', 'Bv', 'Cc', 'Dd', '#', '&', '@', '$', '*', '?', ';', '^', '·', '·', '·', '·'],辨识度会高一点
/* domVide => video元素 size => 存放video等元素的长宽 canvasVideo => 存放video当前的图像的canvas canvasShow => 存放最后展示效果的canvas */ const size = {w: 0, h: 0}; const canvasVideo = document.createElement('canvas'); function handleVideoInit() { domVideo.currentTime = 0; size.w = domVideo.width = canvasVideo.width = canvasShow.width = domVideo.videoWidth * .5; size.h = domVideo.height = canvasVideo.height = canvasShow.height = domVideo.videoHeight * .5; video2Img(); } function video2Img() { const { w, h } = size; ctxVideo.drawImage(domVideo, 0, 0, w, h); const { data } = ctxVideo.getImageData(0, 0, w, h); ctxShow.clearRect(0, 0, w, h); for (let _h= 0; _h< h; _h+= 8) { for (let _w= 0; _w< w; _w+= 8) { const index = (_w + w * _h) * 4; const r = data[index + 0]; const g = data[index + 1]; const b = data[index + 2]; const gray = .299 * r + .587 * g + .114 * b; ctxShow.fillText(img2Text(gray), _w, _h + 8); } } } function img2Text(g) { const i = g % 16 === 0 ? parseInt(g / 16) - 1 : parseInt(g/ 16); return ['#', '&', '@', '%', '$', 'w', '*', '+', 'o', '?', '!', ';', '^', ',', '.', ' '][i]; } 复制代码
到这一步,其实已经实现了把一张图片变为字符填充图了,剩下的工作无非就是把视频变成一张张的图片,然后重复执行这些逻辑
持续调用渲染字符视频
我们改一下 video2Img 函数,将其实现为能持续调用的形式, 再添加一个函数 clear
用来清理垃圾
这里用到的是 window.requestAnimationFrame 去持续调用
function video2Img({ timePoint= 0, curT= Date.now(), prevT= Date.now(), prevInterval, }) { const { w, h } = size; ctxVideo.drawImage(domVideo, 0, 0, w, h); drawOnce(); let _interval = Math.max((curT - prevT), 16) / 1000; if (curT - prevT !== 0) _interval -= prevInterval; await new Promise(res=> setTimeout(res, _interval*1000)); const nextTimePoint = _interval + timePoint; if (nextTimePoint > domVideo.duration) return clear(); tId = window.requestAnimationFrame(()=> video2Img({ timePoint: nextTimePoint, prevT: curT, curT: Date.now(), prevInterval: _interval, })); } function drawOnce() { const { data } = ctxVideo.getImageData(0, 0, w, h); ctxShow.clearRect(0, 0, w, h); for (let _h= 0; _h< h; _h+= 8) { for (let _w= 0; _w< w; _w+= 8) { const index = (_w + w * _h) * 4; const r = data[index + 0]; const g = data[index + 1]; const b = data[index + 2]; const gray = .299 * r + .587 * g + .114 * b; ctxShow.fillText(img2Text(gray), _w, _h + 8); } } } function cleart() { const {w, h} = size; lastUrl && URL.revokeObjectURL(lastUrl); tId && window.cancelAnimationFrame(tId); ctxShow.clearRect(0, 0, w, h); ctxVideo.clearRect(0, 0, w, h); } 复制代码
源码与demo
至此,功能基本都实现了,下面提供在线的呆毛和github仓库地址~
pc端在线呆毛
github 源码
video转图片忘了是在github看哪个项目的, ctx.drawImage(video, 0, 0, width, height)
这个是看完才知道的。
图片转字符基本是看这个大哥的 github
在找方案的时候看到的一个像素图实现,挺有趣的,以前实现马赛克是拿周围像素值取平均去做,这个哥们是直接放大截图 更简单粗暴传送门
以上所述就是小编给大家介绍的《js视频转字符画 —— 写一个属于自己的字符转换器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SpringAMQP 消息转换器 - MessageConverter
- flask视图函数自定义转换器
- 原 荐 转换器(Converter)设计模式
- Mybatis使用小技巧-自定义类型转换器
- 深入理解 Kafka Connect:转换器和序列化
- OpenAPI Generator 4.0.3 发布,使转换器公开访问
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
UML用户指南
[美] Grady Booch、James Rumbaugh、Ivar Jacobson / 邵维忠、麻志毅、马浩海、刘辉 / 人民邮电出版社 / 2006-6 / 49.00元
《UML用户指南》(第2版)是UML方面最权威的一本著作,三位作者是面向对象方法最早的倡导者,是UML的创始人。本版涵盖了UML 2.0。书中为具体的UML特征提供了参考,描述了一个使用UML进行开发的过程,旨在让读者掌握UML的术语、规则和语言特点,以及如何有效地使用这种语言,知道如何应用UML去解决一些常见的建模问题。《UML用户指南》(第2版)由7个部分组成,而且每章都描述了一个特定UML特......一起来看看 《UML用户指南》 这本书的介绍吧!