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