如果嫌字多,直接跳到猪头那里阅读。
一般写需要输出图像的程序我们并不会选择用控制台,因为控制台无法输出图片文件。但是在大学生涯写期末大作业或者实训写一个项目时,我们往往还没有接触过除了控制台以外的其它窗口的便程实现,但我们有时需要得到有图像的程序,甚至让图像能动起来。这个时候我们会想到自然就是通过利用输出符号来组成近似于某个东西的形状。但是具体怎么实现呢?
据我所知,大部分会使用在代码中直接输出符号的方式来组成图像,这种方法固然最容易被人接受,也最简单使用,但是存在的缺点更加明显,比如无法输出较为复杂的图像,更别说是动态的符号图像,同时,这样也会造成代码中大量输出符号的语句,让我们写的代码非常的不优雅。这个时候另辟新径就很有必要了。
在大一期末之后的实训中老师要求写一个宠物精灵的项目,其中就提到要求一定要用到符号图像来显示出宠物,并且要有动效。说实话这个要求让我足足折腾了半天,我百度想寻求解决办法,但是发现网上对于这方面的解答实在太少了,我最后只好自己摸索,差不多又是折腾了半天,总算是摸索出来了,现在将这个方法发到CSDN,希望能给后来者一点帮助!
?正文开始:
第一步:找到一个可以将视频转换为字符图像的软件。别问为什么不是自己写一个程序来转换,因为如果能做到这一点估计也不屑于来看我的博客了。如果找不到,我这里提供一个我找到的,不一定 很好用:链接:https://pan.baidu.com/s/1rN7gyFiVEAnXHMz4dJay-w 提取码:ercl 。用这个软件可以将视频转换位字符图像,那种一帧一帧的。转换之后得到的东西是一个gif文件(这个对我们没有用)和一个html文件,我们用浏览器打开这个html文件,会看到一个完全用字符组成的动态图像:然后右键查看源码:往下翻就是按时间顺序出现的一帧一帧的字符图像。
第二步:
这么大的图像直接从控制台输出,可想而知会发生什么,所以我们需要简化这些字符图像。而处理这些图像,我们就可以自己写程序来处理了。
我们将需要的部分复制下来:接下来我们需要做两个处理的操作,一是将上图的鱼周围没有用的字符给换成空格,必须换成空格,也不能什么也不换,至于为什么后面会有解释;二是进行读一行丢一行、读一列丢一列的操作,这是为了减小图像的尺寸,在控制台输出时就不会看起来很大,这一步操作具体看你需要实现什么来决定你需要放大还是缩小。
ok,第二步的第一小步:将鱼周围无效的字符读成空格。仔细看你会发现鱼周围的字符其实就只有那么几个相同的,所以采用循环结构加上枚举来把无效字符置换成空格就行。但是在处理之前我还需要提醒一点,就是我们之前从源代码中复制下来的第一帧的字符图像在每一行之间还有一行空的,我们处理图像的时候需要将空行跳过,也就是不读。这一步时实现可以参考以下代码,但是我的代码可能并不适合很大情况:
#include<iostream>
#include<fstream>
#include<Windows.h>
#include<string>
using namespace std;
string a[1000];
int main() {
string op = "date.dat";
ofstream filem(op, ios_base::out);
system("mode con cols=320 lines=1000");
for (int i = 0; i < 28; i++) {
//1.112,56 2.118,59 3.116,59 4.116,59 5.110 55 6.58 7.59 8.118 59 9.112 56
//10.118 59 11.118 59这里代表15帧字符图像算上空行有多少行,不算空行有多少行(大概的计算)
//12.118 59 13.114 56 14.120 60 15.120 60
getline(cin,a[i],'\n');//读取一行一定要用这个函数,直接cin会出现问题,因为字符图像中有很多空格会中断cin的读取
for (int j = 0; j < a[i].size(); j++) {
if (a[i][j] == 'M' || a[i][j] == 'A' || a[i][j] == 'B' || a[i][j] == 'H' || a[i][j] == 'X' || a[i][j] == '&')a[i][j] = ' ';//这几个字符位无效的字符,将其替换为空格
}
if (i % 2 == 0) {
filem << a[i] << endl;//这里将空格丢掉
}
}
Sleep(1000);
system("cls");
for (int i = 0; i < 60; i++) {
cout<<a[i]<<endl;
}
return 0;
}
这里的for循环里i 需要看你实际复制下来的符号图像有多少行。
第二小步:隔一行读一行,相当于缩小一倍,我进行了两次隔一行读一行的操作,相当于缩小为了四分之一。发现自己写的代码有点乱七八糟的,也不知道找到的代码有没有问题,所以这里就不贴代码了:
以上是处理一帧的过程,我们照这种方法继续处理接下来的几帧十几帧。就得到了十几个处理后文件,放着每一帧的字符图像。我那个时候处理了15帧,就有了15个文件分别叫作1.dat至15.dat
然后下面这个地方的代码是显示运行效果,运行这个程序,就会有一只鱼在屏幕中游动:
#include<iostream>
#include<fstream>
#include<Windows.h>
#include<string>
using namespace std;
string a[1000], bb[1000];
int main() {
string op="date.dat";
string op1 = "1.dat", op2 = "11.dat";
int b[16] = {
0,28 ,28 ,28,28,28 ,28,28,28,28,28,28,28,28,28,28 };//215
system("mode con cols=320 lines=1000");
for (int i = 1; i <= 15; i++) {
if (i <= 9) {
op1[0] = '0' + i;
op = op1;
}
else {
op2[0] = '1';
op2[1] = '0' + i - 10;
op = op2;
}
ifstream filem(op, ios_base::in);
//cout << endl << endl << endl << endl;
for (int j = 0; j < b[i]; j++) {
getline(filem, a[j], '\n');
cout << a[j] << endl;
}
Sleep(100);
//system("cls");
filem.close();
for (int i = 0; i < b[i]; i++) {
ofstream filem(op, ios_base::out);
if (i % 2 == 0) {
filem << bb[i] << endl;
}
}
if (i == 15)i = 0;
}
return 0;
}
上面的代码中我注释掉了system(“cls”);这样整个程序实际上是没有进行任何的清屏操作的,那有人可能会怀疑,15帧图像输出到屏幕上时不会出现前面的图像还在然后屏幕上一堆乱七八糟的东西呢,答案时不会的,这就是我之前留下的一个悬念,为什么把无效字符读成空格,因为空格可以将前一帧的图像盖掉,所以完全不需要清屏操作。
到了这里明显还不是最优的,我们肯定不能用15个文件来运行一个程序。这15个文件其实完全可以直接放一个文件里。通过下面这个代码,依次复制1.dat至15.dat文件中的内容但程序中进行处理。得到date。dat这一个文件:
#include<iostream>
#include<fstream>
#include<Windows.h>
#include<string>
using namespace std;
string a[1000],bb[1000];
int main() {
string op = "date.dat";
ofstream filem(op, ios_base::out);
system("mode con cols=320 lines=1000");
for (int i = 0; i < 14 * 15; i++) {
//14代表每个文件14行,总共15个文件也就是15帧
getline(cin, a[i], '\n');
filem << a[i] << endl;
}
filem.close();
return 0;
}
最后得到了一个文件,包含所有的15帧字符图像的文件。
然后这样调用:
filem.open(op, ios_base::in);
for (int i = 0; i < 15 * 14; i++) {
getline(filem, a[i], '\n');
}
for (int i = 1; i <= 15; i++) {
for (int j = 14*(i-1); j < i*14; j++) {
cout << a[j] << endl;
}
if (i == 15)i = 0;
}
大功告成!
最后将鱼的字符图像的素材分享给大家:
8 G
G8S 88S8SG339S5SSSS1S3
G5s GG3SS35h111riiii;;ri;sssi
G951 88833S5h1s;;;:i;;;;;;-i;i;;;;i:r
G33hr; GG83hiis;r;i;;::-;;;::;;-:;i::;i;;s
GG835r;i;iiir;i;s:;i-:;:,;::::--,-:::,-,:::i;;
G 9hri:i;;:;::;:::,:-,:::-;:::-.,,,,---:::::irr5
G33hrrrsi;i;;,,:,:;:-;:-:..,::-:::,.;,.,,-:,:;rr18
G93hi;:rrrrr----,,-.,,;;-:;;-:.--;.-.-,-.,-:-sr;irs
G83hr1 G33Ss1i;i-:-.,.--,,,---, ., , ih i.-:;iS
95r 9 GG33hh;;:i;i:-,.-..,-- .,.., . ..-. . .--3
8S3 G955shri;-i1r:::-,-..- . . , , - -,-r
399 9s::---:. . . 8
Sri--:,:-.. . . 5
GG
SG 8G89S9339GS38