├── .gitignore
├── LICENSE
├── README.md
├── converting.mp4
├── demo.gif
├── icon.png
├── index.css
├── index.html
├── index.js
├── nu_chi_1080p.mp4
├── nu_chi_1080p_poster.jpg
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Xmader
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🐸ASCII字符画视频流
2 |
3 | > 自动实时转换视频到ASCII字符画视频
4 |
5 | 
6 |
7 | 只是一个小demo
8 |
9 | 灵感来自 https://github.com/HFO4/plus1s.live
10 |
11 | [演示地址:https://xmader.github.io/ascii_live/](https://xmader.github.io/ascii_live/)
12 |
13 | * 点一下字符画就能像视频一样播放/暂停
14 |
15 | * 字符画可以像正常的文本一样复制/粘贴
16 |
17 | * 滋磁调整ASCII字符画视频的字号 (字号越小分辨率越高,占用的CPU百分比也就越高)
18 |
19 | * 滋磁播放本地视频 (转换完全在本地进行,视频不会上传到任何服务器,所以不必担心隐私问题)
20 |
21 |
22 | * 滋磁在ASCII字符画视频的左侧/上方同时显示转换前的原始视频
23 |
24 | * 全屏观看效果更佳
25 |
26 | * **v1.3.0新增** 打开控制台也能看到ASCII字符画视频 (目前只在字号为16px时可用) (仅在Firefox中测试通过)
27 |
28 | ## 这是如何实现的?
29 |
30 | 使用了canvas作为过渡,具体实现可以查看[源码](https://github.com/Xmader/ascii_live/blob/master/index.js)。
31 |
32 | ```
33 | 原始视频 => canvas => ASCII字符画视频
34 | ```
35 |
36 | 转换视频不依赖任何服务器,完全在你的浏览器中进行,离线也可以使用,具体转换效率取决于你的CPU性能。
37 |
38 | ## License
39 |
40 | MIT
41 |
--------------------------------------------------------------------------------
/converting.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xmader/ascii_live/438bb7766e48809d889555f7b8266b5598d1f3cd/converting.mp4
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xmader/ascii_live/438bb7766e48809d889555f7b8266b5598d1f3cd/demo.gif
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xmader/ascii_live/438bb7766e48809d889555f7b8266b5598d1f3cd/icon.png
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.loli.net/css?family=Roboto+Mono:300");
2 | video {
3 | width: 99.5%;
4 | }
5 |
6 | @media screen and (min-width: 767px) {
7 | body {
8 | margin-left: 5px;
9 | margin-right: 10px;
10 | }
11 | video {
12 | width: 50%;
13 | float: left;
14 | margin-right: 5px;
15 | }
16 | #txt {
17 | position: absolute;
18 | }
19 | }
20 |
21 | #txt {
22 | font-family: "Roboto Mono", "宋体", "simsun", monospace;
23 | font-size: 10px;
24 | line-height: 10px;
25 | width: 0px;
26 | transform-origin: top left;
27 | left: -5px;
28 | right: 0px;
29 | top: 0px;
30 | }
31 |
32 | canvas {
33 | display: none;
34 | }
35 |
36 | .clear {
37 | clear: both;
38 | }
39 |
40 | .range_div {
41 | float: left;
42 | }
43 |
44 | .upload-div {
45 | margin-right: 10px;
46 | margin-bottom: 10px;
47 | }
48 |
49 | @media screen and (min-width: 767px) {
50 | .upload-div {
51 | float: right;
52 | }
53 | }
54 |
55 | #upload-button,
56 | #text-button {
57 | height: 27px;
58 | width: 101px;
59 | }
60 |
61 | .upload-div p {
62 | margin-bottom: 3px;
63 | }
64 |
65 | #upload-button {
66 | position: absolute;
67 | cursor: pointer;
68 | opacity: 0;
69 | }
70 |
71 | .hidden {
72 | position: absolute;
73 | visibility: hidden;
74 | width: 99%;
75 | top: 0;
76 | }
77 |
78 | @media screen and (max-width: 767px) {
79 | .hidden {
80 | width: 96%;
81 | }
82 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | ASCII字符画视频流 - 自动实时转换视频到ASCII字符画视频
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * ASCII字符画视频流 (https://www.xmader.com/ascii_live/)
3 | *
4 | * Copyright (c) 2018 Xmader
5 | * Released under the MIT license
6 | *
7 | * Source Code: https://github.com/Xmader/ascii_live
8 | *
9 | * 部分代码参考了 https://gist.github.com/justjavac/6696499
10 | *
11 | * 为了更好的兼容性,不使用任何ES6特性和新增语法
12 | *
13 | * 如果你在这里发现了bug,请多多包涵,欢迎使用 https://github.com/Xmader/ascii_live/issues 向我提出。
14 | *
15 | */
16 |
17 | var video = document.getElementById("video1");
18 | var cv = document.getElementById('cv');
19 | var ctx = cv.getContext('2d');
20 | var txtDiv = document.getElementById('txt');
21 | var uploadBtn = document.getElementById("upload-button");
22 |
23 | var font_size_range = document.getElementById("font_size_range")
24 | var font_size_span = document.getElementById("font_size")
25 | var footer = document.getElementById("footer")
26 |
27 | var isFirefox = navigator.userAgent.indexOf("Firefox") > -1
28 | var isWindows = navigator.userAgent.indexOf("Windows") > -1
29 |
30 | if (isWindows) { // 中易宋体只在Windows系统中可用
31 | var scale_x = isFirefox ? 0.0895 : 0.1
32 | }
33 | else {
34 | var scale_x = 0.0835
35 | }
36 |
37 | var video_show = false
38 |
39 | var font_size = 2 // ASCII字符画的字号,数值越小分辨率越高,占用的CPU百分比也就越高 (和占用的内存没有关系),必须是2的倍数,单位: px (像素)
40 |
41 | // 根据调整字号滑动条动态地改变ASCII字符画的字号
42 | function change_font_size() {
43 | var n = +font_size_range.value // 获取的原始值是一个字符串,用"+"号将它转换成一个数字
44 | font_size_span.innerText = n
45 |
46 | txtDiv.style["transform"] = "scale(" + (n * scale_x) + "," + (n / 10) + ")"
47 |
48 | font_size = n
49 |
50 | convert() // 实时重绘,不需要等待额外的20毫秒
51 |
52 | font_size_range.scrollIntoView() // 调整字号结束后页面自动回到滑动条所在的位置
53 | }
54 |
55 | // 根据灰度生成相应字符
56 | function toText(g) {
57 | if (g <= 30) {
58 | return '#';
59 | } else if (g > 30 && g <= 60) {
60 | return '&';
61 | } else if (g > 60 && g <= 120) {
62 | return '$';
63 | } else if (g > 120 && g <= 150) {
64 | return '*';
65 | } else if (g > 150 && g <= 180) {
66 | return 'o';
67 | } else if (g > 180 && g <= 210) {
68 | return '!';
69 | } else if (g > 210 && g <= 240) {
70 | return ';';
71 | } else {
72 | return ' ';
73 | }
74 | }
75 |
76 | // 根据rgb值计算灰度
77 | function getGray(r, g, b) {
78 | return 0.299 * r + 0.578 * g + 0.114 * b;
79 | }
80 |
81 | // 转换
82 | function convert() {
83 | var video_width = video.clientWidth
84 | var video_height = video.clientHeight
85 | var txtDiv_height = txtDiv.clientHeight
86 |
87 | cv.width = video_width
88 | cv.height = video_height
89 |
90 | txtDiv.style.left = video_show ?
91 | video_width + 10 + 'px'
92 | : "5px"
93 |
94 | footer.style["margin-top"] = video_show ?
95 | "0px"
96 | : (txtDiv_height * (font_size / 10)) + 'px'
97 |
98 | if (document.body.clientWidth < 767) { // 小屏幕设备
99 | var footer_margin_top = -txtDiv_height * (1 - font_size / 10) // (1 - font_size / 10) 可能会是负数
100 |
101 | if (footer_margin_top > 0) {
102 | footer_margin_top = (font_size - 10) * 12
103 | }
104 |
105 | footer.style["margin-top"] = footer_margin_top + "px"
106 | }
107 |
108 | ctx.drawImage(video, 0, 0, video_width, video_height)
109 |
110 | var imgData = ctx.getImageData(0, 0, video_width, video_height);
111 | var imgDataArr = imgData.data;
112 | var imgDataWidth = imgData.width;
113 | var imgDataHeight = imgData.height;
114 | var html = '';
115 | for (h = 0; h < imgDataHeight; h += font_size) {
116 | var p = '';
117 | for (w = 0; w < imgDataWidth; w += (font_size / 2)) {
118 | var index = (w + imgDataWidth * h) * 4;
119 | var r = imgDataArr[index + 0];
120 | var g = imgDataArr[index + 1];
121 | var b = imgDataArr[index + 2];
122 | var gray = getGray(r, g, b);
123 | p += toText(gray);
124 | }
125 | p += '\n';
126 | html += p;
127 | }
128 | txtDiv.innerHTML = html;
129 |
130 | if (font_size >= 16) {
131 | console.clear()
132 | console.log(html)
133 | }
134 |
135 | }
136 |
137 | // 获取上传的视频文件
138 | function getFile() {
139 | var reader = new FileReader();
140 | reader.readAsDataURL(uploadBtn.files[0]);
141 |
142 | video.src = "converting.mp4"
143 | video.poster = null
144 |
145 | reader.onload = function () {
146 | video.src = reader.result; // 是一个base64 Data URL字符串
147 | video.play()
148 | }
149 | }
150 |
151 | // 显示/隐藏原始视频
152 | function toggle_video() {
153 | video.classList.toggle('hidden')
154 | video_show = !video_show
155 | }
156 |
157 | window.onload = function () {
158 | change_font_size()
159 | window.setInterval(convert, 20);
160 | }
161 |
162 | uploadBtn.onchange = getFile
163 |
164 | txtDiv.onclick = function () {
165 | video.paused ? video.play() : video.pause()
166 | }
167 |
--------------------------------------------------------------------------------
/nu_chi_1080p.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xmader/ascii_live/438bb7766e48809d889555f7b8266b5598d1f3cd/nu_chi_1080p.mp4
--------------------------------------------------------------------------------
/nu_chi_1080p_poster.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xmader/ascii_live/438bb7766e48809d889555f7b8266b5598d1f3cd/nu_chi_1080p_poster.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ascii_live",
3 | "version": "1.3.2",
4 | "description": "ASCII字符画视频流",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/Xmader/ascii_live"
8 | },
9 | "author": "xmader",
10 | "scripts": {
11 | "web-service": "python -m SimpleHTTPServer 3010"
12 | },
13 | "license": "MIT"
14 | }
15 |
--------------------------------------------------------------------------------