├── js ├── index.js └── StringAnmt.js ├── index.html └── README.md /js/index.js: -------------------------------------------------------------------------------- 1 | var StrAnmt = new StringAnmt({ 2 | videoId: 'vdo', 3 | canvasId: 'cvs', 4 | }); 5 | StrAnmt.openCamera( 6 | 800, 7 | 600, 8 | false 9 | ) 10 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 搞事搞事 7 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## StringAnmt 2 | 一个在web开启你的摄像头,然后将视频处理成字符串的动画的简单封装库。   3 | 这里是[demo](https://Char-Ten.github.io/StringAnmt) 4 | --- 5 | * 快速使用: 6 | ```html 7 | 8 | 9 | 10 | 23 | ``` 24 | 25 | * `StringAnmt`参数说明 26 | * `videoId`:`video`标签的id; 27 | * `canvasId`:`canvas`标签的id; 28 | * `text`:想要渲染成动画的字符串或数组,从左到右是黑到白,不推荐字母、数字、汉字混编,尽量选用字符宽度差不多的字符,以免输出失真; 29 | * `fontSize`:字符大小,字符串类型; 30 | * `color`: 输出的字符颜色 31 | 32 | * `StringAnmt`方法: 33 | * `openCamera(width,height,isAudio)`:开启摄像头 34 | * `width`: 摄像头宽度 35 | * `height`: 摄像头高度 36 | * `isAudio`: 是否开启麦克风 37 | * `play()`:播放 38 | * `pause()`:暂停 39 | * `playAndPause()`:若是播放状态则暂停,若是暂停状态则播放(可用于截图) 40 | 41 | --- 42 | ## 注意事项, 43 | * 请放在本地或者https协议的服务器里,这样方能开启摄像头。 44 | * 请在高版本浏览器下使用 45 | * 不对ff做兼容 46 | * 拒绝IE,从我做起 47 | * 据了解,微信以及腾讯系的移动浏览器内核X5在读取视频流的时候有卡顿的bug 48 | * webGL版本请访问:[StringAnmt2](https://github.com/Char-Ten/webglLearningDemoes/tree/master/learnningWebSite/StringAnmt2),除X5内核外,其他兼容的移动端浏览器均可流畅跑webGL版本 49 | -------------------------------------------------------------------------------- /js/StringAnmt.js: -------------------------------------------------------------------------------- 1 | ; 2 | (function(root, fn) { 3 | if (typeof define === 'function' && define.amd) { 4 | define(fn); 5 | } else if (typeof exports === 'object') { 6 | module.exports = fn(); 7 | } else { 8 | root.StringAnmt = fn(); 9 | } 10 | })(this, function() { 11 | 12 | function Main(conf) { 13 | this.vdo = document.getElementById(conf.videoId); 14 | this.cvs = document.getElementById(conf.canvasId); 15 | this.text = conf.text || '丨一二三十上土王田正回困国囸昌晶'; 16 | this.fontSize = conf.fontSize || '10'; 17 | this.color = conf.color || '#0f0'; 18 | 19 | this.ctx = this.cvs.getContext('2d'); 20 | this.W = this.cvs.width = this.cvs.offsetWidth; 21 | this.H = this.cvs.height = this.cvs.offsetHeight; 22 | this.rowLen = parseInt(this.W / this.fontSize); 23 | this.colLen = parseInt(this.H / this.fontSize); 24 | this.isPlay = false; 25 | this.raf = null; 26 | try { 27 | this.raf = requestAnimationFrame || webkitRequestAnimationFrame; 28 | } catch (err) { 29 | alert('你的浏览器真需要去升级了,不然好多好玩的特性你根本玩不了。。。') 30 | } 31 | 32 | var self = this; 33 | this.vdo.addEventListener('play', function() { 34 | self.isPlay = true 35 | }); 36 | 37 | this._begin(); 38 | } 39 | Main.prototype = { 40 | constructor: Main, 41 | 42 | _AddText: function(gray) { 43 | var d = parseInt(256 / this.text.length); 44 | var i = parseInt(gray / d); 45 | if (i > this.text.length - 1) { 46 | i = this.text.length - 1; 47 | } 48 | return this.text[i]; 49 | }, 50 | _begin: function() { 51 | var self = this; 52 | var isPlay = this.isPlay; 53 | var raf = this.raf; 54 | 55 | this.ctx.font = '0px Arial'.replace('0', this.fontSize); 56 | this.ctx.fillStyle = this.color; 57 | loop(); 58 | 59 | function loop() { 60 | var isPlay=self.isPlay; 61 | if (isPlay) { 62 | var ctx = self.ctx; 63 | var W = self.W; 64 | var H = self.H; 65 | var colLen = self.colLen; 66 | var rowLen = self.rowLen; 67 | var fontSize = parseInt(self.fontSize); 68 | var text = self.text; 69 | var len = parseInt(256 / self.text.length); 70 | var gray, k; 71 | 72 | ctx.drawImage(self.vdo, 0, 0, W, H); 73 | try { 74 | var fm = ctx.getImageData(0, 0, W, H); 75 | } catch (err) { 76 | ctx.clearRect(0, 0, W, H); 77 | return 78 | } 79 | ctx.clearRect(0, 0, W, H); 80 | var data = fm.data; 81 | var str = ''; 82 | for (var j = 0; j < colLen; j++) { 83 | str = ''; 84 | for (var i = 0; i < rowLen; i++) { 85 | var index = (j * W + i) * fontSize; 86 | index *= 4; 87 | var gray = data[index] * 0.299 + data[index + 1] * 0.587 + data[index + 2] * 0.114; 88 | var k = parseInt(gray / len); 89 | if (k > len - 1) { 90 | k = len - 1; 91 | } 92 | str += text[k]; 93 | } 94 | ctx.fillText(str, 0, j * fontSize, W) 95 | } 96 | isPlay = ctx = W = H = colLen = rowLen = fontSize = gray = k = data = str= i = j = fm = text =len = null; 97 | } 98 | raf(loop) 99 | } 100 | }, 101 | openCamera: function(cameraW, cameraH, audioBool) { 102 | var vdo = this.vdo; 103 | var constraints = { 104 | audio: audioBool, 105 | video: { 106 | width: cameraW, 107 | height: cameraH 108 | } 109 | } 110 | navigator.mediaDevices 111 | .getUserMedia(constraints) 112 | .then(function(mediaStream) { 113 | vdo.srcObject = mediaStream; 114 | vdo.onloadedmetadata = function(e) { 115 | vdo.play(); 116 | } 117 | }) 118 | .catch(function(err) { 119 | alert('你的浏览器真需要去升级了,不然好多好玩的特性你根本玩不了。。。') 120 | }); 121 | return this; 122 | }, 123 | play: function() { 124 | this.isPlay = true; 125 | }, 126 | pause: function() { 127 | this.isPlay = false; 128 | }, 129 | playAndPause: function() { 130 | return this.isPlay = !this.isPlay; 131 | } 132 | } 133 | return Main 134 | }); 135 | --------------------------------------------------------------------------------